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