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