]> git.ipfire.org Git - thirdparty/util-linux.git/blame - fdisk/fdisk.c
fdisk: add basic routines for LBA alignment
[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.
6dbe3af9
KZ
9 */
10
6dbe3af9
KZ
11#include <unistd.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <fcntl.h>
16#include <ctype.h>
17#include <setjmp.h>
18#include <errno.h>
2b6fc908 19#include <getopt.h>
2b6fc908 20#include <sys/stat.h>
f26873dc 21#include <sys/time.h>
bb6aacfe 22#include <time.h>
ee5355e0 23#include <limits.h>
6dbe3af9 24
22853e4a 25#include "nls.h"
810f986b 26#include "blkdev.h"
7eda085c 27#include "common.h"
726f69e2 28#include "fdisk.h"
929f243f 29#include "wholedisk.h"
5c36a0eb 30
2b6fc908 31#include "fdisksunlabel.h"
5c36a0eb
KZ
32#include "fdisksgilabel.h"
33#include "fdiskaixlabel.h"
e7fa917a 34#include "fdiskmaclabel.h"
5c36a0eb 35
48d7b13a
KZ
36#ifdef HAVE_LINUX_COMPILER_H
37#include <linux/compiler.h>
38#endif
39#ifdef HAVE_LINUX_BLKPG_H
7eda085c
KZ
40#include <linux/blkpg.h>
41#endif
05dc9645
KZ
42#ifdef HAVE_LIBBLKID_INTERNAL
43#include <blkid.h>
44#endif
6dbe3af9 45
5dbff4c0
KZ
46#include "gpt.h"
47
66ee8158
KZ
48static void delete_partition(int i);
49
6dbe3af9
KZ
50#define hex_val(c) ({ \
51 char _c = (c); \
52 isdigit(_c) ? _c - '0' : \
53 tolower(_c) + 10 - 'a'; \
54 })
55
56
c07ebfa1 57#define LINE_LENGTH 800
22853e4a 58#define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
6dbe3af9
KZ
59 (n) * sizeof(struct partition)))
60#define sector(s) ((s) & 0x3f)
61#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
62
5c36a0eb 63#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
6dbe3af9
KZ
64 ((h) + heads * cylinder(s,c)))
65#define set_hsc(h,s,c,sector) { \
66 s = sector % sectors + 1; \
67 sector /= sectors; \
68 h = sector % heads; \
69 sector /= heads; \
70 c = sector & 0xff; \
71 s |= (sector >> 2) & 0xc0; \
72 }
73
2b6fc908 74/* A valid partition table sector ends in 0x55 0xaa */
22853e4a 75static unsigned int
be97c5f3 76part_table_flag(unsigned char *b) {
df1dddf9 77 return ((unsigned int) b[510]) + (((unsigned int) b[511]) << 8);
2b6fc908
KZ
78}
79
80int
81valid_part_table_flag(unsigned char *b) {
82 return (b[510] == 0x55 && b[511] == 0xaa);
83}
84
22853e4a 85static void
be97c5f3 86write_part_table_flag(unsigned char *b) {
2b6fc908
KZ
87 b[510] = 0x55;
88 b[511] = 0xaa;
89}
90
91/* start_sect and nr_sects are stored little endian on all machines */
92/* moreover, they are not aligned correctly */
22853e4a 93static void
2b6fc908
KZ
94store4_little_endian(unsigned char *cp, unsigned int val) {
95 cp[0] = (val & 0xff);
96 cp[1] = ((val >> 8) & 0xff);
97 cp[2] = ((val >> 16) & 0xff);
98 cp[3] = ((val >> 24) & 0xff);
99}
100
22853e4a 101static unsigned int
bb6aacfe 102read4_little_endian(const unsigned char *cp) {
df1dddf9
KZ
103 return (unsigned int)(cp[0]) + ((unsigned int)(cp[1]) << 8)
104 + ((unsigned int)(cp[2]) << 16)
105 + ((unsigned int)(cp[3]) << 24);
2b6fc908
KZ
106}
107
22853e4a 108static void
2b6fc908
KZ
109set_start_sect(struct partition *p, unsigned int start_sect) {
110 store4_little_endian(p->start4, start_sect);
111}
112
be97c5f3 113unsigned long long
2b6fc908
KZ
114get_start_sect(struct partition *p) {
115 return read4_little_endian(p->start4);
116}
117
22853e4a 118static void
be97c5f3 119set_nr_sects(struct partition *p, unsigned long long nr_sects) {
2b6fc908
KZ
120 store4_little_endian(p->size4, nr_sects);
121}
122
be97c5f3 123unsigned long long
2b6fc908
KZ
124get_nr_sects(struct partition *p) {
125 return read4_little_endian(p->size4);
126}
127
bb6aacfe
PA
128static ssize_t
129xread(int fd, void *buf, size_t count) {
130 char *p = buf;
131 ssize_t out = 0;
132 ssize_t rv;
133
134 while (count) {
135 rv = read(fd, p, count);
136 if (rv == -1) {
137 if (errno == EINTR || errno == EAGAIN)
138 continue;
139 return out ? out : -1; /* Error */
140 } else if (rv == 0) {
141 return out; /* EOF */
142 }
143
144 p += rv;
145 out += rv;
146 count -= rv;
147 }
148
149 return out;
150}
151
152static unsigned int
153get_random_id(void) {
154 int fd;
155 unsigned int v;
156 ssize_t rv = -1;
f26873dc 157 struct timeval tv;
bb6aacfe
PA
158
159 fd = open("/dev/urandom", O_RDONLY);
160 if (fd >= 0) {
161 rv = xread(fd, &v, sizeof v);
162 close(fd);
163 }
164
165 if (rv == sizeof v)
166 return v;
167
168 /* Fallback: sucks, but better than nothing */
f26873dc
PA
169 gettimeofday(&tv, NULL);
170 return (unsigned int)(tv.tv_sec + (tv.tv_usec << 12) + getpid());
bb6aacfe
PA
171}
172
726f69e2
KZ
173/* normally O_RDWR, -l option gives O_RDONLY */
174static int type_open = O_RDWR;
6dbe3af9 175
22853e4a
KZ
176/*
177 * Raw disk label. For DOS-type partition tables the MBR,
178 * with descriptions of the primary partitions.
179 */
b2f15782 180unsigned char *MBRbuffer;
22853e4a
KZ
181
182/*
183 * per partition table entry data
184 *
185 * The four primary partitions have the same sectorbuffer (MBRbuffer)
186 * and have NULL ext_pointer.
187 * Each logical partition table entry has two pointers, one for the
188 * partition and one link to the next one.
189 */
190struct pte {
191 struct partition *part_table; /* points into sectorbuffer */
192 struct partition *ext_pointer; /* points into sectorbuffer */
df1dddf9 193 char changed; /* boolean */
be97c5f3
KZ
194 unsigned long long offset; /* disk sector number */
195 unsigned char *sectorbuffer; /* disk sector contents */
22853e4a
KZ
196} ptes[MAXIMUM_PARTS];
197
7eda085c 198char *disk_device, /* must be specified */
6dbe3af9 199 *line_ptr, /* interactive input */
22853e4a 200 line_buffer[LINE_LENGTH];
6dbe3af9
KZ
201
202int fd, /* the disk */
203 ext_index, /* the prime extended partition */
204 listing = 0, /* no aborts for fdisk -l */
2b6fc908 205 nowarn = 0, /* no warnings for fdisk -l/-s */
6dbe3af9 206 dos_compatible_flag = ~0,
e8f26419 207 dos_changed = 0,
6dbe3af9
KZ
208 partitions = 4; /* maximum partition + 1 */
209
df1dddf9
KZ
210unsigned int user_cylinders, user_heads, user_sectors;
211unsigned int pt_heads, pt_sectors;
212unsigned int kern_heads, kern_sectors;
22853e4a 213
be97c5f3
KZ
214unsigned long long sector_offset = 1, extended_offset = 0, sectors;
215
df1dddf9 216unsigned int heads,
6dbe3af9 217 cylinders,
5c36a0eb 218 sector_size = DEFAULT_SECTOR_SIZE,
10e3d031 219 sector_factor = 1,
66ee8158 220 user_set_sector_size = 0,
7eda085c 221 units_per_sector = 1,
be97c5f3 222 display_in_cyl_units = 1;
6dbe3af9 223
85a994c4 224unsigned long long total_number_of_sectors; /* (!) 512-byte sectors */
05dc9645 225unsigned long minimum_io_size, alignment_offset;
24f4bbff 226
e7fa917a
KZ
227#define dos_label (!sun_label && !sgi_label && !aix_label && !mac_label && !osf_label)
228int sun_label = 0; /* looking at sun disklabel */
5c36a0eb
KZ
229int sgi_label = 0; /* looking at sgi disklabel */
230int aix_label = 0; /* looking at aix disklabel */
63cccae4 231int osf_label = 0; /* looking at OSF/1 disklabel */
e7fa917a 232int mac_label = 0; /* looking at mac disklabel */
63cccae4 233int possibly_osf_label = 0;
a2c5f3ca 234
6dbe3af9
KZ
235jmp_buf listingbuf;
236
22853e4a 237void fatal(enum failure why) {
6dbe3af9
KZ
238 char error[LINE_LENGTH],
239 *message = error;
240
241 if (listing) {
242 close(fd);
243 longjmp(listingbuf, 1);
244 }
245
246 switch (why) {
7eda085c
KZ
247 case usage: message = _(
248"Usage: fdisk [-b SSZ] [-u] DISK Change partition table\n"
249" fdisk -l [-b SSZ] [-u] DISK List partition table(s)\n"
250" fdisk -s PARTITION Give partition size(s) in blocks\n"
251" fdisk -v Give fdisk version\n"
5c36a0eb
KZ
252"Here DISK is something like /dev/hdb or /dev/sda\n"
253"and PARTITION is something like /dev/hda7\n"
254"-u: give Start and End in sector (instead of cylinder) units\n"
e8f26419 255"-b 2048: (for certain MO disks) use 2048-byte sectors\n");
7eda085c
KZ
256 break;
257 case usage2:
258 /* msg in cases where fdisk used to probe */
259 message = _(
260"Usage: fdisk [-l] [-b SSZ] [-u] device\n"
261"E.g.: fdisk /dev/hda (for the first IDE disk)\n"
262" or: fdisk /dev/sdc (for the third SCSI disk)\n"
263" or: fdisk /dev/eda (for the first PS/2 ESDI drive)\n"
264" or: fdisk /dev/rd/c0d0 or: fdisk /dev/ida/c0d0 (for RAID devices)\n"
265" ...\n");
5c36a0eb 266 break;
6dbe3af9 267 case unable_to_open:
c07ebfa1
KZ
268 snprintf(error, sizeof(error),
269 _("Unable to open %s\n"), disk_device);
6dbe3af9
KZ
270 break;
271 case unable_to_read:
c07ebfa1
KZ
272 snprintf(error, sizeof(error),
273 _("Unable to read %s\n"), disk_device);
6dbe3af9
KZ
274 break;
275 case unable_to_seek:
c07ebfa1
KZ
276 snprintf(error, sizeof(error),
277 _("Unable to seek on %s\n"),disk_device);
6dbe3af9
KZ
278 break;
279 case unable_to_write:
c07ebfa1
KZ
280 snprintf(error, sizeof(error),
281 _("Unable to write %s\n"), disk_device);
7eda085c
KZ
282 break;
283 case ioctl_error:
c07ebfa1
KZ
284 snprintf(error, sizeof(error),
285 _("BLKGETSIZE ioctl failed on %s\n"),
7eda085c 286 disk_device);
6dbe3af9
KZ
287 break;
288 case out_of_memory:
7eda085c 289 message = _("Unable to allocate any more memory\n");
6dbe3af9 290 break;
c07ebfa1
KZ
291 default:
292 message = _("Fatal error\n");
6dbe3af9
KZ
293 }
294
295 fputc('\n', stderr);
296 fputs(message, stderr);
297 exit(1);
298}
299
22853e4a 300static void
be97c5f3 301seek_sector(int fd, unsigned long long secno) {
cf6d7fae
KZ
302 off_t offset = (off_t) secno * sector_size;
303 if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
22853e4a
KZ
304 fatal(unable_to_seek);
305}
306
307static void
be97c5f3 308read_sector(int fd, unsigned long long secno, unsigned char *buf) {
22853e4a
KZ
309 seek_sector(fd, secno);
310 if (read(fd, buf, sector_size) != sector_size)
311 fatal(unable_to_read);
312}
313
314static void
be97c5f3 315write_sector(int fd, unsigned long long secno, unsigned char *buf) {
22853e4a
KZ
316 seek_sector(fd, secno);
317 if (write(fd, buf, sector_size) != sector_size)
318 fatal(unable_to_write);
319}
320
321/* Allocate a buffer and read a partition table sector */
322static void
be97c5f3 323read_pte(int fd, int pno, unsigned long long offset) {
22853e4a
KZ
324 struct pte *pe = &ptes[pno];
325
326 pe->offset = offset;
be97c5f3 327 pe->sectorbuffer = malloc(sector_size);
22853e4a
KZ
328 if (!pe->sectorbuffer)
329 fatal(out_of_memory);
330 read_sector(fd, offset, pe->sectorbuffer);
331 pe->changed = 0;
332 pe->part_table = pe->ext_pointer = NULL;
333}
c07ebfa1 334
be97c5f3 335static unsigned long long
22853e4a
KZ
336get_partition_start(struct pte *pe) {
337 return pe->offset + get_start_sect(pe->part_table);
338}
339
340struct partition *
341get_part_table(int i) {
342 return ptes[i].part_table;
343}
344
345void
346set_all_unchanged(void) {
347 int i;
348
349 for (i = 0; i < MAXIMUM_PARTS; i++)
350 ptes[i].changed = 0;
351}
352
353void
354set_changed(int i) {
355 ptes[i].changed = 1;
356}
357
d162fcb5
KZ
358static int
359is_garbage_table(void) {
360 int i;
361
362 for (i = 0; i < 4; i++) {
363 struct pte *pe = &ptes[i];
364 struct partition *p = pe->part_table;
365
366 if (p->boot_ind != 0 && p->boot_ind != 0x80)
367 return 1;
368 }
369 return 0;
370}
371
e8f26419
KZ
372/*
373 * Avoid warning about DOS partitions when no DOS partition was changed.
374 * Here a heuristic "is probably dos partition".
375 * We might also do the opposite and warn in all cases except
376 * for "is probably nondos partition".
377 */
378static int
379is_dos_partition(int t) {
380 return (t == 1 || t == 4 || t == 6 ||
381 t == 0x0b || t == 0x0c || t == 0x0e ||
382 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
383 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
384 t == 0xc1 || t == 0xc4 || t == 0xc6);
385}
386
22853e4a
KZ
387static void
388menu(void) {
7eda085c
KZ
389 if (sun_label) {
390 puts(_("Command action"));
391 puts(_(" a toggle a read only flag")); /* sun */
392 puts(_(" b edit bsd disklabel"));
393 puts(_(" c toggle the mountable flag")); /* sun */
394 puts(_(" d delete a partition"));
395 puts(_(" l list known partition types"));
396 puts(_(" m print this menu"));
397 puts(_(" n add a new partition"));
398 puts(_(" o create a new empty DOS partition table"));
399 puts(_(" p print the partition table"));
400 puts(_(" q quit without saving changes"));
401 puts(_(" s create a new empty Sun disklabel")); /* sun */
402 puts(_(" t change a partition's system id"));
403 puts(_(" u change display/entry units"));
404 puts(_(" v verify the partition table"));
405 puts(_(" w write table to disk and exit"));
406 puts(_(" x extra functionality (experts only)"));
407 }
63cccae4 408 else if (sgi_label) {
7eda085c
KZ
409 puts(_("Command action"));
410 puts(_(" a select bootable partition")); /* sgi flavour */
411 puts(_(" b edit bootfile entry")); /* sgi */
412 puts(_(" c select sgi swap partition")); /* sgi flavour */
413 puts(_(" d delete a partition"));
414 puts(_(" l list known partition types"));
415 puts(_(" m print this menu"));
416 puts(_(" n add a new partition"));
417 puts(_(" o create a new empty DOS partition table"));
418 puts(_(" p print the partition table"));
419 puts(_(" q quit without saving changes"));
420 puts(_(" s create a new empty Sun disklabel")); /* sun */
421 puts(_(" t change a partition's system id"));
422 puts(_(" u change display/entry units"));
423 puts(_(" v verify the partition table"));
424 puts(_(" w write table to disk and exit"));
425 }
e7fa917a 426 else if (aix_label || mac_label) {
7eda085c
KZ
427 puts(_("Command action"));
428 puts(_(" m print this menu"));
429 puts(_(" o create a new empty DOS partition table"));
430 puts(_(" q quit without saving changes"));
431 puts(_(" s create a new empty Sun disklabel")); /* sun */
432 }
433 else {
434 puts(_("Command action"));
435 puts(_(" a toggle a bootable flag"));
436 puts(_(" b edit bsd disklabel"));
437 puts(_(" c toggle the dos compatibility flag"));
438 puts(_(" d delete a partition"));
439 puts(_(" l list known partition types"));
440 puts(_(" m print this menu"));
441 puts(_(" n add a new partition"));
442 puts(_(" o create a new empty DOS partition table"));
443 puts(_(" p print the partition table"));
444 puts(_(" q quit without saving changes"));
445 puts(_(" s create a new empty Sun disklabel")); /* sun */
446 puts(_(" t change a partition's system id"));
447 puts(_(" u change display/entry units"));
448 puts(_(" v verify the partition table"));
449 puts(_(" w write table to disk and exit"));
450 puts(_(" x extra functionality (experts only)"));
451 }
6dbe3af9
KZ
452}
453
22853e4a
KZ
454static void
455xmenu(void) {
7eda085c
KZ
456 if (sun_label) {
457 puts(_("Command action"));
22853e4a 458 puts(_(" a change number of alternate cylinders")); /*sun*/
7eda085c
KZ
459 puts(_(" c change number of cylinders"));
460 puts(_(" d print the raw data in the partition table"));
461 puts(_(" e change number of extra sectors per cylinder"));/*sun*/
462 puts(_(" h change number of heads"));
463 puts(_(" i change interleave factor")); /*sun*/
464 puts(_(" o change rotation speed (rpm)")); /*sun*/
465 puts(_(" m print this menu"));
466 puts(_(" p print the partition table"));
467 puts(_(" q quit without saving changes"));
468 puts(_(" r return to main menu"));
469 puts(_(" s change number of sectors/track"));
470 puts(_(" v verify the partition table"));
471 puts(_(" w write table to disk and exit"));
472 puts(_(" y change number of physical cylinders")); /*sun*/
473 }
63cccae4 474 else if (sgi_label) {
22853e4a
KZ
475 puts(_("Command action"));
476 puts(_(" b move beginning of data in a partition")); /* !sun */
477 puts(_(" c change number of cylinders"));
478 puts(_(" d print the raw data in the partition table"));
479 puts(_(" e list extended partitions")); /* !sun */
e8f26419 480 puts(_(" g create an IRIX (SGI) partition table"));/* sgi */
22853e4a
KZ
481 puts(_(" h change number of heads"));
482 puts(_(" m print this menu"));
483 puts(_(" p print the partition table"));
484 puts(_(" q quit without saving changes"));
485 puts(_(" r return to main menu"));
486 puts(_(" s change number of sectors/track"));
487 puts(_(" v verify the partition table"));
488 puts(_(" w write table to disk and exit"));
489 }
e7fa917a 490 else if (aix_label || mac_label) {
22853e4a
KZ
491 puts(_("Command action"));
492 puts(_(" b move beginning of data in a partition")); /* !sun */
493 puts(_(" c change number of cylinders"));
494 puts(_(" d print the raw data in the partition table"));
495 puts(_(" e list extended partitions")); /* !sun */
e8f26419 496 puts(_(" g create an IRIX (SGI) partition table"));/* sgi */
22853e4a
KZ
497 puts(_(" h change number of heads"));
498 puts(_(" m print this menu"));
499 puts(_(" p print the partition table"));
500 puts(_(" q quit without saving changes"));
501 puts(_(" r return to main menu"));
502 puts(_(" s change number of sectors/track"));
503 puts(_(" v verify the partition table"));
504 puts(_(" w write table to disk and exit"));
505 }
7eda085c
KZ
506 else {
507 puts(_("Command action"));
508 puts(_(" b move beginning of data in a partition")); /* !sun */
509 puts(_(" c change number of cylinders"));
510 puts(_(" d print the raw data in the partition table"));
511 puts(_(" e list extended partitions")); /* !sun */
22853e4a 512 puts(_(" f fix partition order")); /* !sun, !aix, !sgi */
e8f26419 513 puts(_(" g create an IRIX (SGI) partition table"));/* sgi */
7eda085c 514 puts(_(" h change number of heads"));
bb6aacfe 515 puts(_(" i change the disk identifier")); /* dos only */
7eda085c
KZ
516 puts(_(" m print this menu"));
517 puts(_(" p print the partition table"));
518 puts(_(" q quit without saving changes"));
519 puts(_(" r return to main menu"));
520 puts(_(" s change number of sectors/track"));
521 puts(_(" v verify the partition table"));
522 puts(_(" w write table to disk and exit"));
22853e4a 523 }
6dbe3af9
KZ
524}
525
22853e4a 526static int
5c36a0eb
KZ
527get_sysid(int i) {
528 return (
899736f1 529 sun_label ? sun_get_sysid(i) :
a2c5f3ca
KZ
530 sgi_label ? sgi_get_sysid(i) :
531 ptes[i].part_table->sys_ind);
5c36a0eb
KZ
532}
533
22853e4a 534static struct systypes *
5c36a0eb
KZ
535get_sys_types(void) {
536 return (
537 sun_label ? sun_sys_types :
a2c5f3ca
KZ
538 sgi_label ? sgi_sys_types :
539 i386_sys_types);
5c36a0eb
KZ
540}
541
6dbe3af9
KZ
542char *partition_type(unsigned char type)
543{
2b6fc908 544 int i;
5c36a0eb 545 struct systypes *types = get_sys_types();
2b6fc908
KZ
546
547 for (i=0; types[i].name; i++)
7eda085c
KZ
548 if (types[i].type == type)
549 return _(types[i].name);
2b6fc908 550
6dbe3af9
KZ
551 return NULL;
552}
553
2b6fc908 554void list_types(struct systypes *sys)
6dbe3af9 555{
df1dddf9 556 unsigned int last[4], done = 0, next = 0, size;
6dbe3af9
KZ
557 int i;
558
2b6fc908
KZ
559 for (i = 0; sys[i].name; i++);
560 size = i;
561
6dbe3af9
KZ
562 for (i = 3; i >= 0; i--)
563 last[3 - i] = done += (size + i - done) / (i + 1);
564 i = done = 0;
565
566 do {
567 printf("%c%2x %-15.15s", i ? ' ' : '\n',
7eda085c 568 sys[next].type, _(sys[next].name));
726f69e2 569 next = last[i++] + done;
6dbe3af9
KZ
570 if (i > 3 || next >= last[i]) {
571 i = 0;
572 next = ++done;
573 }
574 } while (done < last[0]);
575 putchar('\n');
576}
577
e8f26419
KZ
578static int
579is_cleared_partition(struct partition *p) {
580 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
581 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
582 get_start_sect(p) || get_nr_sects(p));
583}
584
22853e4a
KZ
585static void
586clear_partition(struct partition *p) {
587 if (!p)
588 return;
6dbe3af9
KZ
589 p->boot_ind = 0;
590 p->head = 0;
591 p->sector = 0;
592 p->cyl = 0;
593 p->sys_ind = 0;
594 p->end_head = 0;
595 p->end_sector = 0;
596 p->end_cyl = 0;
2b6fc908
KZ
597 set_start_sect(p,0);
598 set_nr_sects(p,0);
6dbe3af9
KZ
599}
600
22853e4a 601static void
be97c5f3
KZ
602set_partition(int i, int doext, unsigned long long start,
603 unsigned long long stop, int sysid) {
364cda48 604 struct partition *p;
be97c5f3 605 unsigned long long offset;
364cda48
KZ
606
607 if (doext) {
608 p = ptes[i].ext_pointer;
609 offset = extended_offset;
610 } else {
611 p = ptes[i].part_table;
612 offset = ptes[i].offset;
613 }
6dbe3af9 614 p->boot_ind = 0;
2b6fc908
KZ
615 p->sys_ind = sysid;
616 set_start_sect(p, start - offset);
617 set_nr_sects(p, stop - start + 1);
6dbe3af9
KZ
618 if (dos_compatible_flag && (start/(sectors*heads) > 1023))
619 start = heads*sectors*1024 - 1;
620 set_hsc(p->head, p->sector, p->cyl, start);
621 if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
622 stop = heads*sectors*1024 - 1;
623 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
22853e4a 624 ptes[i].changed = 1;
6dbe3af9
KZ
625}
626
22853e4a
KZ
627static int
628test_c(char **m, char *mesg) {
6dbe3af9
KZ
629 int val = 0;
630 if (!*m)
7eda085c 631 fprintf(stderr, _("You must set"));
6dbe3af9
KZ
632 else {
633 fprintf(stderr, " %s", *m);
634 val = 1;
635 }
636 *m = mesg;
637 return val;
638}
639
b39a4641
KZ
640#define alignment_required (minimum_io_size != sector_size)
641
642static int
643lba_is_aligned(unsigned long long lba)
644{
645 unsigned long long bytes, phy_sectors;
646
647 bytes = lba * sector_size;
648 phy_sectors = bytes / minimum_io_size;
649
650 return (alignment_offset + (phy_sectors * minimum_io_size) == bytes);
651}
652
653#define ALIGN_UP 1
654#define ALIGN_DOWN 2
655#define ALIGN_NEAREST 3
656
657static unsigned long long
658align_lba(unsigned long long lba, int direction)
659{
660 unsigned long long sects_in_phy, res;
661
662 if (lba_is_aligned(lba))
663 return lba;
664
665 sects_in_phy = minimum_io_size / sector_size;
666
667 if (lba < sects_in_phy)
668 /* align to the first physical sector */
669 res = sects_in_phy;
670
671 else if (direction == ALIGN_UP)
672 res = ((lba + sects_in_phy) / sects_in_phy) * sects_in_phy;
673
674 else if (direction == ALIGN_DOWN)
675 res = (lba / sects_in_phy) * sects_in_phy;
676
677 else /* ALIGN_NEAREST */
678 res = ((lba + sects_in_phy/2) / sects_in_phy) * sects_in_phy;
679
680 if (alignment_offset)
681 /*
682 * apply alignment_offset
683 *
684 * On disk with alignment compensation physical blocks start
685 * at LBA < 0 (usually LBA -1). It means we have to move LBA
686 * according the offset to be on the physical boundary.
687 */
688 res -= (minimum_io_size - alignment_offset) / sector_size;
689
690 /* fprintf(stderr, "LBA %llu -align-> %llu (%s)\n", lba, res,
691 * lba_is_aligned(res) ? "OK" : "FALSE");
692 */
693 return res;
694}
695
696static unsigned long long
697align_lba_in_range( unsigned long long lba,
698 unsigned long long start,
699 unsigned long long stop)
700{
701 start = align_lba(start, ALIGN_UP);
702 stop = align_lba(stop, ALIGN_DOWN);
703
704 lba = align_lba(lba, ALIGN_NEAREST);
705
706 if (lba < start)
707 return start;
708 else if (lba > stop)
709 return stop;
710 return lba;
711}
712
22853e4a
KZ
713static int
714warn_geometry(void) {
6dbe3af9
KZ
715 char *m = NULL;
716 int prev = 0;
a47f2e66
KZ
717
718 if (sgi_label) /* cannot set cylinders etc anyway */
719 return 0;
6dbe3af9 720 if (!heads)
7eda085c 721 prev = test_c(&m, _("heads"));
6dbe3af9 722 if (!sectors)
7eda085c 723 prev = test_c(&m, _("sectors"));
6dbe3af9 724 if (!cylinders)
7eda085c 725 prev = test_c(&m, _("cylinders"));
6dbe3af9
KZ
726 if (!m)
727 return 0;
728 fprintf(stderr,
7eda085c
KZ
729 _("%s%s.\nYou can do this from the extra functions menu.\n"),
730 prev ? _(" and ") : " ", m);
6dbe3af9
KZ
731 return 1;
732}
733
6dbe3af9
KZ
734void update_units(void)
735{
5c36a0eb
KZ
736 int cyl_units = heads * sectors;
737
7eda085c
KZ
738 if (display_in_cyl_units && cyl_units)
739 units_per_sector = cyl_units;
5c36a0eb 740 else
7eda085c 741 units_per_sector = 1; /* in sectors */
6dbe3af9
KZ
742}
743
22853e4a
KZ
744static void
745warn_cylinders(void) {
746 if (dos_label && cylinders > 1024 && !nowarn)
66ee8158
KZ
747 fprintf(stderr, _("\n"
748"The number of cylinders for this disk is set to %d.\n"
749"There is nothing wrong with that, but this is larger than 1024,\n"
750"and could in certain setups cause problems with:\n"
751"1) software that runs at boot time (e.g., old versions of LILO)\n"
752"2) booting and partitioning software from other OSs\n"
753" (e.g., DOS FDISK, OS/2 FDISK)\n"),
6dbe3af9 754 cylinders);
ee5355e0
KZ
755
756 if (total_number_of_sectors > UINT_MAX) {
757 int giga = (total_number_of_sectors << 9) / 1000000000;
32b40fec
KZ
758 int hectogiga = (giga + 50) / 100;
759
ee5355e0
KZ
760 fprintf(stderr, _("\n"
761"WARNING: The size of this disk is %d.%d TB (%llu bytes).\n"
32b40fec 762"DOS partition table format can not be used on drives for volumes\n"
85a994c4 763"larger than (%llu bytes) for %d-byte sectors. Use parted(1) and GUID \n"
ee5355e0 764"partition table format (GPT).\n\n"),
32b40fec 765 hectogiga / 10, hectogiga % 10,
85a994c4
KZ
766 total_number_of_sectors << 9,
767 (unsigned long long ) UINT_MAX * sector_size,
768 sector_size);
ee5355e0 769 }
6dbe3af9
KZ
770}
771
22853e4a
KZ
772static void
773read_extended(int ext) {
6dbe3af9 774 int i;
22853e4a
KZ
775 struct pte *pex;
776 struct partition *p, *q;
777
778 ext_index = ext;
779 pex = &ptes[ext];
780 pex->ext_pointer = pex->part_table;
6dbe3af9 781
22853e4a 782 p = pex->part_table;
66ee8158
KZ
783 if (!get_start_sect(p)) {
784 fprintf(stderr,
785 _("Bad offset in primary extended partition\n"));
786 return;
787 }
788
789 while (IS_EXTENDED (p->sys_ind)) {
22853e4a
KZ
790 struct pte *pe = &ptes[partitions];
791
6dbe3af9 792 if (partitions >= MAXIMUM_PARTS) {
7eda085c
KZ
793 /* This is not a Linux restriction, but
794 this program uses arrays of size MAXIMUM_PARTS.
795 Do not try to `improve' this test. */
22853e4a
KZ
796 struct pte *pre = &ptes[partitions-1];
797
6dbe3af9 798 fprintf(stderr,
b22550fa
KZ
799 _("Warning: omitting partitions after #%d.\n"
800 "They will be deleted "
801 "if you save this partition table.\n"),
6dbe3af9 802 partitions);
22853e4a
KZ
803 clear_partition(pre->ext_pointer);
804 pre->changed = 1;
6dbe3af9
KZ
805 return;
806 }
22853e4a
KZ
807
808 read_pte(fd, partitions, extended_offset + get_start_sect(p));
809
6dbe3af9 810 if (!extended_offset)
2b6fc908 811 extended_offset = get_start_sect(p);
22853e4a
KZ
812
813 q = p = pt_offset(pe->sectorbuffer, 0);
66ee8158 814 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
5c36a0eb 815 if (IS_EXTENDED (p->sys_ind)) {
22853e4a 816 if (pe->ext_pointer)
c07ebfa1
KZ
817 fprintf(stderr,
818 _("Warning: extra link "
819 "pointer in partition table"
820 " %d\n"), partitions + 1);
6dbe3af9 821 else
22853e4a 822 pe->ext_pointer = p;
5c36a0eb 823 } else if (p->sys_ind) {
22853e4a 824 if (pe->part_table)
6dbe3af9 825 fprintf(stderr,
c07ebfa1
KZ
826 _("Warning: ignoring extra "
827 "data in partition table"
828 " %d\n"), partitions + 1);
6dbe3af9 829 else
22853e4a 830 pe->part_table = p;
5c36a0eb 831 }
6dbe3af9 832 }
22853e4a
KZ
833
834 /* very strange code here... */
835 if (!pe->part_table) {
836 if (q != pe->ext_pointer)
837 pe->part_table = q;
838 else
839 pe->part_table = q + 1;
5c36a0eb 840 }
22853e4a
KZ
841 if (!pe->ext_pointer) {
842 if (q != pe->part_table)
843 pe->ext_pointer = q;
844 else
845 pe->ext_pointer = q + 1;
5c36a0eb 846 }
22853e4a
KZ
847
848 p = pe->ext_pointer;
849 partitions++;
6dbe3af9 850 }
66ee8158
KZ
851
852 /* remove empty links */
853 remove:
854 for (i = 4; i < partitions; i++) {
855 struct pte *pe = &ptes[i];
856
c07ebfa1
KZ
857 if (!get_nr_sects(pe->part_table) &&
858 (partitions > 5 || ptes[4].part_table->sys_ind)) {
add5133f 859 printf(_("omitting empty partition (%d)\n"), i+1);
66ee8158
KZ
860 delete_partition(i);
861 goto remove; /* numbering changed */
862 }
863 }
6dbe3af9
KZ
864}
865
bb6aacfe
PA
866static void
867dos_write_mbr_id(unsigned char *b, unsigned int id) {
868 store4_little_endian(&b[440], id);
869}
870
871static unsigned int
872dos_read_mbr_id(const unsigned char *b) {
873 return read4_little_endian(&b[440]);
874}
875
876static void
877dos_print_mbr_id(void) {
878 printf(_("Disk identifier: 0x%08x\n"), dos_read_mbr_id(MBRbuffer));
879}
880
881static void
882dos_set_mbr_id(void) {
883 unsigned long new_id;
884 char *ep;
885 char ps[64];
886
887 snprintf(ps, sizeof ps, _("New disk identifier (current 0x%08x): "),
888 dos_read_mbr_id(MBRbuffer));
889
890 if (read_chars(ps) == '\n')
891 return;
892
893 new_id = strtoul(line_ptr, &ep, 0);
894 if (*ep != '\n')
895 return;
896
897 dos_write_mbr_id(MBRbuffer, new_id);
898 dos_print_mbr_id();
899}
900
22853e4a
KZ
901static void
902create_doslabel(void) {
bb6aacfe 903 unsigned int id = get_random_id();
2b6fc908
KZ
904
905 fprintf(stderr,
bb6aacfe
PA
906 _("Building a new DOS disklabel with disk identifier 0x%08x.\n"
907 "Changes will remain in memory only, until you decide to write them.\n"
908 "After that, of course, the previous content won't be recoverable.\n\n"),
909 id);
5c36a0eb
KZ
910 sun_nolabel(); /* otherwise always recognised as sun */
911 sgi_nolabel(); /* otherwise always recognised as sgi */
e7fa917a 912 mac_label = aix_label = osf_label = possibly_osf_label = 0;
e8f26419 913 partitions = 4;
5c36a0eb 914
bb6aacfe 915 /* Zero out the MBR buffer */
c07ebfa1 916 extended_offset = 0;
22853e4a
KZ
917 set_all_unchanged();
918 set_changed(0);
e8f26419 919 get_boot(create_empty_dos);
bb6aacfe
PA
920
921 /* Generate an MBR ID for this disk */
922 dos_write_mbr_id(MBRbuffer, id);
923
924 /* Mark it bootable (unfortunately required) */
925 write_part_table_flag(MBRbuffer);
2b6fc908
KZ
926}
927
22853e4a 928static void
05dc9645 929get_topology(int fd) {
810f986b 930 int arg;
05dc9645
KZ
931#ifdef HAVE_LIBBLKID_INTERNAL
932 blkid_probe pr;
810f986b
KZ
933
934 if (user_set_sector_size)
935 return;
05dc9645
KZ
936 pr = blkid_new_probe();
937 if (pr && blkid_probe_set_device(pr, fd, 0, 0) == 0) {
938 blkid_topology tp = blkid_probe_get_topology(pr);
939
940 if (tp) {
941 minimum_io_size = blkid_topology_get_minimum_io_size(tp);
942 alignment_offset = blkid_topology_get_alignment_offset(tp);
943 }
944 }
945 blkid_free_probe(pr);
946#endif
810f986b 947
05dc9645
KZ
948 if (user_set_sector_size)
949 ;
950 else if (blkdev_get_sector_size(fd, &arg) == 0)
810f986b 951 sector_size = arg;
05dc9645
KZ
952
953 if (!minimum_io_size)
954 minimum_io_size = sector_size;
955
810f986b
KZ
956 if (sector_size != DEFAULT_SECTOR_SIZE)
957 printf(_("Note: sector size is %d (not %d)\n"),
958 sector_size, DEFAULT_SECTOR_SIZE);
22853e4a 959}
7eda085c 960
1d4ad1de
KZ
961static void
962get_kernel_geometry(int fd) {
963#ifdef HDIO_GETGEO
964 struct hd_geometry geometry;
965
966 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
967 kern_heads = geometry.heads;
968 kern_sectors = geometry.sectors;
969 /* never use geometry.cylinders - it is truncated */
970 }
971#endif
972}
973
974static void
975get_partition_table_geometry(void) {
976 unsigned char *bufp = MBRbuffer;
977 struct partition *p;
978 int i, h, s, hh, ss;
979 int first = 1;
980 int bad = 0;
981
982 if (!(valid_part_table_flag(bufp)))
983 return;
984
985 hh = ss = 0;
986 for (i=0; i<4; i++) {
987 p = pt_offset(bufp, i);
988 if (p->sys_ind != 0) {
989 h = p->end_head + 1;
990 s = (p->end_sector & 077);
991 if (first) {
992 hh = h;
993 ss = s;
994 first = 0;
995 } else if (hh != h || ss != s)
996 bad = 1;
997 }
998 }
999
1000 if (!first && !bad) {
1001 pt_heads = hh;
1002 pt_sectors = ss;
1003 }
1004}
1005
22853e4a
KZ
1006void
1007get_geometry(int fd, struct geom *g) {
85a994c4 1008 unsigned long long llcyls;
2b6fc908 1009
05dc9645 1010 get_topology(fd);
10e3d031 1011 sector_factor = sector_size / 512;
22853e4a 1012 guess_device_type(fd);
22853e4a 1013 heads = cylinders = sectors = 0;
1d4ad1de
KZ
1014 kern_heads = kern_sectors = 0;
1015 pt_heads = pt_sectors = 0;
1016
1017 get_kernel_geometry(fd);
1018 get_partition_table_geometry();
1019
1020 heads = user_heads ? user_heads :
1021 pt_heads ? pt_heads :
1022 kern_heads ? kern_heads : 255;
1023 sectors = user_sectors ? user_sectors :
1024 pt_sectors ? pt_sectors :
1025 kern_sectors ? kern_sectors : 63;
1026
85a994c4
KZ
1027 if (blkdev_get_sectors(fd, &total_number_of_sectors) == -1)
1028 total_number_of_sectors = 0;
1d4ad1de 1029
22853e4a 1030 sector_offset = 1;
1d4ad1de
KZ
1031 if (dos_compatible_flag)
1032 sector_offset = sectors;
22853e4a 1033
10e3d031 1034 llcyls = total_number_of_sectors / (heads * sectors * sector_factor);
2cccd0ff
KZ
1035 cylinders = llcyls;
1036 if (cylinders != llcyls) /* truncated? */
1037 cylinders = ~0;
22853e4a
KZ
1038 if (!cylinders)
1039 cylinders = user_cylinders;
1040
1041 if (g) {
1042 g->heads = heads;
1043 g->sectors = sectors;
1044 g->cylinders = cylinders;
1045 }
1046}
1047
b2f15782
KZ
1048/*
1049 * Please, always use allocated buffer if you want to cast the buffer to
1050 * any struct -- cast non-allocated buffer to any struct is against
1051 * strict-aliasing rules. --kzak 16-Oct-2009
1052 */
1053static void init_mbr_buffer(void)
1054{
1055 if (MBRbuffer)
1056 return;
1057
1058 MBRbuffer = calloc(1, MAX_SECTOR_SIZE);
1059 if (!MBRbuffer)
1060 fatal(out_of_memory);
1061}
1062
1063void zeroize_mbr_buffer(void)
1064{
1065 if (MBRbuffer)
1066 memset(MBRbuffer, 0, MAX_SECTOR_SIZE);
1067}
1068
22853e4a
KZ
1069/*
1070 * Read MBR. Returns:
1071 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1072 * 0: found or created label
e8f26419 1073 * 1: I/O error
22853e4a
KZ
1074 */
1075int
1076get_boot(enum action what) {
1077 int i;
1078
1079 partitions = 4;
c129767e
KZ
1080 ext_index = 0;
1081 extended_offset = 0;
22853e4a 1082
63cccae4
KZ
1083 for (i = 0; i < 4; i++) {
1084 struct pte *pe = &ptes[i];
1085
1086 pe->part_table = pt_offset(MBRbuffer, i);
1087 pe->ext_pointer = NULL;
1088 pe->offset = 0;
1089 pe->sectorbuffer = MBRbuffer;
1090 pe->changed = (what == create_empty_dos);
1091 }
1092
24f4bbff
KZ
1093 if (what == create_empty_sun && check_sun_label())
1094 return 0;
1095
63cccae4
KZ
1096 memset(MBRbuffer, 0, 512);
1097
e8f26419
KZ
1098 if (what == create_empty_dos)
1099 goto got_dos_table; /* skip reading disk */
22853e4a
KZ
1100
1101 if ((fd = open(disk_device, type_open)) < 0) {
e8f26419
KZ
1102 if ((fd = open(disk_device, O_RDONLY)) < 0) {
1103 if (what == try_only)
1104 return 1;
22853e4a 1105 fatal(unable_to_open);
e8f26419 1106 } else
63cccae4
KZ
1107 printf(_("You will not be able to write "
1108 "the partition table.\n"));
22853e4a
KZ
1109 }
1110
1d4ad1de 1111 if (512 != read(fd, MBRbuffer, 512)) {
e8f26419
KZ
1112 if (what == try_only)
1113 return 1;
22853e4a 1114 fatal(unable_to_read);
e8f26419 1115 }
22853e4a 1116
1d4ad1de
KZ
1117 get_geometry(fd, NULL);
1118
1119 update_units();
1120
2b6fc908
KZ
1121 if (check_sun_label())
1122 return 0;
5c36a0eb
KZ
1123
1124 if (check_sgi_label())
1125 return 0;
1126
1127 if (check_aix_label())
1128 return 0;
2b6fc908 1129
e7fa917a
KZ
1130 if (check_mac_label())
1131 return 0;
1132
63cccae4
KZ
1133 if (check_osf_label()) {
1134 possibly_osf_label = 1;
1135 if (!valid_part_table_flag(MBRbuffer)) {
1136 osf_label = 1;
1137 return 0;
1138 }
1139 printf(_("This disk has both DOS and BSD magic.\n"
1140 "Give the 'b' command to go to BSD mode.\n"));
1141 }
22853e4a 1142
e8f26419
KZ
1143got_dos_table:
1144
22853e4a 1145 if (!valid_part_table_flag(MBRbuffer)) {
2b6fc908
KZ
1146 switch(what) {
1147 case fdisk:
1148 fprintf(stderr,
63cccae4
KZ
1149 _("Device contains neither a valid DOS "
1150 "partition table, nor Sun, SGI or OSF "
1151 "disklabel\n"));
2b6fc908
KZ
1152#ifdef __sparc__
1153 create_sunlabel();
1154#else
1155 create_doslabel();
1156#endif
1157 return 0;
1158 case require:
1159 return -1;
1160 case try_only:
1161 return -1;
e8f26419
KZ
1162 case create_empty_dos:
1163 case create_empty_sun:
2b6fc908 1164 break;
f0c8eda1
KZ
1165 default:
1166 fprintf(stderr, _("Internal error\n"));
1167 exit(1);
2b6fc908 1168 }
fd6b7a7f
KZ
1169 }
1170
2b6fc908
KZ
1171 warn_cylinders();
1172 warn_geometry();
1173
22853e4a
KZ
1174 for (i = 0; i < 4; i++) {
1175 struct pte *pe = &ptes[i];
1176
1177 if (IS_EXTENDED (pe->part_table->sys_ind)) {
6dbe3af9 1178 if (partitions != 4)
7eda085c
KZ
1179 fprintf(stderr, _("Ignoring extra extended "
1180 "partition %d\n"), i + 1);
22853e4a
KZ
1181 else
1182 read_extended(i);
5c36a0eb 1183 }
22853e4a
KZ
1184 }
1185
1186 for (i = 3; i < partitions; i++) {
1187 struct pte *pe = &ptes[i];
1188
1189 if (!valid_part_table_flag(pe->sectorbuffer)) {
2b6fc908 1190 fprintf(stderr,
7eda085c
KZ
1191 _("Warning: invalid flag 0x%04x of partition "
1192 "table %d will be corrected by w(rite)\n"),
22853e4a
KZ
1193 part_table_flag(pe->sectorbuffer), i + 1);
1194 pe->changed = 1;
6dbe3af9 1195 }
22853e4a 1196 }
fd6b7a7f 1197
2b6fc908 1198 return 0;
6dbe3af9
KZ
1199}
1200
5c36a0eb
KZ
1201/* read line; return 0 or first char */
1202int
1203read_line(void)
6dbe3af9 1204{
7eda085c
KZ
1205 static int got_eof = 0;
1206
5c36a0eb 1207 line_ptr = line_buffer;
7eda085c
KZ
1208 if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
1209 if (feof(stdin))
1210 got_eof++; /* user typed ^D ? */
1211 if (got_eof >= 3) {
1212 fflush(stdout);
1213 fprintf(stderr, _("\ngot EOF thrice - exiting..\n"));
1214 exit(1);
1215 }
6dbe3af9 1216 return 0;
7eda085c 1217 }
6dbe3af9
KZ
1218 while (*line_ptr && !isgraph(*line_ptr))
1219 line_ptr++;
1220 return *line_ptr;
1221}
1222
5c36a0eb
KZ
1223char
1224read_char(char *mesg)
6dbe3af9 1225{
2b6fc908 1226 do {
6dbe3af9 1227 fputs(mesg, stdout);
66ee8158 1228 fflush (stdout); /* requested by niles@scyld.com */
2b6fc908 1229 } while (!read_line());
6dbe3af9
KZ
1230 return *line_ptr;
1231}
1232
5c36a0eb
KZ
1233char
1234read_chars(char *mesg)
2b6fc908
KZ
1235{
1236 fputs(mesg, stdout);
66ee8158 1237 fflush (stdout); /* niles@scyld.com */
2b6fc908
KZ
1238 if (!read_line()) {
1239 *line_ptr = '\n';
5c36a0eb
KZ
1240 line_ptr[1] = 0;
1241 }
1242 return *line_ptr;
2b6fc908
KZ
1243}
1244
5c36a0eb
KZ
1245int
1246read_hex(struct systypes *sys)
6dbe3af9 1247{
726f69e2
KZ
1248 int hex;
1249
1250 while (1)
1251 {
7eda085c 1252 read_char(_("Hex code (type L to list codes): "));
726f69e2 1253 if (tolower(*line_ptr) == 'l')
2b6fc908 1254 list_types(sys);
726f69e2
KZ
1255 else if (isxdigit (*line_ptr))
1256 {
1257 hex = 0;
1258 do
1259 hex = hex << 4 | hex_val(*line_ptr++);
1260 while (isxdigit(*line_ptr));
1261 return hex;
1262 }
1263 }
1264}
1265
5c36a0eb 1266/*
c129767e
KZ
1267 * Print the message MESG, then read an integer in LOW..HIGH.
1268 * If the user hits Enter, DFLT is returned, provided that is in LOW..HIGH.
5c36a0eb
KZ
1269 * Answers like +10 are interpreted as offsets from BASE.
1270 *
1271 * There is no default if DFLT is not between LOW and HIGH.
1272 */
df1dddf9
KZ
1273unsigned int
1274read_int(unsigned int low, unsigned int dflt, unsigned int high,
1275 unsigned int base, char *mesg)
726f69e2 1276{
df1dddf9 1277 unsigned int i;
5c36a0eb
KZ
1278 int default_ok = 1;
1279 static char *ms = NULL;
1280 static int mslen = 0;
1281
c07ebfa1
KZ
1282 if (!ms || strlen(mesg)+100 > mslen) {
1283 mslen = strlen(mesg)+200;
5c36a0eb
KZ
1284 if (!(ms = realloc(ms,mslen)))
1285 fatal(out_of_memory);
726f69e2 1286 }
6dbe3af9 1287
5c36a0eb
KZ
1288 if (dflt < low || dflt > high)
1289 default_ok = 0;
1290
1291 if (default_ok)
df1dddf9 1292 snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
c07ebfa1 1293 mesg, low, high, dflt);
5c36a0eb 1294 else
df1dddf9 1295 snprintf(ms, mslen, "%s (%u-%u): ",
c07ebfa1 1296 mesg, low, high);
5c36a0eb 1297
6dbe3af9 1298 while (1) {
5c36a0eb
KZ
1299 int use_default = default_ok;
1300
1301 /* ask question and read answer */
1302 while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
1303 && *line_ptr != '-' && *line_ptr != '+')
1304 continue;
1305
726f69e2 1306 if (*line_ptr == '+' || *line_ptr == '-') {
a5a16c68
KZ
1307 int minus = (*line_ptr == '-');
1308 int absolute = 0;
b1edb510 1309 int suflen;
a5a16c68 1310
5c36a0eb 1311 i = atoi(line_ptr+1);
a5a16c68 1312
b1edb510 1313 while (isdigit(*++line_ptr))
726f69e2 1314 use_default = 0;
a5a16c68 1315
b1edb510
KZ
1316 suflen = strlen(line_ptr) - 1;
1317
1318 while(isspace(*(line_ptr + suflen)))
1319 *(line_ptr + suflen--) = '\0';
1320
1321 if ((*line_ptr == 'C' || *line_ptr == 'c') &&
1322 *(line_ptr + 1) == '\0') {
1323 /*
1324 * Cylinders
1325 */
1326 if (!display_in_cyl_units)
1327 i *= heads * sectors;
5ea8931c
KZ
1328 } else if (*line_ptr &&
1329 *(line_ptr + 1) == 'B' &&
b1edb510
KZ
1330 *(line_ptr + 2) == '\0') {
1331 /*
1332 * 10^N
1333 */
1334 if (*line_ptr == 'K')
a5a16c68 1335 absolute = 1000;
b1edb510 1336 else if (*line_ptr == 'M')
a5a16c68 1337 absolute = 1000000;
b1edb510 1338 else if (*line_ptr == 'G')
a5a16c68 1339 absolute = 1000000000;
b1edb510
KZ
1340 else
1341 absolute = -1;
5ea8931c
KZ
1342 } else if (*line_ptr &&
1343 *(line_ptr + 1) == '\0') {
b1edb510
KZ
1344 /*
1345 * 2^N
1346 */
1347 if (*line_ptr == 'K')
1348 absolute = 1 << 10;
1349 else if (*line_ptr == 'M')
1350 absolute = 1 << 20;
1351 else if (*line_ptr == 'G')
1352 absolute = 1 << 30;
1353 else
1354 absolute = -1;
1355 } else if (*line_ptr != '\0')
1356 absolute = -1;
1357
1358 if (absolute == -1) {
1359 printf(_("Unsupported suffix: '%s'.\n"), line_ptr);
1360 printf(_("Supported: 10^N: KB (KiloByte), MB (MegaByte), GB (GigaByte)\n"
1361 " 2^N: K (KibiByte), M (MebiByte), G (GibiByte)\n"));
1362 continue;
726f69e2 1363 }
b1edb510
KZ
1364
1365 if (absolute && i) {
a5a16c68
KZ
1366 unsigned long long bytes;
1367 unsigned long unit;
1368
1369 bytes = (unsigned long long) i * absolute;
1370 unit = sector_size * units_per_sector;
1371 bytes += unit/2; /* round */
1372 bytes /= unit;
1373 i = bytes;
1374 }
1375 if (minus)
1376 i = -i;
5c36a0eb
KZ
1377 i += base;
1378 } else {
726f69e2 1379 i = atoi(line_ptr);
5c36a0eb 1380 while (isdigit(*line_ptr)) {
726f69e2
KZ
1381 line_ptr++;
1382 use_default = 0;
1383 }
1384 }
1385 if (use_default)
df1dddf9 1386 printf(_("Using default value %u\n"), i = dflt);
6dbe3af9
KZ
1387 if (i >= low && i <= high)
1388 break;
726f69e2 1389 else
7eda085c 1390 printf(_("Value out of range.\n"));
6dbe3af9 1391 }
6dbe3af9
KZ
1392 return i;
1393}
1394
22853e4a
KZ
1395int
1396get_partition(int warn, int max) {
1397 struct pte *pe;
1398 int i;
1399
1400 i = read_int(1, 0, max, 0, _("Partition number")) - 1;
1401 pe = &ptes[i];
6dbe3af9 1402
24f4bbff
KZ
1403 if (warn) {
1404 if ((!sun_label && !sgi_label && !pe->part_table->sys_ind)
1405 || (sun_label &&
1406 (!sunlabel->partitions[i].num_sectors ||
899736f1 1407 !sunlabel->part_tags[i].tag))
24f4bbff
KZ
1408 || (sgi_label && (!sgi_get_num_sectors(i)))
1409 )
1410 fprintf(stderr,
1411 _("Warning: partition %d has empty type\n"),
1412 i+1);
1413 }
6dbe3af9
KZ
1414 return i;
1415}
1416
24f4bbff
KZ
1417static int
1418get_existing_partition(int warn, int max) {
1419 int pno = -1;
1420 int i;
1421
1422 for (i = 0; i < max; i++) {
1423 struct pte *pe = &ptes[i];
1424 struct partition *p = pe->part_table;
1425
1426 if (p && !is_cleared_partition(p)) {
1427 if (pno >= 0)
1428 goto not_unique;
1429 pno = i;
1430 }
1431 }
1432 if (pno >= 0) {
1433 printf(_("Selected partition %d\n"), pno+1);
1434 return pno;
1435 }
1436 printf(_("No partition is defined yet!\n"));
1437 return -1;
1438
1439 not_unique:
1440 return get_partition(warn, max);
1441}
1442
1443static int
1444get_nonexisting_partition(int warn, int max) {
1445 int pno = -1;
1446 int i;
1447
1448 for (i = 0; i < max; i++) {
1449 struct pte *pe = &ptes[i];
1450 struct partition *p = pe->part_table;
1451
1452 if (p && is_cleared_partition(p)) {
1453 if (pno >= 0)
1454 goto not_unique;
1455 pno = i;
1456 }
1457 }
1458 if (pno >= 0) {
1459 printf(_("Selected partition %d\n"), pno+1);
1460 return pno;
1461 }
1462 printf(_("All primary partitions have been defined already!\n"));
1463 return -1;
1464
1465 not_unique:
1466 return get_partition(warn, max);
1467}
1468
bf8df991 1469const char *
22853e4a 1470str_units(int n) { /* n==1: use singular */
7eda085c
KZ
1471 if (n == 1)
1472 return display_in_cyl_units ? _("cylinder") : _("sector");
1473 else
1474 return display_in_cyl_units ? _("cylinders") : _("sectors");
6dbe3af9
KZ
1475}
1476
1477void change_units(void)
1478{
7eda085c 1479 display_in_cyl_units = !display_in_cyl_units;
6dbe3af9 1480 update_units();
7eda085c
KZ
1481 printf(_("Changing display/entry units to %s\n"),
1482 str_units(PLURAL));
6dbe3af9
KZ
1483}
1484
22853e4a
KZ
1485static void
1486toggle_active(int i) {
1487 struct pte *pe = &ptes[i];
1488 struct partition *p = pe->part_table;
6dbe3af9 1489
2b6fc908 1490 if (IS_EXTENDED (p->sys_ind) && !p->boot_ind)
6dbe3af9 1491 fprintf(stderr,
7eda085c 1492 _("WARNING: Partition %d is an extended partition\n"),
6dbe3af9 1493 i + 1);
22853e4a
KZ
1494 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1495 pe->changed = 1;
6dbe3af9
KZ
1496}
1497
22853e4a
KZ
1498static void
1499toggle_dos_compatibility_flag(void) {
6dbe3af9 1500 dos_compatible_flag = ~dos_compatible_flag;
7eda085c 1501 if (dos_compatible_flag) {
6dbe3af9 1502 sector_offset = sectors;
7eda085c
KZ
1503 printf(_("DOS Compatibility flag is set\n"));
1504 }
6dbe3af9
KZ
1505 else {
1506 sector_offset = 1;
7eda085c 1507 printf(_("DOS Compatibility flag is not set\n"));
6dbe3af9 1508 }
6dbe3af9
KZ
1509}
1510
22853e4a
KZ
1511static void
1512delete_partition(int i) {
1513 struct pte *pe = &ptes[i];
1514 struct partition *p = pe->part_table;
1515 struct partition *q = pe->ext_pointer;
6dbe3af9
KZ
1516
1517/* Note that for the fifth partition (i == 4) we don't actually
1518 * decrement partitions.
1519 */
1520
1521 if (warn_geometry())
e8f26419 1522 return; /* C/H/S not set */
22853e4a 1523 pe->changed = 1;
5c36a0eb 1524
2b6fc908
KZ
1525 if (sun_label) {
1526 sun_delete_partition(i);
1527 return;
1528 }
66ee8158 1529
5c36a0eb
KZ
1530 if (sgi_label) {
1531 sgi_delete_partition(i);
1532 return;
1533 }
66ee8158 1534
6dbe3af9 1535 if (i < 4) {
2b6fc908 1536 if (IS_EXTENDED (p->sys_ind) && i == ext_index) {
22853e4a
KZ
1537 partitions = 4;
1538 ptes[ext_index].ext_pointer = NULL;
6dbe3af9
KZ
1539 extended_offset = 0;
1540 }
1541 clear_partition(p);
66ee8158 1542 return;
6dbe3af9 1543 }
66ee8158
KZ
1544
1545 if (!q->sys_ind && i > 4) {
c07ebfa1 1546 /* the last one in the chain - just delete */
22853e4a
KZ
1547 --partitions;
1548 --i;
1549 clear_partition(ptes[i].ext_pointer);
1550 ptes[i].changed = 1;
66ee8158 1551 } else {
c07ebfa1 1552 /* not the last one - further ones will be moved down */
6dbe3af9 1553 if (i > 4) {
c07ebfa1 1554 /* delete this link in the chain */
22853e4a 1555 p = ptes[i-1].ext_pointer;
364cda48 1556 *p = *q;
2b6fc908
KZ
1557 set_start_sect(p, get_start_sect(q));
1558 set_nr_sects(p, get_nr_sects(q));
22853e4a 1559 ptes[i-1].changed = 1;
66ee8158 1560 } else if (partitions > 5) { /* 5 will be moved to 4 */
c07ebfa1 1561 /* the first logical in a longer chain */
22853e4a
KZ
1562 struct pte *pe = &ptes[5];
1563
63cccae4 1564 if (pe->part_table) /* prevent SEGFAULT */
22853e4a
KZ
1565 set_start_sect(pe->part_table,
1566 get_partition_start(pe) -
1567 extended_offset);
1568 pe->offset = extended_offset;
1569 pe->changed = 1;
6dbe3af9 1570 }
66ee8158 1571
6dbe3af9
KZ
1572 if (partitions > 5) {
1573 partitions--;
6dbe3af9 1574 while (i < partitions) {
22853e4a 1575 ptes[i] = ptes[i+1];
6dbe3af9
KZ
1576 i++;
1577 }
22853e4a 1578 } else
c07ebfa1 1579 /* the only logical: clear only */
22853e4a 1580 clear_partition(ptes[i].part_table);
6dbe3af9
KZ
1581 }
1582}
1583
22853e4a
KZ
1584static void
1585change_sysid(void) {
6dbe3af9 1586 char *temp;
24f4bbff
KZ
1587 int i, sys, origsys;
1588 struct partition *p;
6dbe3af9 1589
df1dddf9
KZ
1590 /* If sgi_label then don't use get_existing_partition,
1591 let the user select a partition, since get_existing_partition()
1592 only works for Linux like partition tables. */
c64061c9 1593 if (!sgi_label) {
df1dddf9
KZ
1594 i = get_existing_partition(0, partitions);
1595 } else {
1596 i = get_partition(0, partitions);
1597 }
1598
24f4bbff
KZ
1599 if (i == -1)
1600 return;
1601 p = ptes[i].part_table;
5c36a0eb 1602 origsys = sys = get_sysid(i);
2b6fc908 1603
0e6f4a20
KZ
1604 /* if changing types T to 0 is allowed, then
1605 the reverse change must be allowed, too */
1606 if (!sys && !sgi_label && !sun_label && !get_nr_sects(p))
7eda085c 1607 printf(_("Partition %d does not exist yet!\n"), i + 1);
2b6fc908 1608 else while (1) {
5c36a0eb
KZ
1609 sys = read_hex (get_sys_types());
1610
c07ebfa1 1611 if (!sys && !sgi_label && !sun_label) {
7eda085c 1612 printf(_("Type 0 means free space to many systems\n"
5c36a0eb
KZ
1613 "(but not to Linux). Having partitions of\n"
1614 "type 0 is probably unwise. You can delete\n"
7eda085c 1615 "a partition using the `d' command.\n"));
5c36a0eb 1616 /* break; */
2b6fc908
KZ
1617 }
1618
5c36a0eb 1619 if (!sun_label && !sgi_label) {
2b6fc908 1620 if (IS_EXTENDED (sys) != IS_EXTENDED (p->sys_ind)) {
7eda085c 1621 printf(_("You cannot change a partition into"
2b6fc908 1622 " an extended one or vice versa\n"
7eda085c 1623 "Delete it first.\n"));
6dbe3af9
KZ
1624 break;
1625 }
1626 }
2b6fc908
KZ
1627
1628 if (sys < 256) {
899736f1 1629 if (sun_label && i == 2 && sys != SUN_TAG_BACKUP)
7eda085c 1630 printf(_("Consider leaving partition 3 "
2b6fc908
KZ
1631 "as Whole disk (5),\n"
1632 "as SunOS/Solaris expects it and "
7eda085c 1633 "even Linux likes it.\n\n"));
5c36a0eb
KZ
1634 if (sgi_label && ((i == 10 && sys != ENTIRE_DISK)
1635 || (i == 8 && sys != 0)))
7eda085c 1636 printf(_("Consider leaving partition 9 "
5c36a0eb 1637 "as volume header (0),\nand "
6557c512 1638 "partition 11 as entire volume (6), "
7eda085c 1639 "as IRIX expects it.\n\n"));
2b6fc908 1640 if (sys == origsys)
0e6f4a20 1641 break;
5c36a0eb 1642 if (sun_label) {
cc2ce945 1643 ptes[i].changed = sun_change_sysid(i, sys);
2b6fc908 1644 } else
5c36a0eb 1645 if (sgi_label) {
cc2ce945
MF
1646 ptes[i].changed = sgi_change_sysid(i, sys);
1647 } else {
22853e4a 1648 p->sys_ind = sys;
cc2ce945
MF
1649 ptes[i].changed = 1;
1650 }
1651 temp = partition_type(sys) ? : _("Unknown");
1652 if (ptes[i].changed)
1653 printf (_("Changed system type of partition %d "
1654 "to %x (%s)\n"), i + 1, sys, temp);
1655 else
fe82c712
KZ
1656 printf (_("System type of partition %d is unchanged: "
1657 "%x (%s)\n"), i + 1, sys, temp);
e8f26419
KZ
1658 if (is_dos_partition(origsys) ||
1659 is_dos_partition(sys))
1660 dos_changed = 1;
2b6fc908
KZ
1661 break;
1662 }
1663 }
6dbe3af9
KZ
1664}
1665
1666/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
1667 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1668 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1669 * Lubkin Oct. 1991). */
1670
df1dddf9
KZ
1671static void
1672long2chs(ulong ls, unsigned int *c, unsigned int *h, unsigned int *s) {
1673 int spc = heads * sectors;
6dbe3af9
KZ
1674
1675 *c = ls / spc;
1676 ls = ls % spc;
1677 *h = ls / sectors;
1678 *s = ls % sectors + 1; /* sectors count from 1 */
1679}
1680
22853e4a 1681static void check_consistency(struct partition *p, int partition) {
df1dddf9
KZ
1682 unsigned int pbc, pbh, pbs; /* physical beginning c, h, s */
1683 unsigned int pec, peh, pes; /* physical ending c, h, s */
1684 unsigned int lbc, lbh, lbs; /* logical beginning c, h, s */
1685 unsigned int lec, leh, les; /* logical ending c, h, s */
6dbe3af9
KZ
1686
1687 if (!heads || !sectors || (partition >= 4))
1688 return; /* do not check extended partitions */
1689
1690/* physical beginning c, h, s */
fd6b7a7f 1691 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
6dbe3af9
KZ
1692 pbh = p->head;
1693 pbs = p->sector & 0x3f;
1694
1695/* physical ending c, h, s */
fd6b7a7f 1696 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
6dbe3af9
KZ
1697 peh = p->end_head;
1698 pes = p->end_sector & 0x3f;
1699
1700/* compute logical beginning (c, h, s) */
2b6fc908 1701 long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
6dbe3af9
KZ
1702
1703/* compute logical ending (c, h, s) */
2b6fc908 1704 long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
6dbe3af9
KZ
1705
1706/* Same physical / logical beginning? */
1707 if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
7eda085c
KZ
1708 printf(_("Partition %d has different physical/logical "
1709 "beginnings (non-Linux?):\n"), partition + 1);
1710 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
1711 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
6dbe3af9
KZ
1712 }
1713
1714/* Same physical / logical ending? */
1715 if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
7eda085c
KZ
1716 printf(_("Partition %d has different physical/logical "
1717 "endings:\n"), partition + 1);
1718 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
1719 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
6dbe3af9
KZ
1720 }
1721
726f69e2 1722#if 0
6dbe3af9
KZ
1723/* Beginning on cylinder boundary? */
1724 if (pbh != !pbc || pbs != 1) {
7eda085c
KZ
1725 printf(_("Partition %i does not start on cylinder "
1726 "boundary:\n"), partition + 1);
1727 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
1728 printf(_("should be (%d, %d, 1)\n"), pbc, !pbc);
6dbe3af9 1729 }
726f69e2 1730#endif
6dbe3af9
KZ
1731
1732/* Ending on cylinder boundary? */
1733 if (peh != (heads - 1) || pes != sectors) {
a5a16c68 1734 printf(_("Partition %i does not end on cylinder boundary.\n"),
6dbe3af9 1735 partition + 1);
24f4bbff 1736#if 0
7eda085c
KZ
1737 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
1738 printf(_("should be (%d, %d, %d)\n"),
6dbe3af9 1739 pec, heads - 1, sectors);
24f4bbff 1740#endif
6dbe3af9
KZ
1741 }
1742}
1743
22853e4a
KZ
1744static void
1745list_disk_geometry(void) {
df1dddf9 1746 long long bytes = (total_number_of_sectors << 9);
24f4bbff
KZ
1747 long megabytes = bytes/1000000;
1748
1749 if (megabytes < 10000)
1750 printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
1751 disk_device, megabytes, bytes);
32b40fec
KZ
1752 else {
1753 long hectomega = (megabytes + 50) / 100;
24f4bbff 1754 printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
32b40fec
KZ
1755 disk_device, hectomega / 10, hectomega % 10, bytes);
1756 }
be97c5f3 1757 printf(_("%d heads, %llu sectors/track, %d cylinders"),
24f4bbff
KZ
1758 heads, sectors, cylinders);
1759 if (units_per_sector == 1)
df1dddf9 1760 printf(_(", total %llu sectors"),
10e3d031 1761 total_number_of_sectors / sector_factor);
24f4bbff 1762 printf("\n");
bb6aacfe 1763 printf(_("Units = %s of %d * %d = %d bytes\n"),
24f4bbff
KZ
1764 str_units(PLURAL),
1765 units_per_sector, sector_size, units_per_sector * sector_size);
05dc9645
KZ
1766
1767 printf(_("Sector size (logical/physical): %u bytes / %lu bytes\n"),
1768 sector_size, minimum_io_size);
1769 if (alignment_offset)
1770 printf(_("Alignment offset: %lu bytes\n"), alignment_offset);
bb6aacfe
PA
1771 if (dos_label)
1772 dos_print_mbr_id();
1773 printf("\n");
5c36a0eb
KZ
1774}
1775
22853e4a
KZ
1776/*
1777 * Check whether partition entries are ordered by their starting positions.
1778 * Return 0 if OK. Return i if partition i should have been earlier.
1779 * Two separate checks: primary and logical partitions.
1780 */
1781static int
1782wrong_p_order(int *prev) {
1783 struct pte *pe;
1784 struct partition *p;
df1dddf9 1785 unsigned int last_p_start_pos = 0, p_start_pos;
22853e4a
KZ
1786 int i, last_i = 0;
1787
1788 for (i = 0 ; i < partitions; i++) {
1789 if (i == 4) {
1790 last_i = 4;
1791 last_p_start_pos = 0;
1792 }
1793 pe = &ptes[i];
1794 if ((p = pe->part_table)->sys_ind) {
1795 p_start_pos = get_partition_start(pe);
1796
1797 if (last_p_start_pos > p_start_pos) {
1798 if (prev)
1799 *prev = last_i;
1800 return i;
1801 }
1802
1803 last_p_start_pos = p_start_pos;
1804 last_i = i;
1805 }
1806 }
1807 return 0;
1808}
1809
364cda48
KZ
1810/*
1811 * Fix the chain of logicals.
1812 * extended_offset is unchanged, the set of sectors used is unchanged
1813 * The chain is sorted so that sectors increase, and so that
1814 * starting sectors increase.
1815 *
1816 * After this it may still be that cfdisk doesnt like the table.
1817 * (This is because cfdisk considers expanded parts, from link to
1818 * end of partition, and these may still overlap.)
1819 * Now
1820 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
1821 * may help.
1822 */
1823static void
1824fix_chain_of_logicals(void) {
1825 int j, oj, ojj, sj, sjj;
1826 struct partition *pj,*pjj,tmp;
1827
1828 /* Stage 1: sort sectors but leave sector of part 4 */
1829 /* (Its sector is the global extended_offset.) */
1830 stage1:
63cccae4 1831 for (j = 5; j < partitions-1; j++) {
364cda48
KZ
1832 oj = ptes[j].offset;
1833 ojj = ptes[j+1].offset;
1834 if (oj > ojj) {
1835 ptes[j].offset = ojj;
1836 ptes[j+1].offset = oj;
1837 pj = ptes[j].part_table;
1838 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
1839 pjj = ptes[j+1].part_table;
1840 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
1841 set_start_sect(ptes[j-1].ext_pointer,
1842 ojj-extended_offset);
1843 set_start_sect(ptes[j].ext_pointer,
1844 oj-extended_offset);
1845 goto stage1;
1846 }
1847 }
1848
1849 /* Stage 2: sort starting sectors */
1850 stage2:
63cccae4 1851 for (j = 4; j < partitions-1; j++) {
364cda48
KZ
1852 pj = ptes[j].part_table;
1853 pjj = ptes[j+1].part_table;
1854 sj = get_start_sect(pj);
1855 sjj = get_start_sect(pjj);
1856 oj = ptes[j].offset;
1857 ojj = ptes[j+1].offset;
1858 if (oj+sj > ojj+sjj) {
1859 tmp = *pj;
1860 *pj = *pjj;
1861 *pjj = tmp;
1862 set_start_sect(pj, ojj+sjj-oj);
1863 set_start_sect(pjj, oj+sj-ojj);
1864 goto stage2;
1865 }
1866 }
1867
1868 /* Probably something was changed */
63cccae4 1869 for (j = 4; j < partitions; j++)
364cda48
KZ
1870 ptes[j].changed = 1;
1871}
1872
22853e4a
KZ
1873static void
1874fix_partition_table_order(void) {
364cda48 1875 struct pte *pei, *pek;
22853e4a
KZ
1876 int i,k;
1877
63cccae4 1878 if (!wrong_p_order(NULL)) {
22853e4a
KZ
1879 printf(_("Nothing to do. Ordering is correct already.\n\n"));
1880 return;
1881 }
1882
364cda48 1883 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
22853e4a 1884 /* partition i should have come earlier, move it */
364cda48
KZ
1885 /* We have to move data in the MBR */
1886 struct partition *pi, *pk, *pe, pbuf;
22853e4a
KZ
1887 pei = &ptes[i];
1888 pek = &ptes[k];
1889
364cda48
KZ
1890 pe = pei->ext_pointer;
1891 pei->ext_pointer = pek->ext_pointer;
1892 pek->ext_pointer = pe;
22853e4a 1893
364cda48
KZ
1894 pi = pei->part_table;
1895 pk = pek->part_table;
22853e4a 1896
364cda48
KZ
1897 memmove(&pbuf, pi, sizeof(struct partition));
1898 memmove(pi, pk, sizeof(struct partition));
1899 memmove(pk, &pbuf, sizeof(struct partition));
22853e4a 1900
22853e4a 1901 pei->changed = pek->changed = 1;
22853e4a 1902 }
364cda48
KZ
1903
1904 if (i)
1905 fix_chain_of_logicals();
1906
add5133f 1907 printf(_("Done.\n"));
364cda48 1908
22853e4a
KZ
1909}
1910
1911static void
1912list_table(int xtra) {
6dbe3af9
KZ
1913 struct partition *p;
1914 char *type;
2b6fc908
KZ
1915 int i, w;
1916
5c36a0eb 1917 if (sun_label) {
2b6fc908 1918 sun_list_table(xtra);
5c36a0eb
KZ
1919 return;
1920 }
1921
1922 if (sgi_label) {
1923 sgi_list_table(xtra);
1924 return;
1925 }
2b6fc908 1926
22853e4a
KZ
1927 list_disk_geometry();
1928
1929 if (osf_label) {
1930 xbsd_print_disklabel(xtra);
1931 return;
1932 }
1933
d162fcb5
KZ
1934 if (is_garbage_table()) {
1935 printf(_("This doesn't look like a partition table\n"
1936 "Probably you selected the wrong device.\n\n"));
1937 }
d162fcb5 1938
5c36a0eb
KZ
1939 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
1940 but if the device name ends in a digit, say /dev/foo1,
1941 then the partition is called /dev/foo1p3. */
22853e4a
KZ
1942 w = strlen(disk_device);
1943 if (w && isdigit(disk_device[w-1]))
1944 w++;
6dbe3af9
KZ
1945 if (w < 5)
1946 w = 5;
7eda085c 1947
df1dddf9 1948 printf(_("%*s Boot Start End Blocks Id System\n"),
22853e4a 1949 w+1, _("Device"));
2b6fc908 1950
24f4bbff 1951 for (i = 0; i < partitions; i++) {
22853e4a
KZ
1952 struct pte *pe = &ptes[i];
1953
1954 p = pe->part_table;
e8f26419 1955 if (p && !is_cleared_partition(p)) {
2b6fc908 1956 unsigned int psects = get_nr_sects(p);
5c36a0eb
KZ
1957 unsigned int pblocks = psects;
1958 unsigned int podd = 0;
1959
1960 if (sector_size < 1024) {
1961 pblocks /= (1024 / sector_size);
1962 podd = psects % (1024 / sector_size);
1963 }
1964 if (sector_size > 1024)
1965 pblocks *= (sector_size / 1024);
2b6fc908 1966 printf(
df1dddf9 1967 "%s %c %11lu %11lu %11lu%c %2x %s\n",
22853e4a 1968 partname(disk_device, i+1, w+2),
726f69e2 1969/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
6dbe3af9 1970 ? '*' : '?',
df1dddf9
KZ
1971/* start */ (unsigned long) cround(get_partition_start(pe)),
1972/* end */ (unsigned long) cround(get_partition_start(pe) + psects
2b6fc908 1973 - (psects ? 1 : 0)),
df1dddf9 1974/* odd flag on end */ (unsigned long) pblocks, podd ? '+' : ' ',
726f69e2
KZ
1975/* type id */ p->sys_ind,
1976/* type name */ (type = partition_type(p->sys_ind)) ?
7eda085c 1977 type : _("Unknown"));
6dbe3af9
KZ
1978 check_consistency(p, i);
1979 }
2b6fc908 1980 }
c07ebfa1 1981
22853e4a
KZ
1982 /* Is partition table in disk order? It need not be, but... */
1983 /* partition table entries are not checked for correct order if this
1984 is a sgi, sun or aix labeled disk... */
1985 if (dos_label && wrong_p_order(NULL)) {
1986 printf(_("\nPartition table entries are not in disk order\n"));
1987 }
6dbe3af9
KZ
1988}
1989
22853e4a
KZ
1990static void
1991x_list_table(int extend) {
1992 struct pte *pe;
1993 struct partition *p;
6dbe3af9
KZ
1994 int i;
1995
be97c5f3 1996 printf(_("\nDisk %s: %d heads, %llu sectors, %d cylinders\n\n"),
6dbe3af9 1997 disk_device, heads, sectors, cylinders);
df1dddf9 1998 printf(_("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"));
22853e4a
KZ
1999 for (i = 0 ; i < partitions; i++) {
2000 pe = &ptes[i];
2001 p = (extend ? pe->ext_pointer : pe->part_table);
2002 if (p != NULL) {
be97c5f3 2003 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11lu%11lu %02x\n",
6dbe3af9
KZ
2004 i + 1, p->boot_ind, p->head,
2005 sector(p->sector),
2006 cylinder(p->sector, p->cyl), p->end_head,
2007 sector(p->end_sector),
2008 cylinder(p->end_sector, p->end_cyl),
be97c5f3
KZ
2009 (unsigned long) get_start_sect(p),
2010 (unsigned long) get_nr_sects(p), p->sys_ind);
6dbe3af9
KZ
2011 if (p->sys_ind)
2012 check_consistency(p, i);
2013 }
22853e4a 2014 }
6dbe3af9
KZ
2015}
2016
22853e4a 2017static void
be97c5f3 2018fill_bounds(unsigned long long *first, unsigned long long *last) {
6dbe3af9 2019 int i;
22853e4a
KZ
2020 struct pte *pe = &ptes[0];
2021 struct partition *p;
6dbe3af9 2022
22853e4a
KZ
2023 for (i = 0; i < partitions; pe++,i++) {
2024 p = pe->part_table;
2b6fc908 2025 if (!p->sys_ind || IS_EXTENDED (p->sys_ind)) {
5c36a0eb 2026 first[i] = 0xffffffff;
6dbe3af9 2027 last[i] = 0;
2b6fc908 2028 } else {
22853e4a 2029 first[i] = get_partition_start(pe);
5c36a0eb 2030 last[i] = first[i] + get_nr_sects(p) - 1;
6dbe3af9 2031 }
2b6fc908 2032 }
6dbe3af9
KZ
2033}
2034
22853e4a 2035static void
df1dddf9
KZ
2036check(int n, unsigned int h, unsigned int s, unsigned int c,
2037 unsigned int start) {
2038 unsigned int total, real_s, real_c;
6dbe3af9
KZ
2039
2040 real_s = sector(s) - 1;
2041 real_c = cylinder(s, c);
2042 total = (real_c * sectors + real_s) * heads + h;
6dbe3af9 2043 if (!total)
7eda085c 2044 fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
6dbe3af9
KZ
2045 if (h >= heads)
2046 fprintf(stderr,
7eda085c 2047 _("Partition %d: head %d greater than maximum %d\n"),
6dbe3af9
KZ
2048 n, h + 1, heads);
2049 if (real_s >= sectors)
7eda085c 2050 fprintf(stderr, _("Partition %d: sector %d greater than "
be97c5f3 2051 "maximum %llu\n"), n, s, sectors);
6dbe3af9 2052 if (real_c >= cylinders)
7eda085c
KZ
2053 fprintf(stderr, _("Partitions %d: cylinder %d greater than "
2054 "maximum %d\n"), n, real_c + 1, cylinders);
726f69e2 2055 if (cylinders <= 1024 && start != total)
6dbe3af9 2056 fprintf(stderr,
7eda085c
KZ
2057 _("Partition %d: previous sectors %d disagrees with "
2058 "total %d\n"), n, start, total);
6dbe3af9
KZ
2059}
2060
22853e4a
KZ
2061static void
2062verify(void) {
6dbe3af9 2063 int i, j;
85a994c4
KZ
2064 unsigned long long total = 1;
2065 unsigned long long n_sectors = (total_number_of_sectors / sector_factor);
be97c5f3 2066 unsigned long long first[partitions], last[partitions];
c07ebfa1 2067 struct partition *p;
6dbe3af9
KZ
2068
2069 if (warn_geometry())
2070 return;
2071
5c36a0eb 2072 if (sun_label) {
2b6fc908 2073 verify_sun();
5c36a0eb
KZ
2074 return;
2075 }
2076
2077 if (sgi_label) {
2078 verify_sgi(1);
2079 return;
2080 }
2b6fc908 2081
5c36a0eb 2082 fill_bounds(first, last);
22853e4a
KZ
2083 for (i = 0; i < partitions; i++) {
2084 struct pte *pe = &ptes[i];
2085
2086 p = pe->part_table;
2b6fc908 2087 if (p->sys_ind && !IS_EXTENDED (p->sys_ind)) {
6dbe3af9 2088 check_consistency(p, i);
22853e4a 2089 if (get_partition_start(pe) < first[i])
7eda085c
KZ
2090 printf(_("Warning: bad start-of-data in "
2091 "partition %d\n"), i + 1);
6dbe3af9
KZ
2092 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
2093 last[i]);
2094 total += last[i] + 1 - first[i];
2095 for (j = 0; j < i; j++)
fd6b7a7f
KZ
2096 if ((first[i] >= first[j] && first[i] <= last[j])
2097 || ((last[i] <= last[j] && last[i] >= first[j]))) {
7eda085c
KZ
2098 printf(_("Warning: partition %d overlaps "
2099 "partition %d.\n"), j + 1, i + 1);
6dbe3af9
KZ
2100 total += first[i] >= first[j] ?
2101 first[i] : first[j];
2102 total -= last[i] <= last[j] ?
2103 last[i] : last[j];
2104 }
2105 }
22853e4a 2106 }
6dbe3af9
KZ
2107
2108 if (extended_offset) {
22853e4a 2109 struct pte *pex = &ptes[ext_index];
be97c5f3 2110 unsigned long long e_last = get_start_sect(pex->part_table) +
22853e4a 2111 get_nr_sects(pex->part_table) - 1;
6dbe3af9 2112
22853e4a 2113 for (i = 4; i < partitions; i++) {
6dbe3af9 2114 total++;
22853e4a 2115 p = ptes[i].part_table;
6dbe3af9
KZ
2116 if (!p->sys_ind) {
2117 if (i != 4 || i + 1 < partitions)
7eda085c
KZ
2118 printf(_("Warning: partition %d "
2119 "is empty\n"), i + 1);
6dbe3af9
KZ
2120 }
2121 else if (first[i] < extended_offset ||
2122 last[i] > e_last)
7eda085c
KZ
2123 printf(_("Logical partition %d not entirely in "
2124 "partition %d\n"), i + 1, ext_index + 1);
6dbe3af9
KZ
2125 }
2126 }
2127
85a994c4
KZ
2128 if (total > n_sectors)
2129 printf(_("Total allocated sectors %llu greater than the maximum"
2130 " %llu\n"), total, n_sectors);
2131 else if (total < n_sectors)
2132 printf(_("%lld unallocated %d-byte sectors\n"),
2133 n_sectors - total, sector_size);
6dbe3af9
KZ
2134}
2135
22853e4a
KZ
2136static void
2137add_partition(int n, int sys) {
eb63b9b8 2138 char mesg[256]; /* 48 does not suffice in Japanese */
6dbe3af9 2139 int i, read = 0;
22853e4a
KZ
2140 struct partition *p = ptes[n].part_table;
2141 struct partition *q = ptes[ext_index].part_table;
df1dddf9 2142 long long llimit;
be97c5f3 2143 unsigned long long start, stop = 0, limit, temp,
6dbe3af9
KZ
2144 first[partitions], last[partitions];
2145
22853e4a 2146 if (p && p->sys_ind) {
7eda085c 2147 printf(_("Partition %d is already defined. Delete "
364cda48 2148 "it before re-adding it.\n"), n + 1);
6dbe3af9
KZ
2149 return;
2150 }
5c36a0eb 2151 fill_bounds(first, last);
6dbe3af9
KZ
2152 if (n < 4) {
2153 start = sector_offset;
df1dddf9
KZ
2154 if (display_in_cyl_units || !total_number_of_sectors)
2155 llimit = heads * sectors * cylinders - 1;
24f4bbff 2156 else
10e3d031 2157 llimit = (total_number_of_sectors / sector_factor) - 1;
df1dddf9
KZ
2158 limit = llimit;
2159 if (limit != llimit)
2160 limit = 0x7fffffff;
6dbe3af9
KZ
2161 if (extended_offset) {
2162 first[ext_index] = extended_offset;
2b6fc908
KZ
2163 last[ext_index] = get_start_sect(q) +
2164 get_nr_sects(q) - 1;
6dbe3af9 2165 }
2b6fc908 2166 } else {
6dbe3af9 2167 start = extended_offset + sector_offset;
2b6fc908 2168 limit = get_start_sect(q) + get_nr_sects(q) - 1;
6dbe3af9 2169 }
7eda085c 2170 if (display_in_cyl_units)
6dbe3af9 2171 for (i = 0; i < partitions; i++)
7eda085c 2172 first[i] = (cround(first[i]) - 1) * units_per_sector;
6dbe3af9 2173
c07ebfa1 2174 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
6dbe3af9
KZ
2175 do {
2176 temp = start;
2177 for (i = 0; i < partitions; i++) {
981b80b7 2178 unsigned long long lastplusoff;
2b6fc908 2179
22853e4a 2180 if (start == ptes[i].offset)
6dbe3af9 2181 start += sector_offset;
2b6fc908
KZ
2182 lastplusoff = last[i] + ((n<4) ? 0 : sector_offset);
2183 if (start >= first[i] && start <= lastplusoff)
2184 start = lastplusoff + 1;
6dbe3af9
KZ
2185 }
2186 if (start > limit)
2187 break;
7eda085c 2188 if (start >= temp+units_per_sector && read) {
be97c5f3 2189 printf(_("Sector %llu is already allocated\n"), temp);
2b6fc908 2190 temp = start;
6dbe3af9
KZ
2191 read = 0;
2192 }
2193 if (!read && start == temp) {
981b80b7 2194 unsigned long long i = start;
df1dddf9 2195
726f69e2 2196 start = read_int(cround(i), cround(i), cround(limit),
5c36a0eb 2197 0, mesg);
7eda085c
KZ
2198 if (display_in_cyl_units) {
2199 start = (start - 1) * units_per_sector;
6dbe3af9 2200 if (start < i) start = i;
2b6fc908 2201 }
6dbe3af9
KZ
2202 read = 1;
2203 }
2204 } while (start != temp || !read);
7eda085c 2205 if (n > 4) { /* NOT for fifth partition */
22853e4a
KZ
2206 struct pte *pe = &ptes[n];
2207
2208 pe->offset = start - sector_offset;
2209 if (pe->offset == extended_offset) { /* must be corrected */
364cda48
KZ
2210 pe->offset++;
2211 if (sector_offset == 1)
2212 start++;
7eda085c
KZ
2213 }
2214 }
6dbe3af9
KZ
2215
2216 for (i = 0; i < partitions; i++) {
22853e4a
KZ
2217 struct pte *pe = &ptes[i];
2218
2219 if (start < pe->offset && limit >= pe->offset)
2220 limit = pe->offset - 1;
6dbe3af9
KZ
2221 if (start < first[i] && limit >= first[i])
2222 limit = first[i] - 1;
2223 }
2224 if (start > limit) {
7eda085c 2225 printf(_("No free sectors available\n"));
22853e4a 2226 if (n > 4)
6dbe3af9 2227 partitions--;
6dbe3af9
KZ
2228 return;
2229 }
7eda085c
KZ
2230 if (cround(start) == cround(limit)) {
2231 stop = limit;
2232 } else {
c07ebfa1 2233 snprintf(mesg, sizeof(mesg),
b1edb510
KZ
2234 _("Last %1$s, +%2$s or +size{K,M,G}"),
2235 str_units(SINGULAR), str_units(PLURAL));
2236
726f69e2 2237 stop = read_int(cround(start), cround(limit), cround(limit),
5c36a0eb 2238 cround(start), mesg);
7eda085c
KZ
2239 if (display_in_cyl_units) {
2240 stop = stop * units_per_sector - 1;
6dbe3af9
KZ
2241 if (stop >limit)
2242 stop = limit;
2243 }
2244 }
2245
364cda48
KZ
2246 set_partition(n, 0, start, stop, sys);
2247 if (n > 4)
2248 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
6dbe3af9 2249
2b6fc908 2250 if (IS_EXTENDED (sys)) {
22853e4a
KZ
2251 struct pte *pe4 = &ptes[4];
2252 struct pte *pen = &ptes[n];
2253
6dbe3af9 2254 ext_index = n;
22853e4a
KZ
2255 pen->ext_pointer = p;
2256 pe4->offset = extended_offset = start;
2257 if (!(pe4->sectorbuffer = calloc(1, sector_size)))
6dbe3af9 2258 fatal(out_of_memory);
22853e4a
KZ
2259 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2260 pe4->ext_pointer = pe4->part_table + 1;
2261 pe4->changed = 1;
6dbe3af9 2262 partitions = 5;
6dbe3af9
KZ
2263 }
2264}
2265
22853e4a
KZ
2266static void
2267add_logical(void) {
2268 if (partitions > 5 || ptes[4].part_table->sys_ind) {
2269 struct pte *pe = &ptes[partitions];
2270
2271 if (!(pe->sectorbuffer = calloc(1, sector_size)))
6dbe3af9 2272 fatal(out_of_memory);
22853e4a
KZ
2273 pe->part_table = pt_offset(pe->sectorbuffer, 0);
2274 pe->ext_pointer = pe->part_table + 1;
2275 pe->offset = 0;
2276 pe->changed = 1;
6dbe3af9
KZ
2277 partitions++;
2278 }
2279 add_partition(partitions - 1, LINUX_NATIVE);
2280}
2281
22853e4a
KZ
2282static void
2283new_partition(void) {
6dbe3af9
KZ
2284 int i, free_primary = 0;
2285
2286 if (warn_geometry())
2287 return;
2b6fc908 2288
5c36a0eb 2289 if (sun_label) {
2b6fc908 2290 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
5c36a0eb
KZ
2291 return;
2292 }
2293
2294 if (sgi_label) {
2295 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
2296 return;
2297 }
2b6fc908 2298
e8f26419
KZ
2299 if (aix_label) {
2300 printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
2301 "\n\tIf you want to add DOS-type partitions, create"
2302 "\n\ta new empty DOS partition table first. (Use o.)"
2303 "\n\tWARNING: "
2304 "This will destroy the present disk contents.\n"));
2305 return;
2306 }
2307
e7fa917a
KZ
2308 if (mac_label) {
2309 printf(_("\tSorry - this fdisk cannot handle Mac disk labels."
2310 "\n\tIf you want to add DOS-type partitions, create"
2311 "\n\ta new empty DOS partition table first. (Use o.)"
2312 "\n\tWARNING: "
2313 "This will destroy the present disk contents.\n"));
2314 return;
2315 }
2316
95f1bdee
KZ
2317 for (i = 0; i < 4; i++)
2318 free_primary += !ptes[i].part_table->sys_ind;
2319
2320 if (!free_primary && partitions >= MAXIMUM_PARTS) {
7eda085c 2321 printf(_("The maximum number of partitions has been created\n"));
6dbe3af9
KZ
2322 return;
2323 }
2324
5c36a0eb 2325 if (!free_primary) {
6dbe3af9
KZ
2326 if (extended_offset)
2327 add_logical();
2328 else
7eda085c 2329 printf(_("You must delete some partition and add "
c07ebfa1 2330 "an extended partition first\n"));
d03dd608
KZ
2331 } else if (partitions >= MAXIMUM_PARTS) {
2332 printf(_("All logical partitions are in use\n"));
2333 printf(_("Adding a primary partition\n"));
2334 add_partition(get_partition(0, 4), LINUX_NATIVE);
5c36a0eb 2335 } else {
6dbe3af9 2336 char c, line[LINE_LENGTH];
c07ebfa1
KZ
2337 snprintf(line, sizeof(line),
2338 _("Command action\n %s\n p primary "
2339 "partition (1-4)\n"), extended_offset ?
2340 _("l logical (5 or over)") : _("e extended"));
2341 while (1) {
6dbe3af9 2342 if ((c = tolower(read_char(line))) == 'p') {
24f4bbff
KZ
2343 int i = get_nonexisting_partition(0, 4);
2344 if (i >= 0)
2345 add_partition(i, LINUX_NATIVE);
6dbe3af9
KZ
2346 return;
2347 }
2348 else if (c == 'l' && extended_offset) {
2349 add_logical();
2350 return;
2351 }
2352 else if (c == 'e' && !extended_offset) {
24f4bbff
KZ
2353 int i = get_nonexisting_partition(0, 4);
2354 if (i >= 0)
2355 add_partition(i, EXTENDED);
6dbe3af9
KZ
2356 return;
2357 }
726f69e2 2358 else
7eda085c 2359 printf(_("Invalid partition number "
c07ebfa1
KZ
2360 "for type `%c'\n"), c);
2361 }
6dbe3af9
KZ
2362 }
2363}
2364
22853e4a
KZ
2365static void
2366write_table(void) {
eb63b9b8 2367 int i;
6dbe3af9 2368
22853e4a
KZ
2369 if (dos_label) {
2370 for (i=0; i<3; i++)
63cccae4 2371 if (ptes[i].changed)
22853e4a
KZ
2372 ptes[3].changed = 1;
2373 for (i = 3; i < partitions; i++) {
2374 struct pte *pe = &ptes[i];
2375
2376 if (pe->changed) {
2377 write_part_table_flag(pe->sectorbuffer);
2378 write_sector(fd, pe->offset, pe->sectorbuffer);
2379 }
2b6fc908 2380 }
a2c5f3ca
KZ
2381 }
2382 else if (sgi_label) {
22853e4a
KZ
2383 /* no test on change? the printf below might be mistaken */
2384 sgi_write_table();
5c36a0eb 2385 } else if (sun_label) {
22853e4a
KZ
2386 int needw = 0;
2387
2388 for (i=0; i<8; i++)
63cccae4 2389 if (ptes[i].changed)
22853e4a
KZ
2390 needw = 1;
2391 if (needw)
2392 sun_write_table();
6dbe3af9
KZ
2393 }
2394
7eda085c 2395 printf(_("The partition table has been altered!\n\n"));
eb63b9b8
KZ
2396 reread_partition_table(1);
2397}
2398
2399void
2400reread_partition_table(int leave) {
eb63b9b8 2401 int i;
edd867fa 2402 struct stat statbuf;
6dbe3af9 2403
edd867fa
PT
2404 i = fstat(fd, &statbuf);
2405 if (i == 0 && S_ISBLK(statbuf.st_mode)) {
edd867fa
PT
2406 sync();
2407 sleep(2);
6b0054a2
ST
2408#ifdef BLKRRPART
2409 printf(_("Calling ioctl() to re-read partition table.\n"));
edd867fa 2410 i = ioctl(fd, BLKRRPART);
6b0054a2
ST
2411#else
2412 errno = ENOSYS;
2413 i = 1;
2414#endif
726f69e2
KZ
2415 }
2416
e8f26419 2417 if (i) {
c64061c9
VD
2418 printf(_("\nWARNING: Re-reading the partition table failed with error %d: %s.\n"
2419 "The kernel still uses the old table. The new table will be used at\n"
2420 "the next reboot or after you run partprobe(8) or kpartx(8)\n"),
edd867fa 2421 errno, strerror(errno));
e8f26419 2422 }
6dbe3af9 2423
e8f26419 2424 if (dos_changed)
2b6fc908 2425 printf(
7eda085c 2426 _("\nWARNING: If you have created or modified any DOS 6.x\n"
6dbe3af9 2427 "partitions, please see the fdisk manual page for additional\n"
7eda085c 2428 "information.\n"));
6dbe3af9 2429
eb63b9b8 2430 if (leave) {
a47f2e66
KZ
2431 if (fsync(fd) || close(fd)) {
2432 fprintf(stderr, _("\nError closing file\n"));
2433 exit(1);
2434 }
eb63b9b8
KZ
2435
2436 printf(_("Syncing disks.\n"));
2437 sync();
2438 sleep(4); /* for sync() */
2439 exit(!!i);
2440 }
6dbe3af9
KZ
2441}
2442
2443#define MAX_PER_LINE 16
22853e4a 2444static void
be97c5f3 2445print_buffer(unsigned char pbuffer[]) {
6dbe3af9
KZ
2446 int i,
2447 l;
2448
5c36a0eb 2449 for (i = 0, l = 0; i < sector_size; i++, l++) {
6dbe3af9
KZ
2450 if (l == 0)
2451 printf("0x%03X:", i);
be97c5f3 2452 printf(" %02X", pbuffer[i]);
6dbe3af9
KZ
2453 if (l == MAX_PER_LINE - 1) {
2454 printf("\n");
2455 l = -1;
2456 }
2457 }
2458 if (l > 0)
2459 printf("\n");
2460 printf("\n");
2461}
2462
22853e4a
KZ
2463static void
2464print_raw(void) {
6dbe3af9
KZ
2465 int i;
2466
7eda085c 2467 printf(_("Device: %s\n"), disk_device);
5c36a0eb 2468 if (sun_label || sgi_label)
22853e4a 2469 print_buffer(MBRbuffer);
2b6fc908 2470 else for (i = 3; i < partitions; i++)
22853e4a 2471 print_buffer(ptes[i].sectorbuffer);
6dbe3af9
KZ
2472}
2473
22853e4a
KZ
2474static void
2475move_begin(int i) {
2476 struct pte *pe = &ptes[i];
2477 struct partition *p = pe->part_table;
df1dddf9 2478 unsigned int new, first;
6dbe3af9
KZ
2479
2480 if (warn_geometry())
2481 return;
2b6fc908 2482 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED (p->sys_ind)) {
7eda085c 2483 printf(_("Partition %d has no data area\n"), i + 1);
6dbe3af9
KZ
2484 return;
2485 }
22853e4a
KZ
2486 first = get_partition_start(pe);
2487 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
2488 _("New beginning of data")) - pe->offset;
6dbe3af9 2489
2b6fc908
KZ
2490 if (new != get_nr_sects(p)) {
2491 first = get_nr_sects(p) + get_start_sect(p) - new;
2492 set_nr_sects(p, first);
2493 set_start_sect(p, new);
22853e4a 2494 pe->changed = 1;
6dbe3af9
KZ
2495 }
2496}
2497
22853e4a
KZ
2498static void
2499xselect(void) {
2500 char c;
2501
6dbe3af9
KZ
2502 while(1) {
2503 putchar('\n');
22853e4a
KZ
2504 c = tolower(read_char(_("Expert command (m for help): ")));
2505 switch (c) {
2b6fc908
KZ
2506 case 'a':
2507 if (sun_label)
2508 sun_set_alt_cyl();
2509 break;
2b6fc908 2510 case 'b':
22853e4a 2511 if (dos_label)
2b6fc908
KZ
2512 move_begin(get_partition(0, partitions));
2513 break;
2514 case 'c':
22853e4a 2515 user_cylinders = cylinders =
a2c5f3ca 2516 read_int(1, cylinders, 1048576, 0,
22853e4a 2517 _("Number of cylinders"));
2b6fc908
KZ
2518 if (sun_label)
2519 sun_set_ncyl(cylinders);
22853e4a
KZ
2520 if (dos_label)
2521 warn_cylinders();
2b6fc908
KZ
2522 break;
2523 case 'd':
2524 print_raw();
2525 break;
2526 case 'e':
5c36a0eb
KZ
2527 if (sgi_label)
2528 sgi_set_xcyl();
2529 else if (sun_label)
2b6fc908 2530 sun_set_xcyl();
a2c5f3ca
KZ
2531 else
2532 if (dos_label)
5c36a0eb
KZ
2533 x_list_table(1);
2534 break;
22853e4a 2535 case 'f':
63cccae4 2536 if (dos_label)
22853e4a
KZ
2537 fix_partition_table_order();
2538 break;
5c36a0eb
KZ
2539 case 'g':
2540 create_sgilabel();
2b6fc908
KZ
2541 break;
2542 case 'h':
22853e4a 2543 user_heads = heads = read_int(1, heads, 256, 0,
7eda085c 2544 _("Number of heads"));
2b6fc908
KZ
2545 update_units();
2546 break;
2b6fc908
KZ
2547 case 'i':
2548 if (sun_label)
2549 sun_set_ilfact();
bb6aacfe
PA
2550 if (dos_label)
2551 dos_set_mbr_id();
2b6fc908
KZ
2552 break;
2553 case 'o':
2554 if (sun_label)
2555 sun_set_rspeed();
2556 break;
2b6fc908 2557 case 'p':
2b6fc908
KZ
2558 if (sun_label)
2559 list_table(1);
2560 else
2b6fc908
KZ
2561 x_list_table(0);
2562 break;
2563 case 'q':
2564 close(fd);
7eda085c 2565 printf("\n");
2b6fc908
KZ
2566 exit(0);
2567 case 'r':
2568 return;
2569 case 's':
22853e4a 2570 user_sectors = sectors = read_int(1, sectors, 63, 0,
7eda085c 2571 _("Number of sectors"));
2b6fc908
KZ
2572 if (dos_compatible_flag) {
2573 sector_offset = sectors;
7eda085c 2574 fprintf(stderr, _("Warning: setting "
2b6fc908 2575 "sector offset for DOS "
7eda085c 2576 "compatiblity\n"));
2b6fc908
KZ
2577 }
2578 update_units();
2579 break;
2580 case 'v':
2581 verify();
2582 break;
2583 case 'w':
2584 write_table(); /* does not return */
2585 break;
2b6fc908
KZ
2586 case 'y':
2587 if (sun_label)
2588 sun_set_pcylcount();
2589 break;
2b6fc908
KZ
2590 default:
2591 xmenu();
6dbe3af9
KZ
2592 }
2593 }
2594}
2595
22853e4a 2596static int
e8f26419
KZ
2597is_ide_cdrom_or_tape(char *device) {
2598 FILE *procf;
2599 char buf[100];
2600 struct stat statbuf;
2601 int is_ide = 0;
2602
2b6fc908 2603 /* No device was given explicitly, and we are trying some
e8f26419 2604 likely things. But opening /dev/hdc may produce errors like
2b6fc908 2605 "hdc: tray open or drive not ready"
e8f26419
KZ
2606 if it happens to be a CD-ROM drive. It even happens that
2607 the process hangs on the attempt to read a music CD.
2608 So try to be careful. This only works since 2.1.73. */
2b6fc908 2609
e8f26419
KZ
2610 if (strncmp("/dev/hd", device, 7))
2611 return 0;
2b6fc908 2612
e8f26419
KZ
2613 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2614 procf = fopen(buf, "r");
2615 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2616 is_ide = (!strncmp(buf, "cdrom", 5) ||
2617 !strncmp(buf, "tape", 4));
2618 else
2619 /* Now when this proc file does not exist, skip the
2620 device when it is read-only. */
2621 if (stat(device, &statbuf) == 0)
2622 is_ide = ((statbuf.st_mode & 0222) == 0);
2b6fc908 2623
e8f26419
KZ
2624 if (procf)
2625 fclose(procf);
2626 return is_ide;
2b6fc908
KZ
2627}
2628
5dbff4c0
KZ
2629static void
2630gpt_warning(char *dev)
2631{
2632 if (dev && gpt_probe_signature_devname(dev))
2633 fprintf(stderr, _("\nWARNING: GPT (GUID Partition Table) detected on '%s'! "
2634 "The util fdisk doesn't support GPT. Use GNU Parted.\n\n"), dev);
2635}
2636
22853e4a
KZ
2637static void
2638try(char *device, int user_specified) {
e8f26419
KZ
2639 int gb;
2640
6dbe3af9 2641 disk_device = device;
c07ebfa1
KZ
2642 if (setjmp(listingbuf))
2643 return;
2644 if (!user_specified)
e8f26419 2645 if (is_ide_cdrom_or_tape(device))
c07ebfa1 2646 return;
5dbff4c0 2647 gpt_warning(device);
c07ebfa1 2648 if ((fd = open(disk_device, type_open)) >= 0) {
e8f26419 2649 gb = get_boot(try_only);
c129767e 2650 if (gb > 0) { /* I/O error */
e8f26419 2651 } else if (gb < 0) { /* no DOS signature */
c07ebfa1 2652 list_disk_geometry();
e7fa917a 2653 if (!aix_label && !mac_label && btrydev(device) < 0)
c07ebfa1
KZ
2654 fprintf(stderr,
2655 _("Disk %s doesn't contain a valid "
2656 "partition table\n"), device);
fd6b7a7f 2657 } else {
c07ebfa1 2658 list_table(0);
c07ebfa1 2659 }
c129767e 2660 close(fd);
c07ebfa1
KZ
2661 } else {
2662 /* Ignore other errors, since we try IDE
2663 and SCSI hard disks which may not be
2664 installed on the system. */
63cccae4 2665 if (errno == EACCES) {
c07ebfa1
KZ
2666 fprintf(stderr, _("Cannot open %s\n"), device);
2667 return;
fd6b7a7f
KZ
2668 }
2669 }
6dbe3af9
KZ
2670}
2671
c129767e
KZ
2672/*
2673 * for fdisk -l:
2674 * try all things in /proc/partitions that look like a full disk
2675 */
22853e4a
KZ
2676static void
2677tryprocpt(void) {
eb63b9b8 2678 FILE *procpt;
bb662090 2679 char line[128], ptname[128], devname[256];
981b80b7
KZ
2680 int ma, mi;
2681 unsigned long long sz;
eb63b9b8
KZ
2682
2683 procpt = fopen(PROC_PARTITIONS, "r");
2684 if (procpt == NULL) {
2685 fprintf(stderr, _("cannot open %s\n"), PROC_PARTITIONS);
2686 return;
2687 }
2688
2689 while (fgets(line, sizeof(line), procpt)) {
bb662090 2690 if (sscanf (line, " %d %d %llu %128[^\n ]",
eb63b9b8
KZ
2691 &ma, &mi, &sz, ptname) != 4)
2692 continue;
c07ebfa1 2693 snprintf(devname, sizeof(devname), "/dev/%s", ptname);
929f243f 2694 if (is_whole_disk(devname))
c129767e 2695 try(devname, 0);
eb63b9b8 2696 }
e8f26419 2697 fclose(procpt);
eb63b9b8
KZ
2698}
2699
22853e4a
KZ
2700static void
2701dummy(int *kk) {}
7eda085c 2702
22853e4a
KZ
2703static void
2704unknown_command(int c) {
2705 printf(_("%c: unknown command\n"), c);
7eda085c
KZ
2706}
2707
5dbff4c0
KZ
2708
2709
5c36a0eb 2710int
eb63b9b8 2711main(int argc, char **argv) {
7eda085c 2712 int j, c;
2b6fc908 2713 int optl = 0, opts = 0;
2b6fc908 2714
7eda085c
KZ
2715 setlocale(LC_ALL, "");
2716 bindtextdomain(PACKAGE, LOCALEDIR);
2717 textdomain(PACKAGE);
2b6fc908
KZ
2718
2719 /*
2720 * Calls:
2721 * fdisk -v
7eda085c 2722 * fdisk -l [-b sectorsize] [-u] device ...
2b6fc908 2723 * fdisk -s [partition] ...
7eda085c 2724 * fdisk [-b sectorsize] [-u] device
0e6f4a20
KZ
2725 *
2726 * Options -C, -H, -S set the geometry.
c64061c9 2727 *
2b6fc908 2728 */
0e6f4a20 2729 while ((c = getopt(argc, argv, "b:C:H:lsS:uvV")) != -1) {
2b6fc908
KZ
2730 switch (c) {
2731 case 'b':
0e6f4a20
KZ
2732 /* Ugly: this sector size is really per device,
2733 so cannot be combined with multiple disks,
2734 and te same goes for the C/H/S options.
2735 */
5c36a0eb
KZ
2736 sector_size = atoi(optarg);
2737 if (sector_size != 512 && sector_size != 1024 &&
8905beda 2738 sector_size != 2048 && sector_size != 4096)
5c36a0eb
KZ
2739 fatal(usage);
2740 sector_offset = 2;
7eda085c 2741 user_set_sector_size = 1;
2b6fc908 2742 break;
0e6f4a20
KZ
2743 case 'C':
2744 user_cylinders = atoi(optarg);
2745 break;
2746 case 'H':
2747 user_heads = atoi(optarg);
f01a2e3e 2748 if (user_heads <= 0 || user_heads > 256)
0e6f4a20
KZ
2749 user_heads = 0;
2750 break;
2751 case 'S':
2752 user_sectors = atoi(optarg);
2753 if (user_sectors <= 0 || user_sectors >= 64)
2754 user_sectors = 0;
2755 break;
2b6fc908
KZ
2756 case 'l':
2757 optl = 1;
2758 break;
2759 case 's':
2760 opts = 1;
2761 break;
2762 case 'u':
7eda085c 2763 display_in_cyl_units = 0;
2b6fc908 2764 break;
22853e4a 2765 case 'V':
2b6fc908 2766 case 'v':
baf39af1 2767 printf("fdisk (%s)\n", PACKAGE_STRING);
2b6fc908
KZ
2768 exit(0);
2769 default:
2770 fatal(usage);
2771 }
6dbe3af9 2772 }
2b6fc908 2773
7eda085c 2774#if 0
63cccae4
KZ
2775 printf(_("This kernel finds the sector size itself - "
2776 "-b option ignored\n"));
7eda085c
KZ
2777#else
2778 if (user_set_sector_size && argc-optind != 1)
2779 printf(_("Warning: the -b (set sector size) option should"
2780 " be used with one specified device\n"));
2781#endif
2782
b2f15782
KZ
2783 init_mbr_buffer();
2784
2b6fc908 2785 if (optl) {
2b6fc908
KZ
2786 nowarn = 1;
2787 type_open = O_RDONLY;
2788 if (argc > optind) {
2789 int k;
2790 /* avoid gcc warning:
2791 variable `k' might be clobbered by `longjmp' */
2792 dummy(&k);
eb63b9b8 2793 listing = 1;
c129767e 2794 for (k = optind; k < argc; k++)
2b6fc908
KZ
2795 try(argv[k], 1);
2796 } else {
7eda085c 2797 /* we no longer have default device names */
c129767e 2798 /* but we can use /proc/partitions instead */
eb63b9b8 2799 tryprocpt();
2b6fc908
KZ
2800 }
2801 exit(0);
2802 }
2803
2804 if (opts) {
2cccd0ff 2805 unsigned long long size;
7eda085c 2806
2b6fc908 2807 nowarn = 1;
2b6fc908
KZ
2808 type_open = O_RDONLY;
2809
2810 opts = argc - optind;
2811 if (opts <= 0)
2812 fatal(usage);
2813
2814 for (j = optind; j < argc; j++) {
7eda085c 2815 disk_device = argv[j];
2b6fc908
KZ
2816 if ((fd = open(disk_device, type_open)) < 0)
2817 fatal(unable_to_open);
810f986b 2818 if (blkdev_get_sectors(fd, &size) == -1)
7eda085c 2819 fatal(ioctl_error);
2b6fc908 2820 close(fd);
2b6fc908 2821 if (opts == 1)
2cccd0ff 2822 printf("%llu\n", size/2);
2b6fc908 2823 else
2cccd0ff 2824 printf("%s: %llu\n", argv[j], size/2);
6dbe3af9 2825 }
2b6fc908 2826 exit(0);
6dbe3af9 2827 }
6dbe3af9 2828
2b6fc908
KZ
2829 if (argc-optind == 1)
2830 disk_device = argv[optind];
2831 else if (argc-optind != 0)
2832 fatal(usage);
7eda085c
KZ
2833 else
2834 fatal(usage2);
2835
5dbff4c0 2836 gpt_warning(disk_device);
2b6fc908 2837 get_boot(fdisk);
6dbe3af9 2838
22853e4a 2839 if (osf_label) {
63cccae4
KZ
2840 /* OSF label, and no DOS label */
2841 printf(_("Detected an OSF/1 disklabel on %s, entering "
2842 "disklabel mode.\n"),
22853e4a
KZ
2843 disk_device);
2844 bselect();
63cccae4
KZ
2845 osf_label = 0;
2846 /* If we return we may want to make an empty DOS label? */
22853e4a 2847 }
63cccae4 2848
6dbe3af9
KZ
2849 while (1) {
2850 putchar('\n');
22853e4a
KZ
2851 c = tolower(read_char(_("Command (m for help): ")));
2852 switch (c) {
2b6fc908 2853 case 'a':
22853e4a
KZ
2854 if (dos_label)
2855 toggle_active(get_partition(1, partitions));
2856 else if (sun_label)
2b6fc908 2857 toggle_sunflags(get_partition(1, partitions),
899736f1 2858 SUN_FLAG_UNMNT);
22853e4a
KZ
2859 else if (sgi_label)
2860 sgi_set_bootpartition(
2861 get_partition(1, partitions));
2b6fc908 2862 else
22853e4a 2863 unknown_command(c);
2b6fc908
KZ
2864 break;
2865 case 'b':
5c36a0eb 2866 if (sgi_label) {
7eda085c 2867 printf(_("\nThe current boot file is: %s\n"),
5c36a0eb 2868 sgi_get_bootfile());
7eda085c
KZ
2869 if (read_chars(_("Please enter the name of the "
2870 "new boot file: ")) == '\n')
2871 printf(_("Boot file unchanged\n"));
5c36a0eb
KZ
2872 else
2873 sgi_set_bootfile(line_ptr);
2874 } else
2875 bselect();
2b6fc908
KZ
2876 break;
2877 case 'c':
22853e4a
KZ
2878 if (dos_label)
2879 toggle_dos_compatibility_flag();
2880 else if (sun_label)
2b6fc908 2881 toggle_sunflags(get_partition(1, partitions),
899736f1 2882 SUN_FLAG_RONLY);
22853e4a
KZ
2883 else if (sgi_label)
2884 sgi_set_swappartition(
5c36a0eb 2885 get_partition(1, partitions));
22853e4a
KZ
2886 else
2887 unknown_command(c);
2b6fc908
KZ
2888 break;
2889 case 'd':
df1dddf9
KZ
2890 /* If sgi_label then don't use get_existing_partition,
2891 let the user select a partition, since
2892 get_existing_partition() only works for Linux-like
2893 partition tables */
2894 if (!sgi_label) {
2895 j = get_existing_partition(1, partitions);
2896 } else {
2897 j = get_partition(1, partitions);
2898 }
24f4bbff
KZ
2899 if (j >= 0)
2900 delete_partition(j);
2b6fc908 2901 break;
5c36a0eb
KZ
2902 case 'i':
2903 if (sgi_label)
2904 create_sgiinfo();
2b6fc908 2905 else
22853e4a 2906 unknown_command(c);
5c36a0eb
KZ
2907 case 'l':
2908 list_types(get_sys_types());
2b6fc908 2909 break;
22853e4a
KZ
2910 case 'm':
2911 menu();
2912 break;
2b6fc908
KZ
2913 case 'n':
2914 new_partition();
2915 break;
2916 case 'o':
2917 create_doslabel();
2918 break;
2919 case 'p':
2920 list_table(0);
2921 break;
2922 case 'q':
2923 close(fd);
7eda085c 2924 printf("\n");
2b6fc908 2925 exit(0);
2b6fc908
KZ
2926 case 's':
2927 create_sunlabel();
2928 break;
2b6fc908
KZ
2929 case 't':
2930 change_sysid();
2931 break;
2932 case 'u':
2933 change_units();
2934 break;
2935 case 'v':
2936 verify();
2937 break;
2938 case 'w':
2939 write_table(); /* does not return */
2940 break;
2941 case 'x':
63cccae4 2942 if (sgi_label) {
5c36a0eb 2943 fprintf(stderr,
7eda085c
KZ
2944 _("\n\tSorry, no experts menu for SGI "
2945 "partition tables available.\n\n"));
5c36a0eb
KZ
2946 } else
2947 xselect();
2b6fc908 2948 break;
22853e4a
KZ
2949 default:
2950 unknown_command(c);
2951 menu();
6dbe3af9
KZ
2952 }
2953 }
5c36a0eb 2954 return 0;
6dbe3af9 2955}