1 /* part 1.57 - Partition table editor Author: Kees J. Bot 2 * 13 Mar 1992 3 * Needs about 22k heap+stack. 4 * 5 * Forked july 2005 into autopart (Ben Gras), a mode which gives the user 6 * an easier time. 7 * 8 */ 9 #define nil 0 10 #include <sys/types.h> 11 #include <stdio.h> 12 #include <termcap.h> 13 #include <errno.h> 14 #include <unistd.h> 15 #include <stddef.h> 16 #include <ctype.h> 17 #include <stdlib.h> 18 #include <string.h> 19 #include <signal.h> 20 #include <fcntl.h> 21 #include <time.h> 22 #include <dirent.h> 23 #include <limits.h> 24 #include <sys/stat.h> 25 #include <sys/wait.h> 26 #include <sys/ioctl.h> 27 #include <minix/config.h> 28 #include <minix/const.h> 29 #include <minix/partition.h> 30 #include <minix/com.h> 31 #include <machine/partition.h> 32 #include <termios.h> 33 #include <stdarg.h> 34 35 /* Declare prototype. */ 36 void printstep(int step, char *message); 37 38 /* True if a partition is an extended partition. */ 39 #define ext_part(s) ((s) == 0x05 || (s) == 0x0F) 40 41 /* Minix master bootstrap code. */ 42 char MASTERBOOT[] = "/usr/mdec/mbr"; 43 44 /* Template: 45 ----first---- --geom/last-- ------sectors----- 46 Device Cyl Head Sec Cyl Head Sec Base Size Kb 47 /dev/c0d0 977 5 17 48 /dev/c0d0:2 0 0 2 976 4 16 2 83043 41521 49 Num Sort Type 50 0* p0 81 MINIX 0 0 3 33 4 9 3 2880 1440 51 1 p1 81 MINIX 33 4 10 178 2 2 2883 12284 6142 52 2 p2 81 MINIX 178 2 3 976 4 16 15167 67878 33939 53 3 p3 00 None 0 0 0 0 0 -1 0 0 0 54 55 */ 56 #define MAXSIZE 999999999L 57 #define SECTOR_SIZE 512 58 #define DEV_FD0 0x200 /* Device number of /dev/fd0 */ 59 #define DEV_C0D0 0x300 /* Device number of /dev/c0d0 */ 60 61 int min_region_mb = 500; 62 63 #define MIN_REGION_SECTORS (1024*1024*min_region_mb/SECTOR_SIZE) 64 65 #define arraysize(a) (sizeof(a) / sizeof((a)[0])) 66 #define arraylimit(a) ((a) + arraysize(a)) 67 68 #define SORNOT(n) ((n) == 1 ? "" : "s") 69 70 /* screen colours */ 71 #define COL_RED 1 72 #define COL_GREEN 2 73 #define COL_ORANGE 3 74 #define COL_BLUE 4 75 #define COL_MAGENTA 5 76 #define COL_CYAN 6 77 78 #define SURE_SERIOUS 1 79 #define SURE_BACK 2 80 81 void col(int col) 82 { 83 if(!col) printf("\033[0m"); 84 else printf("\033[3%dm", col % 10); 85 } 86 87 void type2col(int type) 88 { 89 switch(type) { 90 /* minix */ 91 case 0x80: 92 case MINIX_PART: col(COL_GREEN); break; 93 94 /* dos/windows */ 95 case 0x0B: case 0x0C: case 0x0E: case 0x0F: case 0x42: 96 case 0x07: col(COL_CYAN); break; 97 98 /* linux */ 99 case 0x82: case 0x83: col(COL_ORANGE); break; 100 } 101 } 102 103 int open_ct_ok(int fd) 104 { 105 int c = -1; 106 if(ioctl(fd, DIOCOPENCT, &c) < 0) { 107 printf("Warning: couldn't verify opencount, continuing\n"); 108 return 1; 109 } 110 111 if(c == 1) return 1; 112 if(c < 1) { printf("Error: open count %d\n", c); } 113 114 return 0; 115 } 116 117 void report(const char *label) 118 { 119 fprintf(stderr, "part: %s: %s\n", label, strerror(errno)); 120 } 121 122 void fatal(const char *label) 123 { 124 report(label); 125 exit(1); 126 } 127 128 struct termios termios; 129 130 void restore_ttyflags(void) 131 /* Reset the tty flags to how we got 'em. */ 132 { 133 if (tcsetattr(0, TCSANOW, &termios) < 0) fatal(""); 134 } 135 136 void tty_raw(void) 137 /* Set the terminal to raw mode, no signals, no echoing. */ 138 { 139 struct termios rawterm; 140 141 rawterm= termios; 142 rawterm.c_lflag &= ~(ICANON|ISIG|ECHO); 143 rawterm.c_iflag &= ~(ICRNL); 144 if (tcsetattr(0, TCSANOW, &rawterm) < 0) fatal(""); 145 } 146 147 #define ctrl(c) ((c) == '?' ? '\177' : ((c) & '\37')) 148 149 char t_cd[16], t_cm[32], t_so[16], t_se[16], t_md[16], t_me[16]; 150 #define STATUSROW 10 151 152 int putchr(int c) 153 { 154 return putchar(c); 155 } 156 157 void putstr(char *s) 158 { 159 int c; 160 161 while ((c= *s++) != 0) putchr(c); 162 } 163 164 void set_cursor(int row, int col) 165 { 166 tputs(tgoto(t_cm, col, row), 1, putchr); 167 } 168 169 int statusrow= STATUSROW; 170 int stat_ktl= 1; 171 int need_help= 1; 172 173 void stat_start(int serious) 174 /* Prepare for printing on a fresh status line, possibly highlighted. */ 175 { 176 set_cursor(statusrow++, 0); 177 tputs(t_cd, 1, putchr); 178 if (serious) tputs(t_so, 1, putchr); 179 } 180 181 void stat_end(int ktl) 182 /* Closing bracket for stat_start. Sets "keystrokes to live" of message. */ 183 { 184 tputs(t_se, 1, putchr); 185 stat_ktl= ktl; 186 need_help= 1; 187 } 188 189 void stat_reset(void) 190 /* Reset the statusline pointer and clear old messages if expired. */ 191 { 192 if (stat_ktl > 0 && --stat_ktl == 0) { 193 statusrow= STATUSROW; 194 need_help= 1; 195 } 196 if (need_help && statusrow < (24-2)) { 197 if (statusrow > STATUSROW) stat_start(0); 198 stat_start(0); 199 putstr( 200 "Type '+' or '-' to change, 'r' to read, '?' for more help, '!' for advice"); 201 } 202 statusrow= STATUSROW; 203 need_help= 0; 204 } 205 206 void clear_screen(void) 207 { 208 set_cursor(0, 0); 209 tputs(t_cd, 1, putchr); 210 stat_ktl= 1; 211 stat_reset(); 212 } 213 214 void reset_tty(void) 215 /* Reset the tty to cooked mode. */ 216 { 217 restore_ttyflags(); 218 set_cursor(statusrow, 0); 219 tputs(t_cd, 1, putchr); 220 } 221 222 void *alloc(size_t n) 223 { 224 void *m; 225 226 if ((m= malloc(n)) == nil) { reset_tty(); fatal(""); } 227 228 return m; 229 } 230 231 typedef enum parttype { DUNNO, SUBPART, PRIMARY, FLOPPY } parttype_t; 232 233 typedef struct device { 234 struct device *next, *prev; /* Circular dequeue. */ 235 dev_t rdev; /* Device number (sorting only). */ 236 char *name; /* E.g. /dev/c0d0 */ 237 char *subname; /* E.g. /dev/c0d0:2 */ 238 parttype_t parttype; 239 int biosdrive; 240 } device_t; 241 242 typedef struct region { 243 /* A region is either an existing top-level partition 244 * entry (used_part is non-NULL) or free space (free_* 245 * contains data). 246 */ 247 struct part_entry used_part; 248 int is_used_part; 249 int tableno; 250 int free_sec_start, free_sec_last; 251 } region_t; 252 253 /* A disk has between 1 and 2*partitions+1 regions; 254 * the last case is free space before and after every partition. 255 */ 256 #define NR_REGIONS (2*NR_PARTITIONS+1) 257 region_t regions[NR_REGIONS]; 258 int nr_partitions = 0, nr_regions = 0, free_regions, used_regions; 259 int nordonly = 0; 260 261 device_t *firstdev= nil, *curdev; 262 263 #define MAX_DEVICES 100 264 static struct { 265 device_t *dev; 266 int nr_partitions, free_regions, used_regions, sectors, nr_regions; 267 int biosdrive; 268 region_t regions[NR_REGIONS]; 269 } devices[MAX_DEVICES]; 270 271 void newdevice(char *name, int scanning, int disk_only) 272 /* Add a device to the device list. If scanning is set then we are reading 273 * /dev, so insert the device in device number order and make /dev/c0d0 current. 274 */ 275 { 276 device_t *new, *nextdev, *prevdev; 277 struct stat st; 278 279 st.st_rdev= 0; 280 if (scanning) { 281 if (stat(name, &st) < 0 || !S_ISBLK(st.st_mode)) return; 282 283 switch (major(st.st_rdev)) { 284 case 3: 285 /* Disk controller */ 286 if (minor(st.st_rdev) >= 0x80 287 || minor(st.st_rdev) % 5 != 0) return; 288 break; 289 default: 290 return; 291 } 292 /* Interesting device found. */ 293 } else { 294 if(stat(name, &st) < 0) { perror(name); return; } 295 } 296 297 new= alloc(sizeof(*new)); 298 new->rdev= st.st_rdev; 299 new->name= alloc((strlen(name) + 1) * sizeof(new->name[0])); 300 strcpy(new->name, name); 301 new->subname= new->name; 302 new->parttype= DUNNO; 303 if (major(st.st_rdev) == major(DEV_FD0) && minor(st.st_rdev) < 112) { 304 new->parttype= FLOPPY; 305 } else 306 if (st.st_rdev >= DEV_C0D0 && minor(st.st_rdev) < 128 307 && minor(st.st_rdev) % 5 == 0) { 308 new->parttype= PRIMARY; 309 } 310 311 if (firstdev == nil) { 312 firstdev= new; 313 new->next= new->prev= new; 314 curdev= firstdev; 315 return; 316 } 317 nextdev= firstdev; 318 while (new->rdev >= nextdev->rdev 319 && (nextdev= nextdev->next) != firstdev) {} 320 prevdev= nextdev->prev; 321 new->next= nextdev; 322 nextdev->prev= new; 323 new->prev= prevdev; 324 prevdev->next= new; 325 326 if (new->rdev < firstdev->rdev) firstdev= new; 327 if (new->rdev == DEV_C0D0) curdev= new; 328 if (curdev->rdev != DEV_C0D0) curdev= firstdev; 329 } 330 331 void getdevices(void) 332 /* Get all block devices from /dev that look interesting. */ 333 { 334 DIR *d; 335 struct dirent *e; 336 char name[5 + NAME_MAX + 1]; 337 338 if ((d= opendir("/dev")) == nil) fatal("/dev"); 339 340 while ((e= readdir(d)) != nil) { 341 strcpy(name, "/dev/"); 342 strcpy(name + 5, e->d_name); 343 newdevice(name, 1, 1); 344 } 345 (void) closedir(d); 346 } 347 348 int dirty= 0; 349 unsigned char bootblock[SECTOR_SIZE]; 350 struct part_entry table[1 + NR_PARTITIONS]; 351 int existing[1 + NR_PARTITIONS]; 352 unsigned long offset= 0, extbase= 0, extsize; 353 int submerged= 0; 354 int sort_index[1 + NR_PARTITIONS], sort_order[1 + NR_PARTITIONS]; 355 unsigned cylinders= 1, heads= 1, sectors= 1, secpcyl= 1; 356 unsigned alt_cyls= 1, alt_heads= 1, alt_secs= 1; 357 int precise= 0; 358 int device= -1; 359 360 unsigned long sortbase(struct part_entry *pe) 361 { 362 return pe->sysind == NO_PART ? -1 : pe->lowsec; 363 } 364 365 void sort(void) 366 /* Let the sort_index array show the order partitions are sorted in. */ 367 { 368 int i, j; 369 370 for (i= 1; i <= NR_PARTITIONS; i++) sort_order[i]= i; 371 372 for (i= 1; i <= NR_PARTITIONS; i++) { 373 for (j= 1; j <= NR_PARTITIONS-1; j++) { 374 int sj= sort_order[j], sj1= sort_order[j+1]; 375 376 if (sortbase(&table[sj]) > sortbase(&table[sj1])) { 377 sort_order[j]= sj1; 378 sort_order[j+1]= sj; 379 } 380 } 381 } 382 for (i= 1; i <= NR_PARTITIONS; i++) sort_index[sort_order[i]]= i; 383 } 384 385 void dos2chs(unsigned char *dos, unsigned *chs) 386 /* Extract cylinder, head and sector from the three bytes DOS uses to address 387 * a sector. Note that bits 8 & 9 of the cylinder number come from bit 6 & 7 388 * of the sector byte. The sector number is rebased to count from 0. 389 */ 390 { 391 chs[0]= ((dos[1] & 0xC0) << 2) | dos[2]; 392 chs[1]= dos[0]; 393 chs[2]= (dos[1] & 0x3F) - 1; 394 } 395 396 void abs2dos(unsigned char *dos, unsigned long pos) 397 /* Translate a sector offset to three DOS bytes. */ 398 { 399 unsigned h, c, s; 400 401 c= pos / secpcyl; 402 h= (pos % secpcyl) / sectors; 403 s= pos % sectors + 1; 404 405 dos[0]= h; 406 dos[1]= s | ((c >> 2) & 0xC0); 407 dos[2]= c & 0xFF; 408 } 409 410 void recompute0(void) 411 /* Recompute the partition size for the device after a geometry change. */ 412 { 413 if (device < 0) { 414 cylinders= heads= sectors= 1; 415 memset(table, 0, sizeof(table)); 416 } else 417 if (!precise && offset == 0) { 418 table[0].lowsec= 0; 419 table[0].size= (unsigned long) cylinders * heads * sectors; 420 } 421 table[0].sysind= device < 0 ? NO_PART : MINIX_PART; 422 secpcyl= heads * sectors; 423 } 424 425 void guess_geometry(void) 426 /* With a bit of work one can deduce the disk geometry from the partition 427 * table. This may be necessary if the driver gets it wrong. (If partition 428 * tables didn't have C/H/S numbers we would not care at all...) 429 */ 430 { 431 int i, n; 432 struct part_entry *pe; 433 unsigned chs[3]; 434 unsigned long sec; 435 unsigned h, s; 436 unsigned char HS[256][8]; /* Bit map off all possible H/S */ 437 438 alt_cyls= alt_heads= alt_secs= 0; 439 440 /* Initially all possible H/S combinations are possible. HS[h][0] 441 * bit 0 is used to rule out a head value. 442 */ 443 for (h= 1; h <= 255; h++) { 444 for (s= 0; s < 8; s++) HS[h][s]= 0xFF; 445 } 446 447 for (i= 0; i < 2*NR_PARTITIONS; i++) { 448 pe= &(table+1)[i >> 1]; 449 if (pe->sysind == NO_PART) continue; 450 451 /* Get the end or start sector numbers (in that order). */ 452 if ((i & 1) == 0) { 453 dos2chs(&pe->last_head, chs); 454 sec= pe->lowsec + pe->size - 1; 455 } else { 456 dos2chs(&pe->start_head, chs); 457 sec= pe->lowsec; 458 } 459 460 if (chs[0] >= alt_cyls) alt_cyls= chs[0]+1; 461 462 /* Which H/S combinations can be ruled out? */ 463 for (h= 1; h <= 255; h++) { 464 if (HS[h][0] == 0) continue; 465 n = 0; 466 for (s= 1; s <= 63; s++) { 467 if ((chs[0] * h + chs[1]) * s + chs[2] != sec) { 468 HS[h][s/8] &= ~(1 << (s%8)); 469 } 470 if (HS[h][s/8] & (1 << (s%8))) n++; 471 } 472 if (n == 0) HS[h][0]= 0; 473 } 474 } 475 476 /* See if only one remains. */ 477 i= 0; 478 for (h= 1; h <= 255; h++) { 479 if (HS[h][0] == 0) continue; 480 for (s= 1; s <= 63; s++) { 481 if (HS[h][s/8] & (1 << (s%8))) { 482 i++; 483 alt_heads= h; 484 alt_secs= s; 485 } 486 } 487 } 488 489 /* Forget it if more than one choice... */ 490 if (i > 1) alt_cyls= alt_heads= alt_secs= 0; 491 } 492 493 void geometry(void) 494 /* Find out the geometry of the device by querying the driver, or by looking 495 * at the partition table. These numbers are crosschecked to make sure that 496 * the geometry is correct. Master bootstraps other than the Minix one use 497 * the CHS numbers in the partition table to load the bootstrap of the active 498 * partition. 499 */ 500 { 501 struct stat dst; 502 int err= 0; 503 struct part_geom geometry; 504 505 if (submerged) { 506 /* Geometry already known. */ 507 sort(); 508 return; 509 } 510 precise= 0; 511 cylinders= 0; 512 recompute0(); 513 if (device < 0) return; 514 515 /* Try to guess the geometry from the partition table. */ 516 guess_geometry(); 517 518 /* Try to get the geometry from the driver. */ 519 (void) fstat(device, &dst); 520 521 if (S_ISBLK(dst.st_mode) || S_ISCHR(dst.st_mode)) { 522 /* Try to get the drive's geometry from the driver. */ 523 524 if (ioctl(device, DIOCGETP, &geometry) < 0) 525 err= errno; 526 else { 527 table[0].lowsec= (unsigned long)(geometry.base / 528 SECTOR_SIZE); 529 table[0].size = (unsigned long)(geometry.size / 530 SECTOR_SIZE); 531 cylinders= geometry.cylinders; 532 heads= geometry.heads; 533 sectors= geometry.sectors; 534 precise= 1; 535 } 536 } else { 537 err= ENODEV; 538 } 539 540 if (err != 0) { 541 /* Getting the geometry from the driver failed, so use the 542 * alternate geometry. 543 */ 544 if (alt_heads == 0) { 545 alt_cyls= table[0].size / (64 * 32); 546 alt_heads= 64; 547 alt_secs= 32; 548 } 549 550 cylinders= alt_cyls; 551 heads= alt_heads; 552 sectors= alt_secs; 553 554 stat_start(1); 555 printf("Failure to get the geometry of %s: %s", curdev->name, 556 errno == ENOTTY ? "No driver support" : strerror(err)); 557 stat_end(5); 558 stat_start(0); 559 printf("The geometry has been guessed as %ux%ux%u", 560 cylinders, heads, sectors); 561 stat_end(5); 562 } else { 563 if (alt_heads == 0) { 564 alt_cyls= cylinders; 565 alt_heads= heads; 566 alt_secs= sectors; 567 } 568 569 if (heads != alt_heads || sectors != alt_secs) { 570 printf( 571 "The geometry obtained from the driver\n" 572 "does not match the geometry implied by the partition\n" 573 "table. Please use expert mode instead.\n"); 574 exit(1); 575 } 576 } 577 578 /* Show the base and size of the device instead of the whole drive. 579 * This makes sense for subpartitioning primary partitions. 580 */ 581 if (precise && ioctl(device, DIOCGETP, &geometry) >= 0) { 582 table[0].lowsec= (unsigned long)(geometry.base / SECTOR_SIZE); 583 table[0].size = (unsigned long)(geometry.size / SECTOR_SIZE); 584 } else { 585 precise= 0; 586 } 587 recompute0(); 588 sort(); 589 } 590 591 typedef struct indicators { /* Partition type to partition name. */ 592 unsigned char ind; 593 char name[10]; 594 } indicators_t; 595 596 indicators_t ind_table[]= { 597 { 0x00, "None" }, 598 { 0x01, "FAT-12" }, 599 { 0x02, "XENIX /" }, 600 { 0x03, "XENIX usr" }, 601 { 0x04, "FAT-16" }, 602 { 0x05, "EXTENDED" }, 603 { 0x06, "FAT-16" }, 604 { 0x07, "HPFS/NTFS" }, 605 { 0x08, "AIX" }, 606 { 0x09, "COHERENT" }, 607 { 0x0A, "OS/2" }, 608 { 0x0B, "FAT-32" }, 609 { 0x0C, "FAT?" }, 610 { 0x0E, "FAT?" }, 611 { 0x0F, "EXTENDED" }, 612 { 0x10, "OPUS" }, 613 { 0x40, "VENIX286" }, 614 { 0x42, "W2000 Dyn" }, 615 { 0x52, "MICROPORT" }, 616 { 0x63, "386/IX" }, 617 { 0x64, "NOVELL286" }, 618 { 0x65, "NOVELL386" }, 619 { 0x75, "PC/IX" }, 620 { 0x80, "MINIX-OLD" }, 621 { 0x81, "MINIX" }, 622 { 0x82, "LINUXswap" }, 623 { 0x83, "LINUX" }, 624 { 0x93, "AMOEBA" }, 625 { 0x94, "AMOEBAbad" }, 626 { 0xA5, "386BSD" }, 627 { 0xB7, "BSDI" }, 628 { 0xB8, "BSDI swap" }, 629 { 0xC7, "SYRINX" }, 630 { 0xDB, "CPM" }, 631 { 0xFF, "BADBLOCKS" }, 632 }; 633 634 char *typ2txt(int ind) 635 /* Translate a numeric partition indicator for human eyes. */ 636 { 637 indicators_t *pind; 638 639 for (pind= ind_table; pind < arraylimit(ind_table); pind++) { 640 if (pind->ind == ind) return pind->name; 641 } 642 return "unknown system"; 643 } 644 645 int round_sysind(int ind, int delta) 646 /* Find the next known partition type starting with ind in direction delta. */ 647 { 648 indicators_t *pind; 649 650 ind= (ind + delta) & 0xFF; 651 652 if (delta < 0) { 653 for (pind= arraylimit(ind_table)-1; pind->ind > ind; pind--) {} 654 } else { 655 for (pind= ind_table; pind->ind < ind; pind++) {} 656 } 657 return pind->ind; 658 } 659 660 /* Objects on the screen, either simple pieces of the text or the cylinder 661 * number of the start of partition three. 662 */ 663 typedef enum objtype { 664 O_INFO, O_TEXT, O_DEV, O_SUB, 665 O_TYPTXT, O_SORT, O_NUM, O_TYPHEX, 666 O_CYL, O_HEAD, O_SEC, 667 O_SCYL, O_SHEAD, O_SSEC, O_LCYL, O_LHEAD, O_LSEC, O_BASE, O_SIZE, O_KB 668 } objtype_t; 669 670 #define rjust(type) ((type) >= O_TYPHEX) 671 #define computed(type) ((type) >= O_TYPTXT) 672 673 typedef struct object { 674 struct object *next; 675 objtype_t type; /* Text field, cylinder number, etc. */ 676 char flags; /* Modifiable? */ 677 char row; 678 char col; 679 char len; 680 struct part_entry *entry; /* What does the object refer to? */ 681 char *text; 682 char value[20]; /* Value when printed. */ 683 } object_t; 684 685 #define OF_MOD 0x01 /* Object value is modifiable. */ 686 #define OF_ODD 0x02 /* It has a somewhat odd value. */ 687 #define OF_BAD 0x04 /* Its value is no good at all. */ 688 689 /* Events: (Keypress events are the value of the key pressed.) */ 690 #define E_ENTER (-1) /* Cursor moves onto object. */ 691 #define E_LEAVE (-2) /* Cursor leaves object. */ 692 #define E_WRITE (-3) /* Write, but not by typing 'w'. */ 693 694 /* The O_SIZE objects have a dual identity. */ 695 enum howend { SIZE, LAST } howend= SIZE; 696 697 object_t *world= nil; 698 object_t *curobj= nil; 699 700 object_t *newobject(objtype_t type, int flags, int row, int col, int len) 701 /* Make a new object given a type, flags, position and length on the screen. */ 702 { 703 object_t *new; 704 object_t **aop= &world; 705 706 new= alloc(sizeof(*new)); 707 708 new->type= type; 709 new->flags= flags; 710 new->row= row; 711 new->col= col; 712 new->len= len; 713 new->entry= nil; 714 new->text= ""; 715 new->value[0]= 0; 716 717 new->next= *aop; 718 *aop= new; 719 720 return new; 721 } 722 723 unsigned long entry2base(struct part_entry *pe) 724 /* Return the base sector of the partition if defined. */ 725 { 726 return pe->sysind == NO_PART ? 0 : pe->lowsec; 727 } 728 729 unsigned long entry2last(struct part_entry *pe) 730 { 731 return pe->sysind == NO_PART ? -1 : pe->lowsec + pe->size - 1; 732 } 733 734 unsigned long entry2size(struct part_entry *pe) 735 { 736 return pe->sysind == NO_PART ? 0 : pe->size; 737 } 738 739 int typing; /* Set if a digit has been typed to set a value. */ 740 int magic; /* Changes when using the magic key. */ 741 742 void event(int ev, object_t *op); 743 744 void m_redraw(int ev, object_t *op) 745 /* Redraw the screen. */ 746 { 747 object_t *op2; 748 749 if (ev != ctrl('L')) return; 750 751 clear_screen(); 752 for (op2= world; op2 != nil; op2= op2->next) op2->value[0]= 0; 753 } 754 755 void m_toggle(int ev, object_t *op) 756 /* Toggle between the driver and alternate geometry. */ 757 { 758 unsigned t; 759 760 if (ev != 'X') return; 761 if (alt_cyls == cylinders && alt_heads == heads && alt_secs == sectors) 762 return; 763 764 t= cylinders; cylinders= alt_cyls; alt_cyls= t; 765 t= heads; heads= alt_heads; alt_heads= t; 766 t= sectors; sectors= alt_secs; alt_secs= t; 767 dirty= 1; 768 recompute0(); 769 } 770 771 char size_last[]= "Size"; 772 773 void m_orientation(int ev, object_t *op) 774 { 775 if (ev != ' ') return; 776 777 switch (howend) { 778 case SIZE: 779 howend= LAST; 780 strcpy(size_last, "Last"); 781 break; 782 case LAST: 783 howend= SIZE; 784 strcpy(size_last, "Size"); 785 } 786 } 787 788 void m_move(int ev, object_t *op) 789 /* Move to the nearest modifiably object in the intended direction. Objects 790 * on the same row or column are really near. 791 */ 792 { 793 object_t *near, *op2; 794 unsigned dist, d2, dr, dc; 795 796 if (ev != 'h' && ev != 'j' && ev != 'k' && ev != 'l' && ev != 'H') 797 return; 798 799 if (device < 0) { 800 /* No device open? Then try to read first. */ 801 event('r', op); 802 if (device < 0) return; 803 } 804 805 near= op; 806 dist= -1; 807 808 for (op2= world; op2 != nil; op2= op2->next) { 809 if (op2 == op || !(op2->flags & OF_MOD)) continue; 810 811 dr= abs(op2->row - op->row); 812 dc= abs(op2->col - op->col); 813 814 d2= 25*dr*dr + dc*dc; 815 if (op2->row != op->row && op2->col != op->col) d2+= 1000; 816 817 switch (ev) { 818 case 'h': /* Left */ 819 if (op2->col >= op->col) d2= -1; 820 break; 821 case 'j': /* Down */ 822 if (op2->row <= op->row) d2= -1; 823 break; 824 case 'k': /* Up */ 825 if (op2->row >= op->row) d2= -1; 826 break; 827 case 'l': /* Right */ 828 if (op2->col <= op->col) d2= -1; 829 break; 830 case 'H': /* Home */ 831 if (op2->type == O_DEV) d2= 0; 832 } 833 if (d2 < dist) { near= op2; dist= d2; } 834 } 835 if (near != op) event(E_LEAVE, op); 836 event(E_ENTER, near); 837 } 838 839 void m_updown(int ev, object_t *op) 840 /* Move a partition table entry up or down. */ 841 { 842 int i, j; 843 struct part_entry tmp; 844 int tmpx; 845 846 if (ev != ctrl('K') && ev != ctrl('J')) return; 847 if (op->entry == nil) return; 848 849 i= op->entry - table; 850 if (ev == ctrl('K')) { 851 if (i <= 1) return; 852 j= i-1; 853 } else { 854 if (i >= NR_PARTITIONS) return; 855 j= i+1; 856 } 857 858 tmp= table[i]; table[i]= table[j]; table[j]= tmp; 859 tmpx= existing[i]; existing[i]= existing[j]; existing[j]= tmpx; 860 sort(); 861 dirty= 1; 862 event(ev == ctrl('K') ? 'k' : 'j', op); 863 } 864 865 void m_enter(int ev, object_t *op) 866 /* We've moved onto this object. */ 867 { 868 if (ev != E_ENTER && ev != ' ' && ev != '<' && ev != '>' && ev != 'X') 869 return; 870 curobj= op; 871 typing= 0; 872 magic= 0; 873 } 874 875 void m_leave(int ev, object_t *op) 876 /* About to leave this object. */ 877 { 878 if (ev != E_LEAVE) return; 879 } 880 881 int within(unsigned *var, unsigned low, unsigned value, unsigned high) 882 /* Only set *var to value if it looks reasonable. */ 883 { 884 if (low <= value && value <= high) { 885 *var= value; 886 return 1; 887 } else 888 return 0; 889 } 890 891 int lwithin(unsigned long *var, unsigned long low, unsigned long value, 892 unsigned long high) 893 { 894 if (low <= value && value <= high) { 895 *var= value; 896 return 1; 897 } else 898 return 0; 899 } 900 901 int nextdevice(object_t *op, int delta) 902 /* Select the next or previous device from the device list. */ 903 { 904 dev_t rdev; 905 906 if (offset != 0) return 0; 907 if (dirty) event(E_WRITE, op); 908 if (dirty) return 0; 909 910 if (device >= 0) { 911 (void) close(device); 912 device= -1; 913 } 914 recompute0(); 915 916 rdev= curdev->rdev; 917 if (delta < 0) { 918 do 919 curdev= curdev->prev; 920 while (delta < -1 && major(curdev->rdev) == major(rdev) 921 && curdev->rdev < rdev); 922 } else { 923 do 924 curdev= curdev->next; 925 while (delta > 1 && major(curdev->rdev) == major(rdev) 926 && curdev->rdev > rdev); 927 } 928 return 1; 929 } 930 931 void check_ind(struct part_entry *pe) 932 /* If there are no other partitions then make this new one active. */ 933 { 934 struct part_entry *pe2; 935 int i = 0; 936 937 for (pe2= table + 1; pe2 < table + 1 + NR_PARTITIONS; pe2++, i++) 938 if (pe2->sysind != NO_PART && (pe2->bootind & ACTIVE_FLAG)) 939 return; 940 941 pe->bootind= ACTIVE_FLAG; 942 dirty = 1; 943 } 944 945 int check_existing(struct part_entry *pe) 946 /* Check and if not ask if an existing partition may be modified. */ 947 { 948 static int expert= 0; 949 int c; 950 951 if (expert || pe == nil || !existing[pe - table]) return 1; 952 953 stat_start(1); 954 putstr("Do you wish to modify existing partitions? (y/n) "); 955 fflush(stdout); 956 while ((c= getchar()) != 'y' && c != 'n') {} 957 putchr(c); 958 stat_end(3); 959 return (expert= (c == 'y')); 960 } 961 962 void m_modify(int ev, object_t *op) 963 /* Increment, decrement, set, or toggle the value of an object, using 964 * arithmetic tricks the author doesn't understand either. 965 */ 966 { 967 object_t *op2; 968 struct part_entry *pe= op->entry; 969 int mul, delta; 970 unsigned level= 1; 971 unsigned long surplus; 972 int radix= op->type == O_TYPHEX ? 0x10 : 10; 973 unsigned long t; 974 975 if (device < 0 && op->type != O_DEV) return; 976 977 switch (ev) { 978 case '-': 979 mul= radix; delta= -1; typing= 0; 980 break; 981 case '+': 982 mul= radix; delta= 1; typing= 0; 983 break; 984 case '\b': 985 if (!typing) return; 986 mul= 1; delta= 0; 987 break; 988 case '\r': 989 typing= 0; 990 return; 991 default: 992 if ('0' <= ev && ev <= '9') 993 delta= ev - '0'; 994 else 995 if (radix == 0x10 && 'a' <= ev && ev <= 'f') 996 delta= ev - 'a' + 10; 997 else 998 if (radix == 0x10 && 'A' <= ev && ev <= 'F') 999 delta= ev - 'A' + 10; 1000 else 1001 return; 1002 1003 mul= typing ? radix*radix : 0; 1004 typing= 1; 1005 } 1006 magic= 0; 1007 1008 if (!check_existing(pe)) return; 1009 1010 switch (op->type) { 1011 case O_DEV: 1012 if (ev != '-' && ev != '+') return; 1013 if (!nextdevice(op, delta)) return; 1014 break; 1015 case O_CYL: 1016 if (!within(&cylinders, 1, 1017 cylinders * mul / radix + delta, 1024)) return; 1018 recompute0(); 1019 break; 1020 case O_HEAD: 1021 if (!within(&heads, 1, heads * mul / radix + delta, 255)) 1022 return; 1023 recompute0(); 1024 break; 1025 case O_SEC: 1026 if (!within(§ors, 1, sectors * mul / radix + delta, 63)) 1027 return; 1028 recompute0(); 1029 break; 1030 case O_NUM: 1031 if (ev != '-' && ev != '+') return; 1032 for (op2= world; op2 != nil; op2= op2->next) { 1033 if (op2->type == O_NUM && ev == '+') 1034 op2->entry->bootind= 0; 1035 } 1036 op->entry->bootind= ev == '+' ? ACTIVE_FLAG : 0; 1037 break; 1038 case O_TYPHEX: 1039 check_ind(pe); 1040 pe->sysind= pe->sysind * mul / radix + delta; 1041 break; 1042 case O_TYPTXT: 1043 if (ev != '-' && ev != '+') return; 1044 check_ind(pe); 1045 pe->sysind= round_sysind(pe->sysind, delta); 1046 break; 1047 case O_SCYL: 1048 level= heads; 1049 case O_SHEAD: 1050 level*= sectors; 1051 case O_SSEC: 1052 if (op->type != O_SCYL && ev != '-' && ev != '+') return; 1053 case O_BASE: 1054 if (pe->sysind == NO_PART) memset(pe, 0, sizeof(*pe)); 1055 t= pe->lowsec; 1056 surplus= t % level; 1057 if (!lwithin(&t, 0L, 1058 (t / level * mul / radix + delta) * level + surplus, 1059 MAXSIZE)) return; 1060 if (howend == LAST || op->type != O_BASE) 1061 pe->size-= t - pe->lowsec; 1062 pe->lowsec= t; 1063 check_ind(pe); 1064 if (pe->sysind == NO_PART) pe->sysind= MINIX_PART; 1065 break; 1066 case O_LCYL: 1067 level= heads; 1068 case O_LHEAD: 1069 level*= sectors; 1070 case O_LSEC: 1071 if (op->type != O_LCYL && ev != '-' && ev != '+') return; 1072 1073 if (pe->sysind == NO_PART) memset(pe, 0, sizeof(*pe)); 1074 t= pe->lowsec + pe->size - 1 + level; 1075 surplus= t % level - mul / radix * level; 1076 if (!lwithin(&t, 0L, 1077 (t / level * mul / radix + delta) * level + surplus, 1078 MAXSIZE)) return; 1079 pe->size= t - pe->lowsec + 1; 1080 check_ind(pe); 1081 if (pe->sysind == NO_PART) pe->sysind= MINIX_PART; 1082 break; 1083 case O_KB: 1084 level= 2; 1085 if (mul == 0) pe->size= 0; /* new value, no surplus */ 1086 case O_SIZE: 1087 if (pe->sysind == NO_PART) { 1088 if (op->type == O_KB || howend == SIZE) { 1089 /* First let loose magic to set the base. */ 1090 event('m', op); 1091 magic= 0; 1092 pe->size= 0; 1093 event(ev, op); 1094 return; 1095 } 1096 memset(pe, 0, sizeof(*pe)); 1097 } 1098 t= (op->type == O_KB || howend == SIZE) ? pe->size 1099 : pe->lowsec + pe->size - 1; 1100 surplus= t % level; 1101 if (!lwithin(&t, 0L, 1102 (t / level * mul / radix + delta) * level + surplus, 1103 MAXSIZE)) return; 1104 pe->size= (op->type == O_KB || howend == SIZE) ? t : 1105 t - pe->lowsec + 1; 1106 check_ind(pe); 1107 if (pe->sysind == NO_PART) pe->sysind= MINIX_PART; 1108 break; 1109 default: 1110 return; 1111 } 1112 1113 /* The order among the entries may have changed. */ 1114 sort(); 1115 dirty= 1; 1116 } 1117 1118 unsigned long spell[3 + 4 * (1+NR_PARTITIONS)]; 1119 int nspells; 1120 objtype_t touching; 1121 1122 void newspell(unsigned long charm) 1123 /* Add a new spell, descending order for the base, ascending for the size. */ 1124 { 1125 int i, j; 1126 1127 if (charm - table[0].lowsec > table[0].size) return; 1128 1129 for (i= 0; i < nspells; i++) { 1130 if (charm == spell[i]) return; /* duplicate */ 1131 1132 if (touching == O_BASE) { 1133 if (charm == table[0].lowsec + table[0].size) return; 1134 if ((spell[0] - charm) < (spell[0] - spell[i])) break; 1135 } else { 1136 if (charm == table[0].lowsec) return; 1137 if ((charm - spell[0]) < (spell[i] - spell[0])) break; 1138 } 1139 } 1140 for (j= ++nspells; j > i; j--) spell[j]= spell[j-1]; 1141 spell[i]= charm; 1142 } 1143 1144 void m_magic(int ev, object_t *op) 1145 /* Apply magic onto a base or size number. */ 1146 { 1147 struct part_entry *pe= op->entry, *pe2; 1148 int rough= (offset != 0 && extbase == 0); 1149 1150 if (ev != 'm' || device < 0) return; 1151 typing= 0; 1152 1153 if (!check_existing(pe)) return; 1154 1155 if (magic == 0) { 1156 /* See what magic we can let loose on this value. */ 1157 nspells= 1; 1158 1159 /* First spell, the current value. */ 1160 switch (op->type) { 1161 case O_SCYL: 1162 case O_SHEAD: /* Start of partition. */ 1163 case O_SSEC: 1164 case O_BASE: 1165 touching= O_BASE; 1166 spell[0]= pe->lowsec; 1167 break; 1168 case O_LCYL: 1169 case O_LHEAD: 1170 case O_LSEC: /* End of partition. */ 1171 case O_KB: 1172 case O_SIZE: 1173 touching= O_SIZE; 1174 spell[0]= pe->lowsec + pe->size; 1175 break; 1176 default: 1177 return; 1178 } 1179 if (pe->sysind == NO_PART) { 1180 memset(pe, 0, sizeof(*pe)); 1181 check_ind(pe); 1182 pe->sysind= MINIX_PART; 1183 spell[0]= 0; 1184 if (touching == O_SIZE) { 1185 /* First let loose magic on the base. */ 1186 object_t *op2; 1187 1188 for (op2= world; op2 != nil; op2= op2->next) { 1189 if (op2->row == op->row && 1190 op2->type == O_BASE) { 1191 event('m', op2); 1192 } 1193 } 1194 magic= 0; 1195 event('m', op); 1196 return; 1197 } 1198 } 1199 /* Avoid the first sector on the device. */ 1200 if (spell[0] == table[0].lowsec) newspell(spell[0] + 1); 1201 1202 /* Further interesting values are the the bases of other 1203 * partitions or their ends. 1204 */ 1205 for (pe2= table; pe2 < table + 1 + NR_PARTITIONS; pe2++) { 1206 if (pe2 == pe || pe2->sysind == NO_PART) continue; 1207 if (pe2->lowsec == table[0].lowsec) 1208 newspell(table[0].lowsec + 1); 1209 else 1210 newspell(pe2->lowsec); 1211 newspell(pe2->lowsec + pe2->size); 1212 if (touching == O_BASE && howend == SIZE) { 1213 newspell(pe2->lowsec - pe->size); 1214 newspell(pe2->lowsec + pe2->size - pe->size); 1215 } 1216 if (pe2->lowsec % sectors != 0) rough= 1; 1217 } 1218 /* Present values rounded up to the next cylinder unless 1219 * the table is already a mess. Use "start + 1 track" instead 1220 * of "start + 1 cylinder". Also add the end of the last 1221 * cylinder. 1222 */ 1223 if (!rough) { 1224 unsigned long n= spell[0]; 1225 if (n == table[0].lowsec) n++; 1226 n= (n + sectors - 1) / sectors * sectors; 1227 if (n != table[0].lowsec + sectors) 1228 n= (n + secpcyl - 1) / secpcyl * secpcyl; 1229 newspell(n); 1230 if (touching == O_SIZE) 1231 newspell(table[0].size / secpcyl * secpcyl); 1232 } 1233 } 1234 /* Magic has been applied, a spell needs to be chosen. */ 1235 1236 if (++magic == nspells) magic= 0; 1237 1238 if (touching == O_BASE) { 1239 if (howend == LAST) pe->size-= spell[magic] - pe->lowsec; 1240 pe->lowsec= spell[magic]; 1241 } else 1242 pe->size= spell[magic] - pe->lowsec; 1243 1244 /* The order among the entries may have changed. */ 1245 sort(); 1246 dirty= 1; 1247 } 1248 1249 typedef struct diving { 1250 struct diving *up; 1251 struct part_entry old0; 1252 char *oldsubname; 1253 parttype_t oldparttype; 1254 unsigned long oldoffset; 1255 unsigned long oldextbase; 1256 } diving_t; 1257 1258 diving_t *diving= nil; 1259 1260 void m_in(int ev, object_t *op) 1261 /* Go down into a primary or extended partition. */ 1262 { 1263 diving_t *newdiv; 1264 struct part_entry *pe= op->entry, ext; 1265 int n; 1266 1267 if (ev != '>' || device < 0 || pe == nil || pe == &table[0] 1268 || (!(pe->sysind == MINIX_PART && offset == 0) 1269 && !ext_part(pe->sysind)) 1270 || pe->size == 0) return; 1271 1272 ext= *pe; 1273 if (extbase != 0) ext.size= extbase + extsize - ext.lowsec; 1274 1275 if (dirty) event(E_WRITE, op); 1276 if (dirty) return; 1277 if (device >= 0) { close(device); device= -1; } 1278 1279 newdiv= alloc(sizeof(*newdiv)); 1280 newdiv->old0= table[0]; 1281 newdiv->oldsubname= curdev->subname; 1282 newdiv->oldparttype= curdev->parttype; 1283 newdiv->oldoffset= offset; 1284 newdiv->oldextbase= extbase; 1285 newdiv->up= diving; 1286 diving= newdiv; 1287 1288 table[0]= ext; 1289 1290 n= strlen(diving->oldsubname); 1291 curdev->subname= alloc((n + 3) * sizeof(curdev->subname[0])); 1292 strcpy(curdev->subname, diving->oldsubname); 1293 curdev->subname[n++]= ':'; 1294 curdev->subname[n++]= '0' + (pe - table - 1); 1295 curdev->subname[n]= 0; 1296 1297 curdev->parttype= curdev->parttype == PRIMARY ? SUBPART : DUNNO; 1298 offset= ext.lowsec; 1299 if (ext_part(ext.sysind) && extbase == 0) { 1300 extbase= ext.lowsec; 1301 extsize= ext.size; 1302 curdev->parttype= DUNNO; 1303 } 1304 1305 submerged= 1; 1306 event('r', op); 1307 } 1308 1309 void m_out(int ev, object_t *op) 1310 /* Go up from an extended or subpartition table to its enclosing. */ 1311 { 1312 diving_t *olddiv; 1313 1314 if (ev != '<' || diving == nil) return; 1315 1316 if (dirty) event(E_WRITE, op); 1317 if (dirty) return; 1318 if (device >= 0) { close(device); device= -1; } 1319 1320 olddiv= diving; 1321 diving= olddiv->up; 1322 1323 table[0]= olddiv->old0; 1324 1325 free(curdev->subname); 1326 curdev->subname= olddiv->oldsubname; 1327 1328 curdev->parttype= olddiv->oldparttype; 1329 offset= olddiv->oldoffset; 1330 extbase= olddiv->oldextbase; 1331 1332 free(olddiv); 1333 1334 event('r', op); 1335 if (diving == nil) submerged= 0; /* We surfaced. */ 1336 } 1337 1338 void installboot(unsigned char *bootblock, char *masterboot) 1339 /* Install code from a master bootstrap into a boot block. */ 1340 { 1341 FILE *mfp; 1342 unsigned char buf[SECTOR_SIZE]; 1343 int n; 1344 char *err; 1345 1346 if ((mfp= fopen(masterboot, "r")) == nil) { 1347 err= strerror(errno); 1348 goto m_err; 1349 } 1350 1351 n= fread(buf, sizeof(char), SECTOR_SIZE, mfp); 1352 if (ferror(mfp)) { 1353 err= strerror(errno); 1354 fclose(mfp); 1355 goto m_err; 1356 } 1357 else if (n < 256) { 1358 err= "Is probably not a boot sector, too small"; 1359 fclose(mfp); 1360 goto m_err; 1361 } 1362 else if (n < SECTOR_SIZE && n > PART_TABLE_OFF) { 1363 /* if only code, it cannot override partition table */ 1364 err= "Does not fit in a boot sector"; 1365 fclose(mfp); 1366 goto m_err; 1367 } 1368 else if (n == SECTOR_SIZE) { 1369 if (buf[510] != 0x55 || buf[511] != 0xaa) { 1370 err= "Is not a boot sector (bad magic)"; 1371 fclose(mfp); 1372 goto m_err; 1373 } 1374 n = PART_TABLE_OFF; 1375 } 1376 1377 if (n > PART_TABLE_OFF) { 1378 err= "Does not fit in a boot sector"; 1379 fclose(mfp); 1380 goto m_err; 1381 } 1382 1383 memcpy(bootblock, buf, n); 1384 fclose(mfp); 1385 1386 /* Bootstrap installed. */ 1387 return; 1388 1389 m_err: 1390 stat_start(1); 1391 printf("%s: %s", masterboot, err); 1392 stat_end(5); 1393 } 1394 1395 ssize_t boot_readwrite(int rw) 1396 /* Read (0) or write (1) the boot sector. */ 1397 { 1398 int r = 0; 1399 1400 if (lseek(device, offset * SECTOR_SIZE, SEEK_SET) < 0) 1401 return -1; 1402 1403 switch (rw) { 1404 case 0: r= read(device, bootblock, SECTOR_SIZE); break; 1405 case 1: r= write(device, bootblock, SECTOR_SIZE); break; 1406 } 1407 1408 return r; 1409 } 1410 1411 int cylinderalign(region_t *reg) 1412 { 1413 if(reg->is_used_part) { 1414 if(reg->used_part.lowsec != table[0].lowsec + sectors 1415 && (reg->used_part.lowsec % secpcyl)) { 1416 int extra; 1417 extra = secpcyl - (reg->used_part.lowsec % secpcyl); 1418 reg->used_part.lowsec += extra; 1419 reg->used_part.size -= extra; 1420 } 1421 if((reg->used_part.size+1) % secpcyl) { 1422 reg->used_part.size -= secpcyl - ((reg->used_part.size + 1) % secpcyl); 1423 } 1424 return reg->used_part.size > 0; 1425 } 1426 1427 if(reg->free_sec_start != table[0].lowsec + sectors && (reg->free_sec_start % secpcyl)) { 1428 /* Start is unaligned. Round up. */ 1429 reg->free_sec_start += secpcyl - (reg->free_sec_start % secpcyl); 1430 } 1431 if((reg->free_sec_last+1) % secpcyl) { 1432 /* End is unaligned. Round down. */ 1433 reg->free_sec_last -= (reg->free_sec_last+1) % secpcyl; 1434 } 1435 1436 /* Return nonzero if anything remains of the region after rounding. */ 1437 return reg->free_sec_last > reg->free_sec_start; 1438 } 1439 1440 void regionize(void) 1441 { 1442 int free_sec, i, si; 1443 1444 sort(); 1445 1446 free_sec = table[0].lowsec + sectors; 1447 1448 /* Create region data used in autopart mode. */ 1449 free_regions = used_regions = nr_regions = nr_partitions = 0; 1450 if(table[0].lowsec > table[sort_order[1]].lowsec && 1451 table[sort_order[1]].sysind != NO_PART) { 1452 printf("\nSanity check failed on %s - first partition starts before disk.\n" 1453 "Please use expert mode to correct it.\n", curdev->name); 1454 exit(1); 1455 } 1456 for(si = 1; si <= NR_PARTITIONS; si++) { 1457 i = sort_order[si]; 1458 if(i < 1 || i > NR_PARTITIONS) { 1459 printf("Sorry, something unexpected has happened (%d out of range).\n", i); 1460 exit(1); 1461 } 1462 1463 if(table[i].sysind == NO_PART) 1464 break; 1465 1466 /* Free space before this partition? */ 1467 if(table[i].lowsec > free_sec) { 1468 /* Free region before this partition. */ 1469 regions[nr_regions].free_sec_start = free_sec; 1470 regions[nr_regions].free_sec_last = table[i].lowsec-1; 1471 regions[nr_regions].is_used_part = 0; 1472 if(cylinderalign(®ions[nr_regions])) { 1473 nr_regions++; 1474 free_regions++; 1475 } 1476 } 1477 1478 /* Sanity check. */ 1479 if(si > 1) { 1480 if(table[i].lowsec < table[sort_order[si-1]].lowsec || 1481 table[i].lowsec < table[sort_order[si-1]].lowsec + table[sort_order[si-1]].size) { 1482 printf("\nSanity check failed on %s - partitions overlap.\n" 1483 "Please use expert mode to correct it.\n", curdev->name); 1484 exit(1); 1485 } 1486 } 1487 if(table[i].size > table[0].size) { 1488 printf("\nSanity check failed on %s - partition is larger than disk.\n" 1489 "Please use expert mode to correct it.\n", curdev->name); 1490 exit(1); 1491 } 1492 if(table[i].size < 1) { 1493 printf("\nSanity check failed on %s - zero-sized partition.\n" 1494 "Please use expert mode to correct it.\n", curdev->name); 1495 exit(1); 1496 } 1497 1498 /* Remember used region. */ 1499 memcpy(®ions[nr_regions].used_part, &table[i], sizeof(table[i])); 1500 free_sec = table[i].lowsec+table[i].size; 1501 regions[nr_regions].is_used_part = 1; 1502 regions[nr_regions].tableno = i; 1503 nr_partitions++; 1504 nr_regions++; 1505 used_regions++; 1506 } 1507 1508 /* Special case: space after partitions. */ 1509 if(free_sec < table[0].lowsec + table[0].size-1) { 1510 regions[nr_regions].free_sec_start = free_sec; 1511 regions[nr_regions].free_sec_last = table[0].lowsec + table[0].size-1; 1512 regions[nr_regions].is_used_part = 0; 1513 if(cylinderalign(®ions[nr_regions])) { 1514 nr_regions++; 1515 free_regions++; 1516 } 1517 } 1518 1519 } 1520 1521 void m_read(int ev, int *biosdrive) 1522 /* Read the partition table from the current device. */ 1523 { 1524 int i, mode, n, v; 1525 struct part_entry *pe; 1526 u32_t system_hz; 1527 1528 if (ev != 'r' || device >= 0) return; 1529 1530 /* Open() may cause kernel messages: */ 1531 stat_start(0); 1532 fflush(stdout); 1533 1534 if ((device= open(curdev->name, mode= O_RDWR, 0666)) < 0) { 1535 if (device >= 0) { close(device); device= -1; } 1536 return; 1537 } 1538 1539 system_hz = (u32_t) sysconf(_SC_CLK_TCK); 1540 v = 2*system_hz; 1541 ioctl(device, DIOCTIMEOUT, &v); 1542 1543 memset(bootblock, 0, sizeof(bootblock)); 1544 1545 n= boot_readwrite(0); 1546 1547 if (n <= 0) stat_start(1); 1548 if (n < 0) { 1549 close(device); 1550 device= -1; 1551 } else 1552 if (n < SECTOR_SIZE) { 1553 close(device); 1554 device= -1; 1555 return; 1556 } 1557 if (n <= 0) stat_end(5); 1558 1559 if (n < SECTOR_SIZE) n= SECTOR_SIZE; 1560 1561 if(biosdrive) (*biosdrive)++; 1562 1563 if(!open_ct_ok(device)) { 1564 printf("\n%s: device in use! skipping it.", curdev->subname); 1565 fflush(stdout); 1566 close(device); 1567 device= -1; 1568 return; 1569 } 1570 1571 memcpy(table+1, bootblock+PART_TABLE_OFF, 1572 NR_PARTITIONS * sizeof(table[1])); 1573 if (bootblock[510] != 0x55 || bootblock[511] != 0xAA) { 1574 /* Invalid boot block, install bootstrap, wipe partition table. 1575 */ 1576 memset(bootblock, 0, sizeof(bootblock)); 1577 installboot(bootblock, MASTERBOOT); 1578 memset(table+1, 0, NR_PARTITIONS * sizeof(table[1])); 1579 } 1580 1581 /* Fix an extended partition table up to something mere mortals can 1582 * understand. Record already defined partitions. 1583 */ 1584 for (i= 1; i <= NR_PARTITIONS; i++) { 1585 pe= &table[i]; 1586 if (extbase != 0 && pe->sysind != NO_PART) 1587 pe->lowsec+= ext_part(pe->sysind) ? extbase : offset; 1588 existing[i]= pe->sysind != NO_PART; 1589 } 1590 geometry(); 1591 dirty= 0; 1592 1593 /* Warn about grave dangers ahead. */ 1594 if (extbase != 0) { 1595 stat_start(1); 1596 printf("Warning: You are in an extended partition."); 1597 stat_end(5); 1598 } 1599 1600 regionize(); 1601 } 1602 1603 void m_write(int ev, object_t *op) 1604 /* Write the partition table back if modified. */ 1605 { 1606 struct part_entry new_table[NR_PARTITIONS], *pe; 1607 1608 if (ev != 'w' && ev != E_WRITE) return; 1609 if (device < 0) { dirty= 0; return; } 1610 if (!dirty) { 1611 if (ev == 'w') { 1612 stat_start(1); 1613 printf("%s is not changed, or has already been written", 1614 curdev->subname); 1615 stat_end(2); 1616 } 1617 return; 1618 } 1619 1620 if (extbase != 0) { 1621 /* Will this stop him? Probably not... */ 1622 stat_start(1); 1623 printf("You have changed an extended partition. Bad Idea."); 1624 stat_end(5); 1625 } 1626 1627 memcpy(new_table, table+1, NR_PARTITIONS * sizeof(table[1])); 1628 for (pe= new_table; pe < new_table + NR_PARTITIONS; pe++) { 1629 if (pe->sysind == NO_PART) { 1630 memset(pe, 0, sizeof(*pe)); 1631 } else { 1632 abs2dos(&pe->start_head, pe->lowsec); 1633 abs2dos(&pe->last_head, pe->lowsec + pe->size - 1); 1634 1635 /* Fear and loathing time: */ 1636 if (extbase != 0) 1637 pe->lowsec-= ext_part(pe->sysind) 1638 ? extbase : offset; 1639 } 1640 } 1641 memcpy(bootblock+PART_TABLE_OFF, new_table, sizeof(new_table)); 1642 bootblock[510]= 0x55; 1643 bootblock[511]= 0xAA; 1644 1645 if (boot_readwrite(1) < 0) { 1646 stat_start(1); 1647 printf("%s: %s", curdev->name, strerror(errno)); 1648 stat_end(5); 1649 return; 1650 } 1651 dirty= 0; 1652 } 1653 1654 void m_shell(int ev, object_t *op) 1655 /* Shell escape, to do calculations for instance. */ 1656 { 1657 int r, pid, status; 1658 void (*sigint)(int), (*sigquit)(int), (*sigterm)(int); 1659 1660 if (ev != 's') return; 1661 1662 reset_tty(); 1663 fflush(stdout); 1664 1665 switch (pid= fork()) { 1666 case -1: 1667 stat_start(1); 1668 printf("can't fork: %s\n", strerror(errno)); 1669 stat_end(3); 1670 break; 1671 case 0: 1672 if (device >= 0) (void) close(device); 1673 execl("/bin/sh", "sh", (char *) nil); 1674 r= errno; 1675 stat_start(1); 1676 printf("/bin/sh: %s\n", strerror(errno)); 1677 stat_end(3); 1678 exit(127); 1679 } 1680 sigint= signal(SIGINT, SIG_IGN); 1681 sigquit= signal(SIGQUIT, SIG_IGN); 1682 sigterm= signal(SIGTERM, SIG_IGN); 1683 while (pid >= 0 && (r= wait(&status)) >= 0 && r != pid) {} 1684 (void) signal(SIGINT, sigint); 1685 (void) signal(SIGQUIT, sigquit); 1686 (void) signal(SIGTERM, sigterm); 1687 tty_raw(); 1688 if (pid < 0) 1689 ; 1690 else 1691 if (WIFEXITED(status) && WEXITSTATUS(status) == 127) 1692 stat_start(0); /* Match the stat_start in the child. */ 1693 else 1694 event(ctrl('L'), op); 1695 } 1696 1697 int quitting= 0; 1698 1699 void m_quit(int ev, object_t *op) 1700 /* Write the partition table if modified and exit. */ 1701 { 1702 if (ev != 'q' && ev != 'x') return; 1703 1704 quitting= 1; 1705 1706 if (dirty) event(E_WRITE, op); 1707 if (dirty) quitting= 0; 1708 } 1709 1710 void m_help(int ev, object_t *op) 1711 /* For people without a clue; let's hope they can find the '?' key. */ 1712 { 1713 static struct help { 1714 char *keys; 1715 char *what; 1716 } help[]= { 1717 { "? !", "This help / more advice!" }, 1718 { "+ - (= _ PgUp PgDn)","Select/increment/decrement/make active" }, 1719 { "0-9 (a-f)", "Enter value" }, 1720 { "hjkl (arrow keys)", "Move around" }, 1721 { "CTRL-K CTRL-J", "Move entry up/down" }, 1722 { "CTRL-L", "Redraw screen" }, 1723 { ">", "Start a subpartition table" }, 1724 { "<", "Back to the primary partition table" }, 1725 { "m", "Cycle through magic values" }, 1726 { "spacebar", "Show \"Size\" or \"Last\"" }, 1727 { "r w", "Read/write partition table" }, 1728 { "p s q x", "Raw dump / Shell escape / Quit / Exit" }, 1729 { "y n DEL", "Answer \"yes\", \"no\", \"cancel\"" }, 1730 }; 1731 static char *advice[] = { 1732 "* Choose a disk with '+' and '-', then hit 'r'.", 1733 "* To change any value: Move to it and use '+', '-' or type the desired value.", 1734 "* To make a new partition: Move over to the Size or Kb field of an unused", 1735 " partition and type the size. Hit the 'm' key to pad the partition out to", 1736 " a cylinder boundary. Hit 'm' again to pad it out to the end of the disk.", 1737 " You can hit 'm' more than once on a base or size field to see several", 1738 " interesting values go by. Note: Other Operating Systems can be picky about", 1739 " partitions that are not padded to cylinder boundaries. Look for highlighted", 1740 " head or sector numbers.", 1741 "* To reuse a partition: Change the type to MINIX.", 1742 "* To delete a partition: Type a zero in the hex Type field.", 1743 "* To make a partition active: Type '+' in the Num field.", 1744 "* To study the list of keys: Type '?'.", 1745 }; 1746 1747 if (ev == '?') { 1748 struct help *hp; 1749 1750 for (hp= help; hp < arraylimit(help); hp++) { 1751 stat_start(0); 1752 printf("%-25s - %s", hp->keys, hp->what); 1753 stat_end(0); 1754 } 1755 stat_start(0); 1756 putstr("Things like "); 1757 putstr(t_so); putstr("this"); putstr(t_se); 1758 putstr(" must be checked, but "); 1759 putstr(t_md); putstr("this"); putstr(t_me); 1760 putstr(" is not really a problem"); 1761 stat_end(0); 1762 } else 1763 if (ev == '!') { 1764 char **ap; 1765 1766 for (ap= advice; ap < arraylimit(advice); ap++) { 1767 stat_start(0); 1768 putstr(*ap); 1769 stat_end(0); 1770 } 1771 } 1772 } 1773 1774 void event(int ev, object_t *op) 1775 /* Simply call all modifiers for an event, each one knows when to act. */ 1776 { 1777 m_help(ev, op); 1778 m_redraw(ev, op); 1779 m_toggle(ev, op); 1780 m_orientation(ev, op); 1781 m_move(ev, op); 1782 m_updown(ev, op); 1783 m_enter(ev, op); 1784 m_leave(ev, op); 1785 m_modify(ev, op); 1786 m_magic(ev, op); 1787 m_in(ev, op); 1788 m_out(ev, op); 1789 m_read(ev, NULL); 1790 m_write(ev, op); 1791 m_shell(ev, op); 1792 m_quit(ev, op); 1793 } 1794 1795 char * 1796 prettysizeprint(int kb) 1797 { 1798 int toosmall = 0; 1799 static char str[200]; 1800 char unit = 'k'; 1801 if(MIN_REGION_SECTORS > kb*2) 1802 toosmall = 1; 1803 if(kb >= 5*1024) { 1804 kb /= 1024; 1805 unit = 'M'; 1806 if(kb >= 5*1024) { 1807 kb /= 1024; 1808 unit = 'G'; 1809 } 1810 } 1811 sprintf(str, "%4d %cB%s", kb, unit, 1812 toosmall ? ", too small for MINIX 3" : ""); 1813 return str; 1814 } 1815 1816 void 1817 printregions(region_t *theregions, int indent, int p_nr_partitions, int p_free_regions, int p_nr_regions, int numbers) 1818 { 1819 int r, nofree = 0; 1820 region_t *reg; 1821 reg = theregions; 1822 1823 if((p_nr_partitions >= NR_PARTITIONS || !p_free_regions) && p_free_regions) 1824 nofree = 1; 1825 for(r = 0; r < p_nr_regions; r++, reg++) { 1826 unsigned long units; 1827 if(reg->is_used_part) { 1828 char *name; 1829 name = typ2txt(reg->used_part.sysind); 1830 printf("%*s", indent, ""); type2col(reg->used_part.sysind); 1831 if(numbers) printf("[%d] ", r); 1832 printf("In use by %-10s ", name); 1833 units = reg->used_part.size / 2; 1834 col(0); 1835 printf(" (%s)\n", prettysizeprint(units)); 1836 } else { 1837 printf("%*s", indent, ""); 1838 if(numbers) { 1839 if(!nofree) printf("[%d] ", r); 1840 else printf("[-] "); 1841 } 1842 printf("Free space "); 1843 units = ((reg->free_sec_last - reg->free_sec_start+1))/2; 1844 printf(" (%s)\n", prettysizeprint(units)); 1845 } 1846 } 1847 1848 if(numbers && p_nr_partitions >= NR_PARTITIONS && p_free_regions) { 1849 printf( 1850 "\nNote: there is free space on this disk, but you can't select it,\n" 1851 "because there isn't a free slot in the partition table to use it.\n" 1852 "You can reclaim the free space by deleting an adjacent region.\n"); 1853 } 1854 1855 return; 1856 } 1857 1858 #define IS_YES 3 1859 #define IS_NO 4 1860 #define IS_OTHER 5 1861 int 1862 is_sure(char *fmt, ...) 1863 { 1864 char yesno[10]; 1865 va_list ap; 1866 va_start (ap, fmt); 1867 vprintf(fmt, ap); 1868 va_end(ap); 1869 printf(" Please enter 'yes' or 'no': "); 1870 fflush(stdout); 1871 if(!fgets(yesno, sizeof(yesno)-1, stdin)) exit(1); 1872 1873 if (strcmp(yesno, "yes\n") == 0) return(IS_YES); 1874 if (strcmp(yesno, "no\n") == 0) return(IS_NO); 1875 return IS_OTHER; 1876 } 1877 1878 void warn(char *message) 1879 { 1880 printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b ! %s\n",message); 1881 } 1882 1883 int 1884 may_kill_region(void) 1885 { 1886 int confirmation; 1887 char line[100]; 1888 int r, i; 1889 1890 if(used_regions < 1) return 1; 1891 1892 printf("\n -- Delete in-use region? --\n\n"); 1893 1894 printregions(regions, 3, nr_partitions, free_regions, nr_regions, 1); 1895 printf("\nEnter the region number to delete or ENTER to continue: "); 1896 fflush(NULL); 1897 fgets(line, sizeof(line)-2, stdin); 1898 if(!isdigit(line[0])) 1899 return 1; 1900 1901 r=atoi(line); 1902 if(r < 0 || r >= nr_regions) { 1903 printf("This choice is out of range.\n"); 1904 return 0; 1905 } 1906 1907 if(!regions[r].is_used_part) { 1908 printf("This region is not in use.\n"); 1909 return 0; 1910 } 1911 1912 i = regions[r].tableno; 1913 1914 printf("\nPlease confirm that you want to delete region %d, losing all data it", r); 1915 printf("\ncontains. You're disk is not actually updated right away, but still."); 1916 printf("\n\n"); 1917 1918 do { 1919 confirmation = is_sure("Are you sure you want to continue?"); 1920 if (confirmation == IS_NO) return 0; 1921 } while (confirmation != IS_YES); 1922 1923 table[i].sysind = NO_PART; 1924 dirty = 1; 1925 regionize(); 1926 1927 /* User may go again. */ 1928 return 0; 1929 } 1930 1931 1932 region_t * 1933 select_region(void) 1934 { 1935 int rn, done = 0; 1936 static char line[100]; 1937 int nofree = 0; 1938 1939 printstep(2, "Select a disk region"); 1940 1941 if(nr_regions < 1) { 1942 printf("\nNo regions found - maybe the drive is too small.\n" 1943 "Please try expert mode.\n"); 1944 exit(1); 1945 } 1946 1947 if(nr_partitions >= NR_PARTITIONS || !free_regions) { 1948 if(free_regions) { 1949 nofree = 1; 1950 } 1951 } 1952 1953 1954 printf("\nPlease select the region that you want to use for the MINIX 3 setup."); 1955 printf("\nIf you select an in-use region it will be overwritten by MINIX. The"); 1956 printf("\nfollowing region%s were found on the selected disk:\n\n", 1957 SORNOT(nr_regions)); 1958 printregions(regions, 3, nr_partitions, free_regions, nr_regions, 1); 1959 1960 1961 printf("\n"); 1962 do { 1963 printf("Enter the region number to use or type 'delete': "); 1964 if(nr_regions == 1) printf(" [0] "); 1965 fflush(NULL); 1966 1967 if(!fgets(line, sizeof(line)-2, stdin)) 1968 exit(1); 1969 1970 if (nr_regions == 1 && line[0] == '\n') { 1971 rn = 0; 1972 done = 1; 1973 } 1974 else { 1975 if(strcmp(line,"delete\n") == 0) { 1976 may_kill_region(); 1977 return NULL; 1978 } 1979 1980 if(sscanf(line, "%d", &rn) != 1) { 1981 warn("invalid choice"); 1982 continue; 1983 } 1984 1985 if(rn < 0 || rn >= nr_regions) { 1986 warn("out of range"); 1987 continue; 1988 } 1989 1990 if(nofree && !regions[rn].is_used_part) { 1991 warn("not available"); 1992 continue; 1993 } 1994 1995 done = 1; 1996 } 1997 } while(! done); 1998 1999 return(®ions[rn]); 2000 } 2001 2002 void printstep(int step, char *str) 2003 { 2004 int n; 2005 n = printf("\n --- Substep 3.%d: %s ---", step, str); 2006 while(n++ < 73) printf("-"); 2007 printf("\n"); 2008 } 2009 2010 device_t * 2011 select_disk(void) 2012 { 2013 int done = 0; 2014 int i, choice, drives; 2015 static char line[500]; 2016 int biosdrive = 0; 2017 2018 printstep(1, "Select a disk to install MINIX 3"); 2019 printf("\nProbing for disks. This may take a short while."); 2020 2021 i = 0; 2022 curdev=firstdev; 2023 2024 for(; i < MAX_DEVICES;) { 2025 printf("."); 2026 fflush(stdout); 2027 m_read('r', &biosdrive); 2028 if(device >= 0) { 2029 devices[i].dev = curdev; 2030 devices[i].free_regions = free_regions; 2031 devices[i].nr_regions = nr_regions; 2032 devices[i].nr_partitions = nr_partitions; 2033 devices[i].used_regions = used_regions; 2034 devices[i].sectors = table[0].size; 2035 curdev->biosdrive = biosdrive-1; 2036 memcpy(devices[i].regions, regions, sizeof(regions)); 2037 i++; 2038 } 2039 2040 nextdevice(NULL, 1); 2041 if(curdev == firstdev) 2042 break; 2043 } 2044 2045 drives = i; 2046 2047 if(drives < 1) { 2048 printf("\nFound no drives - can't partition.\n"); 2049 exit(1); 2050 } 2051 2052 printf(" Probing done.\n"); 2053 printf("The following disk%s %s found on your system:\n\n", SORNOT(drives), 2054 drives == 1 ? "was" : "were"); 2055 2056 for(i = 0; i < drives; i++) { 2057 printf(" "); 2058 printf("Disk [%d]: ", i); 2059 printf("%s, ", devices[i].dev->name); 2060 printf("%s\n", prettysizeprint(devices[i].sectors/2)); 2061 printregions(devices[i].regions, 8, 2062 devices[i].nr_partitions, 2063 devices[i].free_regions, 2064 devices[i].nr_regions, 0); 2065 } 2066 2067 printf("\n"); 2068 do { 2069 printf("Enter the disk number to use: "); 2070 if (drives == 1) printf("[0] "); 2071 fflush(NULL); 2072 if(!fgets(line, sizeof(line)-2, stdin)) 2073 exit(1); 2074 if (line[0] == '\n' && drives == 1) { 2075 choice = 0; 2076 done = 1; 2077 } else { 2078 if(sscanf(line, "%d", &choice) != 1) { 2079 warn("choose a disk"); 2080 continue; 2081 } 2082 if(choice < 0 || choice >= i) { 2083 warn("out of range"); 2084 continue; 2085 } 2086 done = 1; 2087 } 2088 } while(! done); 2089 return devices[choice].dev; 2090 } 2091 2092 int 2093 scribble_region(region_t *reg, struct part_entry **pe, int *made_new) 2094 { 2095 int ex, changed = 0, i; 2096 struct part_entry *newpart; 2097 if(!reg->is_used_part) { 2098 ex = reg->free_sec_last - reg->free_sec_start + 1; 2099 if(made_new) *made_new = 1; 2100 } else if(made_new) *made_new = 0; 2101 if(!reg->is_used_part) { 2102 for(i = 1; i <= NR_PARTITIONS; i++) 2103 if(table[i].sysind == NO_PART) 2104 break; 2105 if(i > NR_PARTITIONS) { 2106 /* Bug, should've been caught earlier. */ 2107 printf("Couldn't find a free slot. Please try expert mode.\n"); 2108 exit(1); 2109 } 2110 newpart = &table[i]; 2111 newpart->lowsec = reg->free_sec_start; 2112 newpart->size = reg->free_sec_last - reg->free_sec_start + 1; 2113 changed = 1; 2114 newpart->sysind = MINIX_PART; 2115 } else { 2116 newpart = ®->used_part; 2117 } 2118 *pe = newpart; 2119 changed = 1; 2120 dirty = 1; 2121 return changed; 2122 } 2123 2124 int 2125 sanitycheck_failed(char *dev, struct part_entry *pe) 2126 { 2127 struct part_geom part; 2128 int fd; 2129 unsigned long it_lowsec, it_secsize; 2130 2131 if((fd = open(dev, O_RDONLY)) < 0) { 2132 perror(dev); 2133 return 1; 2134 } 2135 2136 if (ioctl(fd, DIOCGETP, &part) < 0) { 2137 fprintf(stderr, "DIOCGETP failed\n"); 2138 perror(dev); 2139 return 1; 2140 } 2141 2142 if(!open_ct_ok(fd)) { 2143 printf("\nAutopart error: the disk is in use. This means that although a\n" 2144 "new table has been written, it won't be in use by the system\n" 2145 "until it's no longer in use (or a reboot is done). Just in case,\n" 2146 "I'm not going to continue. Please un-use the disk (or reboot) and try\n" 2147 "again.\n\n"); 2148 return 1; 2149 } 2150 2151 close(fd); 2152 2153 it_lowsec = (unsigned long)(part.base / SECTOR_SIZE); 2154 it_secsize = (unsigned long)(part.size / SECTOR_SIZE); 2155 2156 if(it_lowsec != pe->lowsec || it_secsize != pe->size) { 2157 fprintf(stderr, "\nReturned and set numbers don't match up!\n"); 2158 fprintf(stderr, "This can happen if the disk is still opened.\n"); 2159 return 1; 2160 } 2161 2162 return 0; 2163 } 2164 2165 int 2166 do_autopart(int resultfd) 2167 { 2168 int confirmation; 2169 region_t *r; 2170 struct part_entry *pe; 2171 struct part_entry orig_table[1 + NR_PARTITIONS]; 2172 int region, newp; 2173 2174 nordonly = 1; 2175 2176 do { 2177 curdev = select_disk(); 2178 } while(!curdev); 2179 2180 if(device >= 0) { 2181 close(device); 2182 device = -1; 2183 } 2184 recompute0(); 2185 2186 m_read('r', NULL); 2187 2188 memcpy(orig_table, table, sizeof(table)); 2189 2190 do { 2191 /* Show regions. */ 2192 r = select_region(); 2193 } while(!r); /* Back to step 2. */ 2194 2195 /* Write things. */ 2196 if(scribble_region(r, &pe, &newp)) { 2197 char *name; 2198 int i, found = -1; 2199 char partbuf[100], devname[100]; 2200 struct part_entry *tpe = NULL; 2201 2202 printstep(3, "Confirm your choices"); 2203 2204 region = (int)(r-regions); 2205 /* disk = (int) (curdev-devices); */ 2206 2207 printf("\nThis is the point of no return. You have selected to install MINIX 3\n"); 2208 printf("into region %d of disk %s. Please confirm that you want\n", 2209 region, curdev->name); 2210 printf("to use this selection to install MINIX 3.\n\n"); 2211 2212 do { 2213 confirmation = is_sure("Are you sure you want to continue?"); 2214 if (confirmation == IS_NO) return 1; 2215 } while (confirmation != IS_YES); 2216 2217 /* Retrieve partition number in sorted order that we 2218 * have scribbled in. 2219 */ 2220 sort(); 2221 for(i = 1; i <= NR_PARTITIONS; i++) { 2222 int si; 2223 si = sort_order[i]; 2224 if(si < 1 || si > NR_PARTITIONS) { 2225 fprintf(stderr, "Autopart internal error (out of range) (nothing written).\n"); 2226 exit(1); 2227 } 2228 if(table[si].lowsec == pe->lowsec) { 2229 if(found > 0) { 2230 fprintf(stderr, "Autopart internal error (part found twice) (nothing written).\n"); 2231 exit(1); 2232 } 2233 check_ind(&table[si]); 2234 table[si].sysind = MINIX_PART; 2235 found = i; 2236 tpe = &table[si]; 2237 } 2238 } 2239 if(found < 1) { 2240 fprintf(stderr, "Autopart internal error (part not found) (nothing written).\n"); 2241 exit(1); 2242 } 2243 m_write('w', NULL); 2244 if(dirty) { 2245 fprintf(stderr, "Autopart internal error (couldn't update disk).\n"); 2246 exit(1); 2247 } 2248 name=strrchr(curdev->name, '/'); 2249 if(!name) name = curdev->name; 2250 else name++; 2251 2252 sprintf(partbuf, "%sp%d d%dp%d\n", name, found-1, 2253 curdev->biosdrive, found-1); 2254 sprintf(devname, "/dev/%sp%d", name, found-1); 2255 if(resultfd >= 0 && write(resultfd, partbuf, strlen(partbuf)) < strlen(partbuf)) { 2256 fprintf(stderr, "Autopart internal error (couldn't write result).\n"); 2257 exit(1); 2258 } 2259 if(device >= 0) { 2260 close(device); 2261 device = -1; 2262 } 2263 2264 #if 0 2265 m_dump(orig_table); 2266 printf("\n"); 2267 m_dump(table); 2268 #endif 2269 2270 if(sanitycheck_failed(devname, tpe)) { 2271 fprintf(stderr, "Autopart internal error (disk sanity check failed).\n"); 2272 exit(1); 2273 } 2274 2275 if(newp) { 2276 int fd; 2277 if((fd=open(devname, O_WRONLY)) < 0) { 2278 perror(devname); 2279 } else { 2280 /* Clear any subpartitioning. */ 2281 static unsigned char sub[2048]; 2282 sub[510] = 0x55; 2283 sub[511] = 0xAA; 2284 write(fd, sub, sizeof(sub)); 2285 close(fd); 2286 } 2287 } 2288 return 0; 2289 } 2290 2291 return 1; 2292 } 2293 2294 int main(int argc, char **argv) 2295 { 2296 int c; 2297 int i, key; 2298 int resultfd = -1; 2299 2300 /* autopart uses getopt() */ 2301 while((c = getopt(argc, argv, "m:f:")) != EOF) { 2302 switch(c) { 2303 case 'm': 2304 min_region_mb = atoi(optarg); 2305 break; 2306 case 'f': 2307 /* Make sure old data file is gone. */ 2308 unlink(optarg); 2309 if((resultfd=open(optarg, O_CREAT | O_WRONLY | O_TRUNC)) < 0) { 2310 perror(optarg); 2311 return 1; 2312 } 2313 sync(); /* Make sure no old data file lingers. */ 2314 break; 2315 default: 2316 fprintf(stderr, "Unknown option\n"); 2317 return 1; 2318 } 2319 } 2320 2321 argc -= optind; 2322 argv += optind; 2323 2324 for (i= 0; i < argc; i++) { 2325 newdevice(argv[i], 0, 0); 2326 } 2327 2328 if (firstdev == nil) { 2329 getdevices(); 2330 key= ctrl('L'); 2331 } else { 2332 key= 'r'; 2333 } 2334 2335 { 2336 int r; 2337 if (firstdev == nil) { 2338 fprintf(stderr, "autopart couldn't find any devices.\n"); 2339 return 1; 2340 } 2341 r = do_autopart(resultfd); 2342 if(resultfd >= 0) { close(resultfd); } 2343 return r; 2344 } 2345 2346 exit(0); 2347 } 2348