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