2 * fdisk - edit dos disk partition table
11 typedef struct Dospart Dospart;
17 static void rdpart(Edit*, uvlong, uvlong, int);
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*);
35 static void cmdsum(Edit*, Part*, vlong, vlong);
36 static char *cmdadd(Edit*, char*, vlong, vlong);
37 static char *cmddel(Edit*, Part*);
38 static char *cmdext(Edit*, int, char**);
39 static char *cmdhelp(Edit*);
40 static char *cmdokname(Edit*, char*);
41 static char *cmdwrite(Edit*);
42 static void cmdprintctl(Edit*, int);
44 #pragma varargck type "D" uchar*
54 .printctl= cmdprintctl,
60 * Catch the obvious error routines to fix up the disk.
63 sysfatal(char *fmt, ...)
69 vseprint(buf, buf+sizeof(buf), fmt, arg);
72 fprint(2, "%s: %s\n", argv0, buf);
74 fprint(2, "%s\n", buf);
92 fprint(2, "usage: disk/fdisk [-abfprvw] [-s sectorsize] /dev/sdC0/data\n");
97 main(int argc, char **argv)
119 secsize = atoi(ARGF());
129 fmtinstall('D', Dfmt);
134 edit.disk = opendisk(argv[0], rdonly, file);
135 if(edit.disk == nil) {
136 fprint(2, "cannot open disk: %r\n");
141 edit.disk->secsize = secsize;
142 edit.disk->secs = edit.disk->size / secsize;
145 sec2cyl = edit.disk->h * edit.disk->s;
146 edit.end = edit.disk->secs / sec2cyl;
153 rdpart(&edit, 0, 0, 0);
164 if(dowrite || printflag)
167 fprint(2, "cylinder = %lld bytes\n", sec2cyl*edit.disk->secsize);
171 runcmd(&edit, getline(&edit));
175 typedef struct Tentry Tentry;
176 typedef struct Table Table;
177 typedef struct Type Type;
178 typedef struct Tab Tab;
179 typedef struct Recover Recover;
182 uchar active; /* active flag */
183 uchar starth; /* starting head */
184 uchar starts; /* starting sector */
185 uchar startc; /* starting cylinder */
186 uchar type; /* partition type */
187 uchar endh; /* ending head */
188 uchar ends; /* ending sector */
189 uchar endc; /* ending cylinder */
190 uchar xlba[4]; /* starting LBA from beginning of disc or ext. partition */
191 uchar xsize[4]; /* size in sectors */
195 Active = 0x80, /* partition is active */
196 Primary = 0x01, /* internal flag */
202 TypeXENIX = 0x02, /* root */
203 TypeXENIXUSR = 0x03, /* usr */
210 TypeOS2BOOT = 0x0A, /* OS/2 Boot Manager */
211 TypeFAT32 = 0x0B, /* FAT 32 */
212 TypeFAT32LBA = 0x0C, /* FAT 32 needing LBA support */
213 TypeFAT16X = 0x0E, /* FAT 16 needing LBA support */
214 TypeEXTHUGE = 0x0F, /* FAT 32 extended partition */
215 TypeUNFORMATTED = 0x16, /* unformatted primary partition (OS/2 FDISK)? */
217 TypeIBMRecovery = 0x1C, /* really hidden fat */
219 TypeDMDDO = 0x54, /* Disk Manager Dynamic Disk Overlay */
220 TypeGB = 0x56, /* ???? */
221 TypeSPEEDSTOR = 0x61,
222 TypeSYSV386 = 0x63, /* also HURD? */
225 TypeMINIX13 = 0x80, /* Minix v1.3 and below */
226 TypeMINIX = 0x81, /* Minix v1.5+ */
227 TypeLINUXSWAP = 0x82,
230 TypeLINUXLVM = 0x8E, /* logical volume manager */
239 TypeDellRecovery= 0xDE,
240 TypeSPEEDSTOR12 = 0xE1,
241 TypeSPEEDSTOR16 = 0xE4,
246 Toffset = 446, /* offset of partition table in sector */
252 Tentry entry[NTentry];
275 static Type types[256] = {
276 [TypeEMPTY] { "EMPTY", "" },
277 [TypeFAT12] { "FAT12", "dos" },
278 [TypeFAT16] { "FAT16", "dos" },
279 [TypeFAT32] { "FAT32", "dos" },
280 [TypeFAT32LBA] { "FAT32LBA", "dos" },
281 [TypeFAT16X] { "FAT16X", "dos" },
282 [TypeEXTHUGE] { "EXTHUGE", "" },
283 [TypeIBMRecovery] { "IBMRECOVERY", "ibm" },
284 [TypeEXTENDED] { "EXTENDED", "" },
285 [TypeFATHUGE] { "FATHUGE", "dos" },
286 [TypeBB] { "BB", "bb" },
288 [TypeXENIX] { "XENIX", "xenix" },
289 [TypeXENIXUSR] { "XENIX USR", "xenixusr" },
290 [TypeHPFS] { "HPFS", "ntfs" },
291 [TypeAIXBOOT] { "AIXBOOT", "aixboot" },
292 [TypeAIXDATA] { "AIXDATA", "aixdata" },
293 [TypeOS2BOOT] { "OS/2BOOT", "os2boot" },
294 [TypeUNFORMATTED] { "UNFORMATTED", "" },
295 [TypeHPFS2] { "HPFS2", "hpfs2" },
296 [TypeCPM0] { "CPM0", "cpm0" },
297 [TypeDMDDO] { "DMDDO", "dmdd0" },
298 [TypeGB] { "GB", "gb" },
299 [TypeSPEEDSTOR] { "SPEEDSTOR", "speedstor" },
300 [TypeSYSV386] { "SYSV386", "sysv386" },
301 [TypeNETWARE] { "NETWARE", "netware" },
302 [TypePCIX] { "PCIX", "pcix" },
303 [TypeMINIX13] { "MINIXV1.3", "minix13" },
304 [TypeMINIX] { "MINIXV1.5", "minix15" },
305 [TypeLINUXSWAP] { "LINUXSWAP", "linuxswap" },
306 [TypeLINUX] { "LINUX", "linux" },
307 [TypeLINUXEXT] { "LINUXEXTENDED", "" },
308 [TypeLINUXLVM] { "LINUXLVM", "linuxlvm" },
309 [TypeAMOEBA] { "AMOEBA", "amoeba" },
310 [TypeAMOEBABB] { "AMOEBABB", "amoebaboot" },
311 [TypeBSD386] { "BSD386", "bsd386" },
312 [TypeNETBSD] { "NETBSD", "netbsd" },
313 [TypeBSDI] { "BSDI", "bsdi" },
314 [TypeBSDISWAP] { "BSDISWAP", "bsdiswap" },
315 [TypeOTHER] { "OTHER", "other" },
316 [TypeCPM] { "CPM", "cpm" },
317 [TypeDellRecovery] { "DELLRECOVERY", "dell" },
318 [TypeSPEEDSTOR12] { "SPEEDSTOR12", "speedstor" },
319 [TypeSPEEDSTOR16] { "SPEEDSTOR16", "speedstor" },
320 [TypeLANSTEP] { "LANSTEP", "lanstep" },
322 [Type9] { "PLAN9", "plan9" },
325 static Dospart part[Mpart];
331 static char buf[100];
333 sprint(buf, "type %d", type);
334 if(type < 0 || type >= 256)
336 if(types[type].desc == nil)
338 return types[type].desc;
347 return (p[3]<<24)|(p[2]<<16)|(p[1]<<8)|p[0];
351 putle32(void* v, u32int i)
363 diskread(Disk *disk, void *data, int ndata, u32int sec, u32int off)
365 if(seek(disk->fd, (vlong)sec*disk->secsize+off, 0) != (vlong)sec*disk->secsize+off)
366 sysfatal("diskread seek %lud.%lud: %r", (ulong)sec, (ulong)off);
367 if(readn(disk->fd, data, ndata) != ndata)
368 sysfatal("diskread %lud at %lud.%lud: %r", (ulong)ndata, (ulong)sec, (ulong)off);
372 diskwrite(Disk *disk, void *data, int ndata, u32int sec, u32int off)
375 if(seek(disk->wfd, (vlong)sec*disk->secsize+off, 0) != (vlong)sec*disk->secsize+off)
377 if(write(disk->wfd, data, ndata) != ndata)
382 fprint(2, "write %d bytes at %lud.%lud failed: %r\n", ndata, (ulong)sec, (ulong)off);
387 mkpart(char *name, vlong lba, vlong size, Tentry *t, vlong ebrstart, int ebrtype)
393 primary = (ebrstart == 0) && (ebrtype == 0);
394 p = emalloc(sizeof(*p));
396 p->name = estrdup(name);
398 p->name = emalloc(20);
399 sprint(p->name, "%c%d", primary ? 'p' : 's', ++n);
405 memset(&p->Tentry, 0, sizeof(Tentry));
408 p->start = lba/sec2cyl;
409 p->end = (lba+size+sec2cyl-1)/sec2cyl;
412 p->ctlend = lba+size;
414 p->ebrstart = ebrstart;
415 p->ebrtype = ebrtype;
416 p->primary = primary;
424 if(end >= 1024*sec2cyl)
430 * Recovery takes care of remembering what the various tables
431 * looked like when we started, attempting to restore them when
434 static Recover *rtab;
438 addrecover(Table t, ulong lba)
441 rtab = realloc(rtab, (nrtab+8)*sizeof(rtab[0]));
443 sysfatal("out of memory");
445 rtab[nrtab] = (Recover){t, lba};
456 for(i=0; i<nrtab; i++)
457 if(diskwrite(edit->disk, &rtab[i].table, sizeof(Table), rtab[i].lba, Toffset) < 0)
460 fprint(2, "warning: some writes failed during restoration of old partition tables\n");
461 exits("inconsistent");
463 fprint(2, "restored old partition tables\n");
466 ctlfd = edit->disk->ctlfd;
467 offset = edit->disk->offset;
469 for(i=0; i<edit->npart; i++)
470 if(edit->part[i]->ctlname && fprint(ctlfd, "delpart %s", edit->part[i]->ctlname)<0)
471 fprint(2, "delpart failed: %s: %r", edit->part[i]->ctlname);
472 for(i=0; i<edit->nctlpart; i++)
473 if(edit->part[i]->name && fprint(ctlfd, "delpart %s", edit->ctlpart[i]->name)<0)
474 fprint(2, "delpart failed: %s: %r", edit->ctlpart[i]->name);
475 for(i=0; i<edit->nctlpart; i++){
476 if(fprint(ctlfd, "part %s %lld %lld", edit->ctlpart[i]->name,
477 edit->ctlpart[i]->start+offset, edit->ctlpart[i]->end+offset) < 0){
478 fprint(2, "restored disk partition table but not kernel; reboot\n");
479 exits("inconsistent");
488 * Read the partition table (including extended partition tables)
489 * from the disk into the part array.
492 rdpart(Edit *edit, uvlong xbase, uvlong ebrstart, int ebrtype)
502 diskread(edit->disk, &table, sizeof table, ebrstart, Toffset);
503 addrecover(table, ebrstart);
504 if(table.magic[0] != Magic0 || table.magic[1] != Magic1)
507 for(tp=table.entry, ep=tp+NTentry; tp<ep && npart < Mpart; tp++) {
514 rdpart(edit, xbase, xbase+getle32(tp->xlba), tp->type);
517 p = mkpart(nil, ebrstart+getle32(tp->xlba), getle32(tp->xsize), tp, ebrstart, ebrtype);
518 if(err = addpart(edit, p))
519 fprint(2, "adding partition: %s\n", err);
526 blankpart(Edit *edit)
536 diskread(edit->disk, &table, sizeof(Table), 0, Toffset);
537 if(table.magic[0] != Magic0 || table.magic[1] != Magic1)
538 sysfatal("did not find master boot record");
542 haveroom(Edit *edit, int primary, vlong start)
550 * must be open primary slot.
551 * primary slots are taken by primary partitions
552 * and runs of secondary partitions.
556 for(i=0; i<edit->npart; i++) {
557 p = (Dospart*)edit->part[i];
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.
573 for(i=0; i<edit->npart; i++){
574 p = (Dospart*)edit->part[i];
579 q = (Dospart*)edit->part[i+1];
585 if(start < pend || start >= qstart)
587 /* we go between these two */
588 if(p->primary==0 || (q && q->primary==0))
591 /* not next to a secondary, need a new primary */
600 vlong bigstart, bigsize, start;
603 for(i=0; i<edit->npart; i++)
604 if(((Dospart*)edit->part[i])->type == Type9)
607 /* look for the biggest gap in which we can put a primary partition */
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;
620 if(edit->end - start > bigsize && haveroom(edit, 1, start)) {
621 bigsize = edit->end - start;
625 fprint(2, "couldn't find space or partition slot for plan 9 partition\n");
629 /* set new partition active only if no others are */
631 for(i=0; i<edit->npart; i++)
632 if(((Dospart*)edit->part[i])->primary && (((Dospart*)edit->part[i])->active & Active))
635 /* add new plan 9 partition */
639 bigstart += edit->disk->s;
640 bigsize -= edit->disk->s;
642 p = mkpart(nil, bigstart, bigsize, nil, 0, 0);
647 if(err = addpart(edit, p)) {
648 fprint(2, "error adding plan9 partition: %s\n", err);
653 typedef struct Name Name;
660 plan9print(Dospart *part, int fd)
667 vname = types[part->type].name;
668 if(vname==nil || strcmp(vname, "")==0) {
673 /* avoid names like plan90 */
674 i = strlen(vname) - 1;
675 if(vname[i] >= '0' && vname[i] <= '9')
681 name = emalloc(strlen(vname)+10);
683 sprint(name, "%s", vname);
686 for(n=namelist; n; n=n->link) {
687 if(strcmp(name, n->name) == 0) {
689 sprint(name, "%s%s%d", vname, sep, i);
695 n = emalloc(sizeof(*n));
699 part->ctlname = name;
702 print("part %s %lld %lld\n", name, part->ctlstart, part->ctlend);
710 for(n=namelist; n; n=next) {
718 cmdprintctl(Edit *edit, int ctlfd)
723 for(i=0; i<edit->npart; i++)
724 plan9print((Dospart*)edit->part[i], -1);
725 ctldiff(edit, ctlfd);
729 cmdokname(Edit*, char *name)
733 if(name[0] != 'p' && name[0] != 's')
734 return "name must be pN or sN";
736 strtol(name+1, &q, 10);
738 return "name must be pN or sN";
743 #define TB (1024LL*GB)
744 #define GB (1024*1024*1024)
745 #define MB (1024*1024)
749 cmdsum(Edit *edit, Part *vp, vlong a, vlong b)
759 buf[0] = p && p->changed ? '\'' : ' ';
760 buf[1] = p && (p->active & Active) ? '*' : ' ';
763 name = p ? p->name : "empty";
764 ty = p ? typestr0(p->type) : "";
766 sz = (b-a)*edit->disk->secsize*sec2cyl;
770 }else if(sz >= 1*GB){
773 }else if(sz >= 1*MB){
776 }else if(sz >= 1*KB){
785 print("%s %-12s %*lld %-*lld (%lld cylinders, %lld %s) %s\n", buf, name,
786 edit->disk->width, a, edit->disk->width, b, b-a, sz, suf, ty);
788 print("%s %-12s %*lld %-*lld (%lld cylinders, %lld.%.2d %s) %s\n", buf, name,
789 edit->disk->width, a, edit->disk->width, b, b-a,
790 sz/div, (int)(((sz%div)*100)/div), suf, ty);
794 cmdadd(Edit *edit, char *name, vlong start, vlong end)
800 if(!haveroom(edit, name[0]=='p', start))
801 return "no room for partition";
808 start += edit->disk->s;
811 start += edit->disk->s;
812 ebrtype = mkebrtype(end);
814 start += edit->disk->s;
816 p = mkpart(name, start, end-start, nil, ebrstart, ebrtype);
819 return addpart(edit, p);
823 cmddel(Edit *edit, Part *p)
825 return delpart(edit, p);
836 "A name - set partition active\n"
837 "P - print table in ctl format\n"
838 "R - restore disk back to initial configuration and exit\n"
839 "e - show empty dos partitions\n"
840 "t name [type] - set partition type\n";
850 cmdactive(Edit *edit, int nf, char **f)
859 return "cannot set secondary partition active";
861 if((p = (Dospart*)findpart(edit, f[1])) == nil)
862 return "unknown partition";
864 for(i=0; i<edit->npart; i++) {
865 ip = (Dospart*)edit->part[i];
866 if(ip->active & Active) {
867 ip->active &= ~Active;
873 if((p->active & Active) == 0) {
898 for(i=0; i<256; i++) {
900 print("%-16s", types[i].desc);
910 cmdtype(Edit *edit, int nf, char **f)
919 if((p = (Dospart*)findpart(edit, f[1])) == nil)
920 return "unknown partition";
924 fprint(2, "new partition type [? for list]: ");
936 if(types[i].desc && strcmp(types[i].desc, q) == 0)
938 if(i < 256 && p->type != i) {
947 cmdext(Edit *edit, int nf, char **f)
951 return cmdactive(edit, nf, f);
953 return cmdtype(edit, nf, f);
958 return "unknown command";
969 p = va_arg(f->args, uchar*);
975 sprint(buf, "%d/%d/%d", c, h, s);
976 return fmtstrcpy(f, buf);
980 writechs(Disk *disk, uchar *p, vlong lba)
985 h = (lba / disk->s) % disk->h;
986 c = lba / (disk->s * disk->h);
995 p[1] = ((s+1) & 0x3F) | ((c>>2) & 0xC0);
1000 wrtentry(Disk *disk, Tentry *tp, int type, u32int xbase, u32int lba, u32int end)
1003 writechs(disk, &tp->starth, lba);
1004 writechs(disk, &tp->endh, end-1);
1005 putle32(tp->xlba, lba-xbase);
1006 putle32(tp->xsize, end-lba);
1010 wrextend(Edit *edit, int i, vlong xbase, vlong startlba, vlong *endlba)
1020 if(i == edit->npart){
1021 *endlba = edit->disk->secs;
1023 if(startlba < *endlba){
1025 diskread(disk, &table, sizeof table, startlba, Toffset);
1029 memset(tp, 0, sizeof *tp);
1030 table.magic[0] = Magic0;
1031 table.magic[1] = Magic1;
1032 if(diskwrite(edit->disk, &table, sizeof table, startlba, Toffset) < 0)
1037 p = (Dospart*)edit->part[i];
1044 diskread(disk, &table, sizeof table, startlba, Toffset);
1048 nextebrtype = TypeEMPTY;
1049 if(i+1 >= edit->npart)
1050 nextebrstart = p->ctlend;
1052 Dospart *x = (Dospart*)edit->part[i+1];
1054 nextebrstart = x->ctlstart;
1056 nextebrstart = x->ebrstart;
1057 nextebrtype = x->ebrtype;
1060 ni = wrextend(edit, i+1, xbase, nextebrstart, endlba);
1063 wrtentry(disk, tp, p->type, startlba, p->ctlstart, p->ctlend);
1066 if(nextebrstart != *endlba){
1067 memset(tp, 0, sizeof *tp);
1068 if(nextebrtype == TypeEMPTY)
1069 nextebrtype = mkebrtype(*endlba);
1070 wrtentry(disk, tp, nextebrtype, xbase, nextebrstart, *endlba);
1075 memset(tp, 0, sizeof *tp);
1077 table.magic[0] = Magic0;
1078 table.magic[1] = Magic1;
1080 if(diskwrite(edit->disk, &table, sizeof table, startlba, Toffset) < 0)
1097 diskread(disk, &table, sizeof table, 0, Toffset);
1101 for(i=0; i<edit->npart && tp<ep; ) {
1102 p = (Dospart*)edit->part[i];
1105 wrtentry(disk, tp, p->type, 0, p->ctlstart, p->ctlend);
1109 ni = wrextend(edit, i, p->ebrstart, p->ebrstart, &endlba);
1110 memset(tp, 0, sizeof *tp);
1111 wrtentry(disk, tp, p->ebrtype, 0, p->ebrstart, endlba);
1117 memset(tp, 0, sizeof(*tp));
1119 if(i != edit->npart)
1120 sysfatal("cannot happen #1");
1122 if(diskwrite(disk, &table, sizeof table, 0, Toffset) < 0)
1125 /* bring parts up to date */
1127 for(i=0; i<edit->npart; i++)
1128 plan9print((Dospart*)edit->part[i], -1);
1130 if(ctldiff(edit, disk->ctlfd) < 0)
1131 fprint(2, "?warning: partitions could not be updated in devsd\n");