1 /* 2 * fdisk - edit dos disk partition table 3 */ 4 #include <u.h> 5 #include <libc.h> 6 #include <bio.h> 7 #include <ctype.h> 8 #include <disk.h> 9 #include "edit.h" 10 11 typedef struct Dospart Dospart; 12 enum { 13 NTentry = 4, 14 Mpart = 64, 15 }; 16 17 static void rdpart(Edit*, ulong, ulong); 18 static void findmbr(Edit*); 19 static void autopart(Edit*); 20 static void wrpart(Edit*); 21 static void blankpart(Edit*); 22 static void cmdnamectl(Edit*); 23 static void recover(Edit*); 24 static int Dfmt(Fmt*); 25 static int blank; 26 static int dowrite; 27 static int file; 28 static int rdonly; 29 static int doauto; 30 static vlong mbroffset; 31 static int printflag; 32 static int printchs; 33 static int sec2cyl; 34 static int written; 35 36 static void cmdsum(Edit*, Part*, vlong, vlong); 37 static char *cmdadd(Edit*, char*, vlong, vlong); 38 static char *cmddel(Edit*, Part*); 39 static char *cmdext(Edit*, int, char**); 40 static char *cmdhelp(Edit*); 41 static char *cmdokname(Edit*, char*); 42 static char *cmdwrite(Edit*); 43 static void cmdprintctl(Edit*, int); 44 45 #pragma varargck type "D" uchar* 46 47 Edit edit = { 48 .add= cmdadd, 49 .del= cmddel, 50 .ext= cmdext, 51 .help= cmdhelp, 52 .okname= cmdokname, 53 .sum= cmdsum, 54 .write= cmdwrite, 55 .printctl= cmdprintctl, 56 57 .unit= "cylinder", 58 }; 59 60 /* 61 * Catch the obvious error routines to fix up the disk. 62 */ 63 void 64 sysfatal(char *fmt, ...) 65 { 66 char buf[1024]; 67 va_list arg; 68 69 va_start(arg, fmt); 70 vseprint(buf, buf+sizeof(buf), fmt, arg); 71 va_end(arg); 72 if(argv0) 73 fprint(2, "%s: %s\n", argv0, buf); 74 else 75 fprint(2, "%s\n", buf); 76 77 if(written) 78 recover(&edit); 79 80 exits(buf); 81 } 82 83 void 84 abort(void) 85 { 86 fprint(2, "abort\n"); 87 recover(&edit); 88 } 89 90 void 91 usage(void) 92 { 93 fprint(2, "usage: disk/fdisk [-abfprvw] [-s sectorsize] /dev/sdC0/data\n"); 94 exits("usage"); 95 } 96 97 void 98 main(int argc, char **argv) 99 { 100 vlong secsize; 101 102 secsize = 0; 103 ARGBEGIN{ 104 case 'a': 105 doauto++; 106 break; 107 case 'b': 108 blank++; 109 break; 110 case 'f': 111 file++; 112 break; 113 case 'p': 114 printflag++; 115 break; 116 case 'r': 117 rdonly++; 118 break; 119 case 's': 120 secsize = atoi(ARGF()); 121 break; 122 case 'v': 123 printchs++; 124 break; 125 case 'w': 126 dowrite++; 127 break; 128 }ARGEND; 129 130 fmtinstall('D', Dfmt); 131 132 if(argc != 1) 133 usage(); 134 135 edit.disk = opendisk(argv[0], rdonly, file); 136 if(edit.disk == nil) { 137 fprint(2, "cannot open disk: %r\n"); 138 exits("opendisk"); 139 } 140 141 if(secsize != 0) { 142 edit.disk->secsize = secsize; 143 edit.disk->secs = edit.disk->size / secsize; 144 } 145 146 sec2cyl = edit.disk->h * edit.disk->s; 147 edit.end = edit.disk->secs / sec2cyl; 148 149 findmbr(&edit); 150 151 if(blank) 152 blankpart(&edit); 153 else 154 rdpart(&edit, 0, 0); 155 156 if(doauto) 157 autopart(&edit); 158 159 if(dowrite) 160 runcmd(&edit, "w"); 161 162 if(printflag) 163 runcmd(&edit, "P"); 164 165 if(dowrite || printflag) 166 exits(0); 167 168 fprint(2, "cylinder = %lld bytes\n", sec2cyl*edit.disk->secsize); 169 runcmd(&edit, "p"); 170 for(;;) { 171 fprint(2, ">>> "); 172 runcmd(&edit, getline(&edit)); 173 } 174 } 175 176 typedef struct Tentry Tentry; 177 typedef struct Table Table; 178 typedef struct Type Type; 179 typedef struct Tab Tab; 180 typedef struct Recover Recover; 181 182 struct Tentry { 183 uchar active; /* active flag */ 184 uchar starth; /* starting head */ 185 uchar starts; /* starting sector */ 186 uchar startc; /* starting cylinder */ 187 uchar type; /* partition type */ 188 uchar endh; /* ending head */ 189 uchar ends; /* ending sector */ 190 uchar endc; /* ending cylinder */ 191 uchar xlba[4]; /* starting LBA from beginning of disc or ext. partition */ 192 uchar xsize[4]; /* size in sectors */ 193 }; 194 195 enum { 196 Active = 0x80, /* partition is active */ 197 Primary = 0x01, /* internal flag */ 198 199 TypeBB = 0xFF, 200 201 TypeEMPTY = 0x00, 202 TypeFAT12 = 0x01, 203 TypeXENIX = 0x02, /* root */ 204 TypeXENIXUSR = 0x03, /* usr */ 205 TypeFAT16 = 0x04, 206 TypeEXTENDED = 0x05, 207 TypeFATHUGE = 0x06, 208 TypeHPFS = 0x07, 209 TypeAIXBOOT = 0x08, 210 TypeAIXDATA = 0x09, 211 TypeOS2BOOT = 0x0A, /* OS/2 Boot Manager */ 212 TypeFAT32 = 0x0B, /* FAT 32 */ 213 TypeFAT32LBA = 0x0C, /* FAT 32 needing LBA support */ 214 TypeFAT16X = 0x0E, /* FAT 16 needing LBA support */ 215 TypeEXTHUGE = 0x0F, /* FAT 32 extended partition */ 216 TypeUNFORMATTED = 0x16, /* unformatted primary partition (OS/2 FDISK)? */ 217 TypeHPFS2 = 0x17, 218 TypeIBMRecovery = 0x1C, /* really hidden fat */ 219 TypeCPM0 = 0x52, 220 TypeDMDDO = 0x54, /* Disk Manager Dynamic Disk Overlay */ 221 TypeGB = 0x56, /* ???? */ 222 TypeSPEEDSTOR = 0x61, 223 TypeSYSV386 = 0x63, /* also HURD? */ 224 TypeNETWARE = 0x64, 225 TypePCIX = 0x75, 226 TypeMINIX13 = 0x80, /* Minix v1.3 and below */ 227 TypeMINIX = 0x81, /* Minix v1.5+ */ 228 TypeLINUXSWAP = 0x82, 229 TypeLINUX = 0x83, 230 TypeLINUXEXT = 0x85, 231 TypeAMOEBA = 0x93, 232 TypeAMOEBABB = 0x94, 233 TypeBSD386 = 0xA5, 234 TypeBSDI = 0xB7, 235 TypeBSDISWAP = 0xB8, 236 TypeOTHER = 0xDA, 237 TypeCPM = 0xDB, 238 TypeDellRecovery= 0xDE, 239 TypeSPEEDSTOR12 = 0xE1, 240 TypeSPEEDSTOR16 = 0xE4, 241 TypeLANSTEP = 0xFE, 242 243 Type9 = 0x39, 244 245 Toffset = 446, /* offset of partition table in sector */ 246 Magic0 = 0x55, 247 Magic1 = 0xAA, 248 }; 249 250 struct Table { 251 Tentry entry[NTentry]; 252 uchar magic[2]; 253 }; 254 255 struct Type { 256 char *desc; 257 char *name; 258 }; 259 260 struct Dospart { 261 Part; 262 Tentry; 263 264 u32int lba; 265 u32int size; 266 int primary; 267 }; 268 269 struct Recover { 270 Table table; 271 ulong lba; 272 }; 273 274 static Type types[256] = { 275 [TypeEMPTY] { "EMPTY", "" }, 276 [TypeFAT12] { "FAT12", "dos" }, 277 [TypeFAT16] { "FAT16", "dos" }, 278 [TypeFAT32] { "FAT32", "dos" }, 279 [TypeFAT32LBA] { "FAT32LBA", "dos" }, 280 [TypeFAT16X] { "FAT16X", "dos" }, 281 [TypeEXTHUGE] { "EXTHUGE", "" }, 282 [TypeIBMRecovery] { "IBMRECOVERY", "ibm" }, 283 [TypeEXTENDED] { "EXTENDED", "" }, 284 [TypeFATHUGE] { "FATHUGE", "dos" }, 285 [TypeBB] { "BB", "bb" }, 286 287 [TypeXENIX] { "XENIX", "xenix" }, 288 [TypeXENIXUSR] { "XENIX USR", "xenixusr" }, 289 [TypeHPFS] { "HPFS", "ntfs" }, 290 [TypeAIXBOOT] { "AIXBOOT", "aixboot" }, 291 [TypeAIXDATA] { "AIXDATA", "aixdata" }, 292 [TypeOS2BOOT] { "OS/2BOOT", "os2boot" }, 293 [TypeUNFORMATTED] { "UNFORMATTED", "" }, 294 [TypeHPFS2] { "HPFS2", "hpfs2" }, 295 [TypeCPM0] { "CPM0", "cpm0" }, 296 [TypeDMDDO] { "DMDDO", "dmdd0" }, 297 [TypeGB] { "GB", "gb" }, 298 [TypeSPEEDSTOR] { "SPEEDSTOR", "speedstor" }, 299 [TypeSYSV386] { "SYSV386", "sysv386" }, 300 [TypeNETWARE] { "NETWARE", "netware" }, 301 [TypePCIX] { "PCIX", "pcix" }, 302 [TypeMINIX13] { "MINIXV1.3", "minix13" }, 303 [TypeMINIX] { "MINIXV1.5", "minix15" }, 304 [TypeLINUXSWAP] { "LINUXSWAP", "linuxswap" }, 305 [TypeLINUX] { "LINUX", "linux" }, 306 [TypeLINUXEXT] { "LINUXEXTENDED", "" }, 307 [TypeAMOEBA] { "AMOEBA", "amoeba" }, 308 [TypeAMOEBABB] { "AMOEBABB", "amoebaboot" }, 309 [TypeBSD386] { "BSD386", "bsd386" }, 310 [TypeBSDI] { "BSDI", "bsdi" }, 311 [TypeBSDISWAP] { "BSDISWAP", "bsdiswap" }, 312 [TypeOTHER] { "OTHER", "other" }, 313 [TypeCPM] { "CPM", "cpm" }, 314 [TypeDellRecovery] { "DELLRECOVERY", "dell" }, 315 [TypeSPEEDSTOR12] { "SPEEDSTOR12", "speedstor" }, 316 [TypeSPEEDSTOR16] { "SPEEDSTOR16", "speedstor" }, 317 [TypeLANSTEP] { "LANSTEP", "lanstep" }, 318 319 [Type9] { "PLAN9", "plan9" }, 320 }; 321 322 static Dospart part[Mpart]; 323 static int npart; 324 325 static char* 326 typestr0(int type) 327 { 328 static char buf[100]; 329 330 sprint(buf, "type %d", type); 331 if(type < 0 || type >= 256) 332 return buf; 333 if(types[type].desc == nil) 334 return buf; 335 return types[type].desc; 336 } 337 338 static u32int 339 getle32(void* v) 340 { 341 uchar *p; 342 343 p = v; 344 return (p[3]<<24)|(p[2]<<16)|(p[1]<<8)|p[0]; 345 } 346 347 static void 348 putle32(void* v, u32int i) 349 { 350 uchar *p; 351 352 p = v; 353 p[0] = i; 354 p[1] = i>>8; 355 p[2] = i>>16; 356 p[3] = i>>24; 357 } 358 359 static void 360 diskread(Disk *disk, void *data, int ndata, u32int sec, u32int off) 361 { 362 if(seek(disk->fd, (vlong)sec*disk->secsize+off, 0) != (vlong)sec*disk->secsize+off) 363 sysfatal("diskread seek %lud.%lud: %r", (ulong)sec, (ulong)off); 364 if(readn(disk->fd, data, ndata) != ndata) 365 sysfatal("diskread %lud at %lud.%lud: %r", (ulong)ndata, (ulong)sec, (ulong)off); 366 } 367 368 static int 369 diskwrite(Disk *disk, void *data, int ndata, u32int sec, u32int off) 370 { 371 written = 1; 372 if(seek(disk->wfd, (vlong)sec*disk->secsize+off, 0) != (vlong)sec*disk->secsize+off) 373 goto Error; 374 if(write(disk->wfd, data, ndata) != ndata) 375 goto Error; 376 return 0; 377 378 Error: 379 fprint(2, "write %d bytes at %lud.%lud failed: %r\n", ndata, (ulong)sec, (ulong)off); 380 return -1; 381 } 382 383 static Dospart* 384 mkpart(char *name, int primary, u32int lba, u32int size, Tentry *t) 385 { 386 static int n; 387 Dospart *p; 388 389 p = emalloc(sizeof(*p)); 390 if(name) 391 p->name = estrdup(name); 392 else{ 393 p->name = emalloc(20); 394 sprint(p->name, "%c%d", primary ? 'p' : 's', ++n); 395 } 396 397 if(t) 398 p->Tentry = *t; 399 else 400 memset(&p->Tentry, 0, sizeof(Tentry)); 401 402 p->changed = 0; 403 p->start = lba/sec2cyl; 404 p->end = (lba+size)/sec2cyl; 405 p->ctlstart = lba; 406 p->ctlend = lba+size; 407 p->lba = lba; 408 p->size = size; 409 p->primary = primary; 410 return p; 411 } 412 413 /* 414 * Recovery takes care of remembering what the various tables 415 * looked like when we started, attempting to restore them when 416 * we are finished. 417 */ 418 static Recover *rtab; 419 static int nrtab; 420 421 static void 422 addrecover(Table t, ulong lba) 423 { 424 if((nrtab%8) == 0) { 425 rtab = realloc(rtab, (nrtab+8)*sizeof(rtab[0])); 426 if(rtab == nil) 427 sysfatal("out of memory"); 428 } 429 rtab[nrtab] = (Recover){t, lba}; 430 nrtab++; 431 } 432 433 static void 434 recover(Edit *edit) 435 { 436 int err, i, ctlfd; 437 vlong offset; 438 439 err = 0; 440 for(i=0; i<nrtab; i++) 441 if(diskwrite(edit->disk, &rtab[i].table, sizeof(Table), rtab[i].lba, Toffset) < 0) 442 err = 1; 443 if(err) { 444 fprint(2, "warning: some writes failed during restoration of old partition tables\n"); 445 exits("inconsistent"); 446 } else { 447 fprint(2, "restored old partition tables\n"); 448 } 449 450 ctlfd = edit->disk->ctlfd; 451 offset = edit->disk->offset; 452 if(ctlfd >= 0){ 453 for(i=0; i<edit->npart; i++) 454 if(edit->part[i]->ctlname && fprint(ctlfd, "delpart %s", edit->part[i]->ctlname)<0) 455 fprint(2, "delpart failed: %s: %r", edit->part[i]->ctlname); 456 for(i=0; i<edit->nctlpart; i++) 457 if(edit->part[i]->name && fprint(ctlfd, "delpart %s", edit->ctlpart[i]->name)<0) 458 fprint(2, "delpart failed: %s: %r", edit->ctlpart[i]->name); 459 for(i=0; i<edit->nctlpart; i++){ 460 if(fprint(ctlfd, "part %s %lld %lld", edit->ctlpart[i]->name, 461 edit->ctlpart[i]->start+offset, edit->ctlpart[i]->end+offset) < 0){ 462 fprint(2, "restored disk partition table but not kernel; reboot\n"); 463 exits("inconsistent"); 464 } 465 } 466 } 467 exits("restored"); 468 469 } 470 471 /* 472 * Read the partition table (including extended partition tables) 473 * from the disk into the part array. 474 */ 475 static void 476 rdpart(Edit *edit, ulong lba, ulong xbase) 477 { 478 char *err; 479 Table table; 480 Tentry *tp, *ep; 481 Dospart *p; 482 483 if(xbase == 0) 484 xbase = lba; 485 486 diskread(edit->disk, &table, sizeof table, mbroffset+lba, Toffset); 487 addrecover(table, mbroffset+lba); 488 489 if(table.magic[0] != Magic0 || table.magic[1] != Magic1) { 490 assert(lba != 0); 491 return; 492 } 493 494 for(tp=table.entry, ep=tp+NTentry; tp<ep && npart < Mpart; tp++) { 495 switch(tp->type) { 496 case TypeEMPTY: 497 break; 498 case TypeEXTENDED: 499 case TypeEXTHUGE: 500 case TypeLINUXEXT: 501 rdpart(edit, xbase+getle32(tp->xlba), xbase); 502 break; 503 default: 504 p = mkpart(nil, lba==0, lba+getle32(tp->xlba), getle32(tp->xsize), tp); 505 if(err = addpart(edit, p)) 506 fprint(2, "adding partition: %s\n", err); 507 break; 508 } 509 } 510 } 511 512 static void 513 blankpart(Edit *edit) 514 { 515 edit->changed = 1; 516 } 517 518 static void 519 findmbr(Edit *edit) 520 { 521 Table table; 522 Tentry *tp; 523 524 diskread(edit->disk, &table, sizeof(Table), 0, Toffset); 525 if(table.magic[0] != Magic0 || table.magic[1] != Magic1) 526 sysfatal("did not find master boot record"); 527 528 for(tp = table.entry; tp < &table.entry[NTentry]; tp++) 529 if(tp->type == TypeDMDDO) 530 mbroffset = edit->disk->s; 531 } 532 533 static int 534 haveroom(Edit *edit, int primary, vlong start) 535 { 536 int i, lastsec, n; 537 Dospart *p, *q; 538 ulong pend, qstart; 539 540 if(primary) { 541 /* 542 * must be open primary slot. 543 * primary slots are taken by primary partitions 544 * and runs of secondary partitions. 545 */ 546 n = 0; 547 lastsec = 0; 548 for(i=0; i<edit->npart; i++) { 549 p = (Dospart*)edit->part[i]; 550 if(p->primary) 551 n++, lastsec=0; 552 else if(!lastsec) 553 n++, lastsec=1; 554 } 555 return n<4; 556 } 557 558 /* 559 * secondary partitions can be inserted between two primary 560 * partitions only if there is an empty primary slot. 561 * otherwise, we can put a new secondary partition next 562 * to a secondary partition no problem. 563 */ 564 n = 0; 565 for(i=0; i<edit->npart; i++){ 566 p = (Dospart*)edit->part[i]; 567 if(p->primary) 568 n++; 569 pend = p->end; 570 if(i+1<edit->npart){ 571 q = (Dospart*)edit->part[i+1]; 572 qstart = q->start; 573 }else{ 574 qstart = edit->end; 575 q = nil; 576 } 577 if(start < pend || start >= qstart) 578 continue; 579 /* we go between these two */ 580 if(p->primary==0 || (q && q->primary==0)) 581 return 1; 582 } 583 /* not next to a secondary, need a new primary */ 584 return n<4; 585 } 586 587 static void 588 autopart(Edit *edit) 589 { 590 char *err; 591 int active, i; 592 vlong bigstart, bigsize, start; 593 Dospart *p; 594 595 for(i=0; i<edit->npart; i++) 596 if(((Dospart*)edit->part[i])->type == Type9) 597 return; 598 599 /* look for the biggest gap in which we can put a primary partition */ 600 start = 0; 601 bigsize = 0; 602 SET(bigstart); 603 for(i=0; i<edit->npart; i++) { 604 p = (Dospart*)edit->part[i]; 605 if(p->start > start && p->start - start > bigsize && haveroom(edit, 1, start)) { 606 bigsize = p->start - start; 607 bigstart = start; 608 } 609 start = p->end; 610 } 611 612 if(edit->end - start > bigsize && haveroom(edit, 1, start)) { 613 bigsize = edit->end - start; 614 bigstart = start; 615 } 616 if(bigsize < 1) { 617 fprint(2, "couldn't find space or partition slot for plan 9 partition\n"); 618 return; 619 } 620 621 /* set new partition active only if no others are */ 622 active = Active; 623 for(i=0; i<edit->npart; i++) 624 if(((Dospart*)edit->part[i])->primary && (((Dospart*)edit->part[i])->active & Active)) 625 active = 0; 626 627 /* add new plan 9 partition */ 628 bigsize *= sec2cyl; 629 bigstart *= sec2cyl; 630 if(bigstart == 0) { 631 bigstart += edit->disk->s; 632 bigsize -= edit->disk->s; 633 } 634 p = mkpart(nil, 1, bigstart, bigsize, nil); 635 p->active = active; 636 p->changed = 1; 637 p->type = Type9; 638 edit->changed = 1; 639 if(err = addpart(edit, p)) { 640 fprint(2, "error adding plan9 partition: %s\n", err); 641 return; 642 } 643 } 644 645 typedef struct Name Name; 646 struct Name { 647 char *name; 648 Name *link; 649 }; 650 Name *namelist; 651 static void 652 plan9print(Dospart *part, int fd) 653 { 654 int i, ok; 655 char *name, *vname; 656 Name *n; 657 vlong start, end; 658 char *sep; 659 660 vname = types[part->type].name; 661 if(vname==nil || strcmp(vname, "")==0) { 662 part->ctlname = ""; 663 return; 664 } 665 666 start = mbroffset+part->lba; 667 end = start+part->size; 668 669 /* avoid names like plan90 */ 670 i = strlen(vname) - 1; 671 if(vname[i] >= '0' && vname[i] <= '9') 672 sep = "."; 673 else 674 sep = ""; 675 676 i = 0; 677 name = emalloc(strlen(vname)+10); 678 679 sprint(name, "%s", vname); 680 do { 681 ok = 1; 682 for(n=namelist; n; n=n->link) { 683 if(strcmp(name, n->name) == 0) { 684 i++; 685 sprint(name, "%s%s%d", vname, sep, i); 686 ok = 0; 687 } 688 } 689 } while(ok == 0); 690 691 n = emalloc(sizeof(*n)); 692 n->name = name; 693 n->link = namelist; 694 namelist = n; 695 part->ctlname = name; 696 697 if(fd >= 0) 698 print("part %s %lld %lld\n", name, start, end); 699 } 700 701 static void 702 freenamelist(void) 703 { 704 Name *n, *next; 705 706 for(n=namelist; n; n=next) { 707 next = n->link; 708 free(n); 709 } 710 namelist = nil; 711 } 712 713 static void 714 cmdprintctl(Edit *edit, int ctlfd) 715 { 716 int i; 717 718 freenamelist(); 719 for(i=0; i<edit->npart; i++) 720 plan9print((Dospart*)edit->part[i], -1); 721 ctldiff(edit, ctlfd); 722 } 723 724 static char* 725 cmdokname(Edit*, char *name) 726 { 727 char *q; 728 729 if(name[0] != 'p' && name[0] != 's') 730 return "name must be pN or sN"; 731 732 strtol(name+1, &q, 10); 733 if(*q != '\0') 734 return "name must be pN or sN"; 735 736 return nil; 737 } 738 739 #define GB (1024*1024*1024) 740 #define MB (1024*1024) 741 #define KB (1024) 742 743 static void 744 cmdsum(Edit *edit, Part *vp, vlong a, vlong b) 745 { 746 char *name, *ty; 747 char buf[3]; 748 char *suf; 749 Dospart *p; 750 vlong sz, div; 751 752 p = (Dospart*)vp; 753 754 buf[0] = p && p->changed ? '\'' : ' '; 755 buf[1] = p && (p->active & Active) ? '*' : ' '; 756 buf[2] = '\0'; 757 758 name = p ? p->name : "empty"; 759 ty = p ? typestr0(p->type) : ""; 760 761 sz = (b-a)*edit->disk->secsize*sec2cyl; 762 if(sz >= 1*GB){ 763 suf = "GB"; 764 div = GB; 765 }else if(sz >= 1*MB){ 766 suf = "MB"; 767 div = MB; 768 }else if(sz >= 1*KB){ 769 suf = "KB"; 770 div = KB; 771 }else{ 772 suf = "B "; 773 div = 1; 774 } 775 776 if(div == 1) 777 print("%s %-12s %*lld %-*lld (%lld cylinders, %lld %s) %s\n", buf, name, 778 edit->disk->width, a, edit->disk->width, b, b-a, sz, suf, ty); 779 else 780 print("%s %-12s %*lld %-*lld (%lld cylinders, %lld.%.2d %s) %s\n", buf, name, 781 edit->disk->width, a, edit->disk->width, b, b-a, 782 sz/div, (int)(((sz%div)*100)/div), suf, ty); 783 } 784 785 static char* 786 cmdadd(Edit *edit, char *name, vlong start, vlong end) 787 { 788 Dospart *p; 789 790 if(!haveroom(edit, name[0]=='p', start)) 791 return "no room for partition"; 792 start *= sec2cyl; 793 end *= sec2cyl; 794 if(start == 0 || name[0] != 'p') 795 start += edit->disk->s; 796 p = mkpart(name, name[0]=='p', start, end-start, nil); 797 p->changed = 1; 798 p->type = Type9; 799 return addpart(edit, p); 800 } 801 802 static char* 803 cmddel(Edit *edit, Part *p) 804 { 805 return delpart(edit, p); 806 } 807 808 static char* 809 cmdwrite(Edit *edit) 810 { 811 wrpart(edit); 812 return nil; 813 } 814 815 static char *help = 816 "A name - set partition active\n" 817 "P - print table in ctl format\n" 818 "R - restore disk back to initial configuration and exit\n" 819 "e - show empty dos partitions\n" 820 "t name [type] - set partition type\n"; 821 822 static char* 823 cmdhelp(Edit*) 824 { 825 print("%s\n", help); 826 return nil; 827 } 828 829 static char* 830 cmdactive(Edit *edit, int nf, char **f) 831 { 832 int i; 833 Dospart *p, *ip; 834 835 if(nf != 2) 836 return "args"; 837 838 if(f[1][0] != 'p') 839 return "cannot set secondary partition active"; 840 841 if((p = (Dospart*)findpart(edit, f[1])) == nil) 842 return "unknown partition"; 843 844 for(i=0; i<edit->npart; i++) { 845 ip = (Dospart*)edit->part[i]; 846 if(ip->active & Active) { 847 ip->active &= ~Active; 848 ip->changed = 1; 849 edit->changed = 1; 850 } 851 } 852 853 if((p->active & Active) == 0) { 854 p->active |= Active; 855 p->changed = 1; 856 edit->changed = 1; 857 } 858 859 return nil; 860 } 861 862 static char* 863 strupr(char *s) 864 { 865 char *p; 866 867 for(p=s; *p; p++) 868 *p = toupper(*p); 869 return s; 870 } 871 872 static void 873 dumplist(void) 874 { 875 int i, n; 876 877 n = 0; 878 for(i=0; i<256; i++) { 879 if(types[i].desc) { 880 print("%-16s", types[i].desc); 881 if(n++%4 == 3) 882 print("\n"); 883 } 884 } 885 if(n%4) 886 print("\n"); 887 } 888 889 static char* 890 cmdtype(Edit *edit, int nf, char **f) 891 { 892 char *q; 893 Dospart *p; 894 int i; 895 896 if(nf < 2) 897 return "args"; 898 899 if((p = (Dospart*)findpart(edit, f[1])) == nil) 900 return "unknown partition"; 901 902 if(nf == 2) { 903 for(;;) { 904 fprint(2, "new partition type [? for list]: "); 905 q = getline(edit); 906 if(q[0] == '?') 907 dumplist(); 908 else 909 break; 910 } 911 } else 912 q = f[2]; 913 914 strupr(q); 915 for(i=0; i<256; i++) 916 if(types[i].desc && strcmp(types[i].desc, q) == 0) 917 break; 918 if(i < 256 && p->type != i) { 919 p->type = i; 920 p->changed = 1; 921 edit->changed = 1; 922 } 923 return nil; 924 } 925 926 static char* 927 cmdext(Edit *edit, int nf, char **f) 928 { 929 switch(f[0][0]) { 930 case 'A': 931 return cmdactive(edit, nf, f); 932 case 't': 933 return cmdtype(edit, nf, f); 934 case 'R': 935 recover(edit); 936 return nil; 937 default: 938 return "unknown command"; 939 } 940 } 941 942 static int 943 Dfmt(Fmt *f) 944 { 945 char buf[60]; 946 uchar *p; 947 int c, h, s; 948 949 p = va_arg(f->args, uchar*); 950 h = p[0]; 951 c = p[2]; 952 c |= (p[1]&0xC0)<<2; 953 s = (p[1] & 0x3F); 954 955 sprint(buf, "%d/%d/%d", c, h, s); 956 return fmtstrcpy(f, buf); 957 } 958 959 static void 960 writechs(Disk *disk, uchar *p, vlong lba) 961 { 962 int c, h, s; 963 964 s = lba % disk->s; 965 h = (lba / disk->s) % disk->h; 966 c = lba / (disk->s * disk->h); 967 968 if(c >= 1024) { 969 c = 1023; 970 h = disk->h - 1; 971 s = disk->s - 1; 972 } 973 974 p[0] = h; 975 p[1] = ((s+1) & 0x3F) | ((c>>2) & 0xC0); 976 p[2] = c; 977 } 978 979 static void 980 wrtentry(Disk *disk, Tentry *tp, int type, u32int xbase, u32int lba, u32int end) 981 { 982 tp->type = type; 983 writechs(disk, &tp->starth, lba); 984 writechs(disk, &tp->endh, end-1); 985 putle32(tp->xlba, lba-xbase); 986 putle32(tp->xsize, end-lba); 987 } 988 989 static int 990 wrextend(Edit *edit, int i, vlong xbase, vlong startlba, vlong *endlba) 991 { 992 int ni; 993 Table table; 994 Tentry *tp, *ep; 995 Dospart *p; 996 Disk *disk; 997 998 if(i == edit->npart){ 999 *endlba = edit->disk->secs; 1000 Finish: 1001 if(startlba < *endlba){ 1002 disk = edit->disk; 1003 diskread(disk, &table, sizeof table, mbroffset+startlba, Toffset); 1004 tp = table.entry; 1005 ep = tp+NTentry; 1006 for(; tp<ep; tp++) 1007 memset(tp, 0, sizeof *tp); 1008 table.magic[0] = Magic0; 1009 table.magic[1] = Magic1; 1010 1011 if(diskwrite(edit->disk, &table, sizeof table, mbroffset+startlba, Toffset) < 0) 1012 recover(edit); 1013 } 1014 return i; 1015 } 1016 1017 p = (Dospart*)edit->part[i]; 1018 if(p->primary){ 1019 *endlba = (vlong)p->start*sec2cyl; 1020 goto Finish; 1021 } 1022 1023 disk = edit->disk; 1024 diskread(disk, &table, sizeof table, mbroffset+startlba, Toffset); 1025 tp = table.entry; 1026 ep = tp+NTentry; 1027 1028 ni = wrextend(edit, i+1, xbase, p->end*sec2cyl, endlba); 1029 1030 *tp = p->Tentry; 1031 wrtentry(disk, tp, p->type, startlba, startlba+disk->s, p->end*sec2cyl); 1032 tp++; 1033 1034 if(p->end*sec2cyl != *endlba){ 1035 memset(tp, 0, sizeof *tp); 1036 wrtentry(disk, tp, TypeEXTENDED, xbase, p->end*sec2cyl, *endlba); 1037 tp++; 1038 } 1039 1040 for(; tp<ep; tp++) 1041 memset(tp, 0, sizeof *tp); 1042 1043 table.magic[0] = Magic0; 1044 table.magic[1] = Magic1; 1045 1046 if(diskwrite(edit->disk, &table, sizeof table, mbroffset+startlba, Toffset) < 0) 1047 recover(edit); 1048 return ni; 1049 } 1050 1051 static void 1052 wrpart(Edit *edit) 1053 { 1054 int i, ni, t; 1055 Table table; 1056 Tentry *tp, *ep; 1057 Disk *disk; 1058 vlong s, endlba; 1059 Dospart *p; 1060 1061 disk = edit->disk; 1062 1063 diskread(disk, &table, sizeof table, mbroffset, Toffset); 1064 1065 tp = table.entry; 1066 ep = tp+NTentry; 1067 for(i=0; i<edit->npart && tp<ep; ) { 1068 p = (Dospart*)edit->part[i]; 1069 if(p->start == 0) 1070 s = disk->s; 1071 else 1072 s = p->start*sec2cyl; 1073 if(p->primary) { 1074 *tp = p->Tentry; 1075 wrtentry(disk, tp, p->type, 0, s, p->end*sec2cyl); 1076 tp++; 1077 i++; 1078 } else { 1079 ni = wrextend(edit, i, p->start*sec2cyl, p->start*sec2cyl, &endlba); 1080 memset(tp, 0, sizeof *tp); 1081 if(endlba >= 1024*sec2cyl) 1082 t = TypeEXTHUGE; 1083 else 1084 t = TypeEXTENDED; 1085 wrtentry(disk, tp, t, 0, s, endlba); 1086 tp++; 1087 i = ni; 1088 } 1089 } 1090 for(; tp<ep; tp++) 1091 memset(tp, 0, sizeof(*tp)); 1092 1093 if(i != edit->npart) 1094 sysfatal("cannot happen #1"); 1095 1096 if(diskwrite(disk, &table, sizeof table, mbroffset, Toffset) < 0) 1097 recover(edit); 1098 1099 /* bring parts up to date */ 1100 freenamelist(); 1101 for(i=0; i<edit->npart; i++) 1102 plan9print((Dospart*)edit->part[i], -1); 1103 1104 if(ctldiff(edit, disk->ctlfd) < 0) 1105 fprint(2, "?warning: partitions could not be updated in devsd\n"); 1106 } 1107