xref: /plan9/sys/src/cmd/disk/mbr.c (revision 3ff48bf5ed603850fcd251ddf13025d23d693782)
17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier  * install new master boot record boot code on PC disk.
37dd7cddfSDavid du Colombier  */
47dd7cddfSDavid du Colombier 
57dd7cddfSDavid du Colombier #include <u.h>
67dd7cddfSDavid du Colombier #include <libc.h>
77dd7cddfSDavid du Colombier #include <disk.h>
87dd7cddfSDavid du Colombier 
97dd7cddfSDavid du Colombier enum {
107dd7cddfSDavid du Colombier 	Toffset = 0x1BE	/* offset of partition table */
117dd7cddfSDavid du Colombier };
127dd7cddfSDavid du Colombier 
137dd7cddfSDavid du Colombier /*
147dd7cddfSDavid du Colombier  * Default boot block prints an error message and reboots.
157dd7cddfSDavid du Colombier  */
167dd7cddfSDavid du Colombier static int ndefmbr = Toffset;
177dd7cddfSDavid du Colombier static char defmbr[512] = {
187dd7cddfSDavid du Colombier [0x000]	0xEB, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
197dd7cddfSDavid du Colombier 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
207dd7cddfSDavid du Colombier [0x03E] 0xFA, 0xFC, 0x8C, 0xC8, 0x8E, 0xD8, 0x8E, 0xD0,
217dd7cddfSDavid du Colombier 	0xBC, 0x00, 0x7C, 0xBE, 0x77, 0x7C, 0xE8, 0x19,
227dd7cddfSDavid du Colombier 	0x00, 0x33, 0xC0, 0xCD, 0x16, 0xBB, 0x40, 0x00,
237dd7cddfSDavid du Colombier 	0x8E, 0xC3, 0xBB, 0x72, 0x00, 0xB8, 0x34, 0x12,
247dd7cddfSDavid du Colombier 	0x26, 0x89, 0x07, 0xEA, 0x00, 0x00, 0xFF, 0xFF,
257dd7cddfSDavid du Colombier 	0xEB, 0xD6, 0xAC, 0x0A, 0xC0, 0x74, 0x09, 0xB4,
267dd7cddfSDavid du Colombier 	0x0E, 0xBB, 0x07, 0x00, 0xCD, 0x10, 0xEB, 0xF2,
277dd7cddfSDavid du Colombier 	0xC3,  'N',  'o',  't',  ' ',  'a',  ' ',  'b',
287dd7cddfSDavid du Colombier 	 'o',  'o',  't',  'a',  'b',  'l',  'e',  ' ',
297dd7cddfSDavid du Colombier 	 'd',  'i',  's',  'c',  ' ',  'o',  'r',  ' ',
307dd7cddfSDavid du Colombier 	 'd',  'i',  's',  'c',  ' ',  'e',  'r',  'r',
317dd7cddfSDavid du Colombier 	 'o',  'r', '\r', '\n',  'P',  'r',  'e',  's',
327dd7cddfSDavid du Colombier 	 's',  ' ',  'a',  'l',  'm',  'o',  's',  't',
337dd7cddfSDavid du Colombier 	 ' ',  'a',  'n',  'y',  ' ',  'k',  'e',  'y',
347dd7cddfSDavid du Colombier 	 ' ',  't',  'o',  ' ',  'r',  'e',  'b',  'o',
357dd7cddfSDavid du Colombier 	 'o',  't',  '.',  '.',  '.', 0x00, 0x00, 0x00,
367dd7cddfSDavid du Colombier };
377dd7cddfSDavid du Colombier 
387dd7cddfSDavid du Colombier void
397dd7cddfSDavid du Colombier usage(void)
407dd7cddfSDavid du Colombier {
417dd7cddfSDavid du Colombier 	fprint(2, "usage: disk/mbr [-m mbrfile] disk\n");
427dd7cddfSDavid du Colombier 	exits("usage");
437dd7cddfSDavid du Colombier }
447dd7cddfSDavid du Colombier 
457dd7cddfSDavid du Colombier void
467dd7cddfSDavid du Colombier fatal(char *fmt, ...)
477dd7cddfSDavid du Colombier {
489a747e4fSDavid du Colombier 	char err[ERRMAX];
497dd7cddfSDavid du Colombier 	va_list arg;
507dd7cddfSDavid du Colombier 
517dd7cddfSDavid du Colombier 	va_start(arg, fmt);
529a747e4fSDavid du Colombier 	vsnprint(err, ERRMAX, fmt, arg);
537dd7cddfSDavid du Colombier 	va_end(arg);
547dd7cddfSDavid du Colombier 	fprint(2, "mbr: %s\n", err);
557dd7cddfSDavid du Colombier 	exits(err);
567dd7cddfSDavid du Colombier }
577dd7cddfSDavid du Colombier 
587dd7cddfSDavid du Colombier void
597dd7cddfSDavid du Colombier main(int argc, char **argv)
607dd7cddfSDavid du Colombier {
617dd7cddfSDavid du Colombier 	Disk *disk;
627dd7cddfSDavid du Colombier 	uchar *mbr, *buf;
637dd7cddfSDavid du Colombier 	char *mbrfile;
647dd7cddfSDavid du Colombier 	ulong secsize;
657dd7cddfSDavid du Colombier 	int sysfd, nmbr;
667dd7cddfSDavid du Colombier 
677dd7cddfSDavid du Colombier 	mbrfile = nil;
687dd7cddfSDavid du Colombier 	ARGBEGIN {
697dd7cddfSDavid du Colombier 	case 'm':
707dd7cddfSDavid du Colombier 		mbrfile = ARGF();
717dd7cddfSDavid du Colombier 		break;
727dd7cddfSDavid du Colombier 	default:
737dd7cddfSDavid du Colombier 		usage();
747dd7cddfSDavid du Colombier 	} ARGEND
757dd7cddfSDavid du Colombier 
767dd7cddfSDavid du Colombier 	if(argc < 1)
777dd7cddfSDavid du Colombier 		usage();
787dd7cddfSDavid du Colombier 
797dd7cddfSDavid du Colombier 	disk = opendisk(argv[0], 0, 0);
807dd7cddfSDavid du Colombier 	if(disk == nil)
817dd7cddfSDavid du Colombier 		fatal("opendisk %s: %r", argv[0]);
827dd7cddfSDavid du Colombier 
837dd7cddfSDavid du Colombier 	if(disk->type == Tfloppy)
847dd7cddfSDavid du Colombier 		fatal("will not install mbr on floppy");
857dd7cddfSDavid du Colombier 	if(disk->secsize != 512)
867dd7cddfSDavid du Colombier 		fatal("secsize %d invalid", disk->secsize);
877dd7cddfSDavid du Colombier 
887dd7cddfSDavid du Colombier 	secsize = disk->secsize;
89*3ff48bf5SDavid du Colombier 	buf = malloc(secsize*(disk->s+1));
90*3ff48bf5SDavid du Colombier 	mbr = malloc(secsize*disk->s);
917dd7cddfSDavid du Colombier 	if(buf == nil || mbr == nil)
927dd7cddfSDavid du Colombier 		fatal("out of memory");
937dd7cddfSDavid du Colombier 
947dd7cddfSDavid du Colombier 	/*
957dd7cddfSDavid du Colombier 	 * Start with initial sector from disk.
967dd7cddfSDavid du Colombier 	 */
977dd7cddfSDavid du Colombier 	if(seek(disk->fd, 0, 0) < 0)
987dd7cddfSDavid du Colombier 		fatal("seek to boot sector: %r\n");
997dd7cddfSDavid du Colombier 	if(read(disk->fd, mbr, secsize) != secsize)
1007dd7cddfSDavid du Colombier 		fatal("reading boot sector: %r");
1017dd7cddfSDavid du Colombier 
1027dd7cddfSDavid du Colombier 	if(mbrfile == nil){
1037dd7cddfSDavid du Colombier 		nmbr = ndefmbr;
1047dd7cddfSDavid du Colombier 		memmove(mbr, defmbr, nmbr);
1057dd7cddfSDavid du Colombier 	} else {
106*3ff48bf5SDavid du Colombier 		memset(buf, 0, secsize*disk->s);
1077dd7cddfSDavid du Colombier 		if((sysfd = open(mbrfile, OREAD)) < 0)
1087dd7cddfSDavid du Colombier 			fatal("open %s: %r", mbrfile);
109*3ff48bf5SDavid du Colombier 		if((nmbr = read(sysfd, buf, secsize*(disk->s+1))) < 0)
1107dd7cddfSDavid du Colombier 			fatal("read %s: %r", mbrfile);
111*3ff48bf5SDavid du Colombier 		if(nmbr > secsize*disk->s)
112*3ff48bf5SDavid du Colombier 			fatal("master boot record too large %d > %d", nmbr, secsize*disk->s);
113*3ff48bf5SDavid du Colombier 		if(nmbr < secsize)
114*3ff48bf5SDavid du Colombier 			nmbr = secsize;
1157dd7cddfSDavid du Colombier 		close(sysfd);
116*3ff48bf5SDavid du Colombier 		memmove(buf+Toffset, mbr+Toffset, secsize-Toffset);
1177dd7cddfSDavid du Colombier 		memmove(mbr, buf, nmbr);
1187dd7cddfSDavid du Colombier 	}
1197dd7cddfSDavid du Colombier 	mbr[secsize-2] = 0x55;
1207dd7cddfSDavid du Colombier 	mbr[secsize-1] = 0xAA;
121*3ff48bf5SDavid du Colombier 	nmbr = (nmbr+secsize-1)&~(secsize-1);
1227dd7cddfSDavid du Colombier 	if(seek(disk->wfd, 0, 0) < 0)
1237dd7cddfSDavid du Colombier 		fatal("seek to MBR sector: %r\n");
124*3ff48bf5SDavid du Colombier 	if(write(disk->wfd, mbr, nmbr) != nmbr)
1257dd7cddfSDavid du Colombier 		fatal("writing MBR: %r");
1267dd7cddfSDavid du Colombier 
1277dd7cddfSDavid du Colombier 	exits(0);
1287dd7cddfSDavid du Colombier }
129