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