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