xref: /plan9-contrib/sys/src/9/boot/parts.c (revision 217e9e83c7f9cc6fb27d97dda90c8339b6f98728)
123173ec1SDavid du Colombier /*
223173ec1SDavid du Colombier  * read disk partition tables, intended for early use on systems
323173ec1SDavid du Colombier  * that don't use 9load.  borrowed from 9load.
423173ec1SDavid du Colombier  */
523173ec1SDavid du Colombier 
623173ec1SDavid du Colombier #include <u.h>
723173ec1SDavid du Colombier #include <libc.h>
823173ec1SDavid du Colombier #include <auth.h>
923173ec1SDavid du Colombier #include <fcall.h>
1023173ec1SDavid du Colombier #include <bio.h>
1123173ec1SDavid du Colombier #include "../boot/boot.h"
1223173ec1SDavid du Colombier 
1323173ec1SDavid du Colombier typedef struct Fs Fs;
1423173ec1SDavid du Colombier #include "/sys/src/boot/pc/dosfs.h"
1523173ec1SDavid du Colombier 
1623173ec1SDavid du Colombier #define	GSHORT(p)	(((p)[1]<<8)|(p)[0])
1723173ec1SDavid du Colombier #define	GLONG(p)	((GSHORT((p)+2)<<16)|GSHORT(p))
1823173ec1SDavid du Colombier 
1923173ec1SDavid du Colombier #define trace 0
2023173ec1SDavid du Colombier 
2123173ec1SDavid du Colombier enum {
2223173ec1SDavid du Colombier 	parttrace = 0,
2323173ec1SDavid du Colombier 
2423173ec1SDavid du Colombier 	Npart = 64,
2523173ec1SDavid du Colombier 	SDnpart = Npart,
2623173ec1SDavid du Colombier 
2723173ec1SDavid du Colombier 	Maxsec = 2048,
2823173ec1SDavid du Colombier 	Cdsec = 2048,
2923173ec1SDavid du Colombier 	Normsec = 512,			/* disks */
3023173ec1SDavid du Colombier 
3123173ec1SDavid du Colombier 	NAMELEN = 256,			/* hack */
3223173ec1SDavid du Colombier };
3323173ec1SDavid du Colombier 
3423173ec1SDavid du Colombier typedef struct SDpart SDpart;
3523173ec1SDavid du Colombier typedef struct SDunit SDunit;
3623173ec1SDavid du Colombier 
3723173ec1SDavid du Colombier typedef struct SDpart {
3823173ec1SDavid du Colombier 	uvlong	start;
3923173ec1SDavid du Colombier 	uvlong	end;
4023173ec1SDavid du Colombier 	char	name[NAMELEN];
4123173ec1SDavid du Colombier 	int	valid;
4223173ec1SDavid du Colombier } SDpart;
4323173ec1SDavid du Colombier 
4423173ec1SDavid du Colombier typedef struct SDunit {
4523173ec1SDavid du Colombier 	int	ctl;			/* fds */
4623173ec1SDavid du Colombier 	int	data;
4723173ec1SDavid du Colombier 
4823173ec1SDavid du Colombier 	char	name[NAMELEN];
4923173ec1SDavid du Colombier 
5023173ec1SDavid du Colombier 	uvlong	sectors;
5123173ec1SDavid du Colombier 	ulong	secsize;
5223173ec1SDavid du Colombier 	SDpart*	part;
5323173ec1SDavid du Colombier 	int	npart;			/* of valid partitions */
5423173ec1SDavid du Colombier } SDunit;
5523173ec1SDavid du Colombier 
5623173ec1SDavid du Colombier static uchar *mbrbuf, *partbuf;
5723173ec1SDavid du Colombier 
5823173ec1SDavid du Colombier static void
sdaddpart(SDunit * unit,char * name,uvlong start,uvlong end)5923173ec1SDavid du Colombier sdaddpart(SDunit* unit, char* name, uvlong start, uvlong end)
6023173ec1SDavid du Colombier {
6123173ec1SDavid du Colombier 	SDpart *pp;
6223173ec1SDavid du Colombier 	int i, partno;
6323173ec1SDavid du Colombier 
6423173ec1SDavid du Colombier 	if(parttrace)
6523173ec1SDavid du Colombier 		print("add %d %s %s %lld %lld\n", unit->npart, unit->name, name, start, end);
6623173ec1SDavid du Colombier 	/*
6723173ec1SDavid du Colombier 	 * Check name not already used
6823173ec1SDavid du Colombier 	 * and look for a free slot.
6923173ec1SDavid du Colombier 	 */
7023173ec1SDavid du Colombier 	if(unit->part != nil){
7123173ec1SDavid du Colombier 		partno = -1;
7223173ec1SDavid du Colombier 		for(i = 0; i < SDnpart; i++){
7323173ec1SDavid du Colombier 			pp = &unit->part[i];
7423173ec1SDavid du Colombier 			if(!pp->valid){
7523173ec1SDavid du Colombier 				if(partno == -1)
7623173ec1SDavid du Colombier 					partno = i;
7723173ec1SDavid du Colombier 				break;
7823173ec1SDavid du Colombier 			}
7923173ec1SDavid du Colombier 			if(strcmp(name, pp->name) == 0){
8023173ec1SDavid du Colombier 				if(pp->start == start && pp->end == end){
8123173ec1SDavid du Colombier 					if(parttrace)
8223173ec1SDavid du Colombier 						print("already present\n");
8323173ec1SDavid du Colombier 					return;
8423173ec1SDavid du Colombier 				}
8523173ec1SDavid du Colombier 			}
8623173ec1SDavid du Colombier 		}
8723173ec1SDavid du Colombier 	}else{
8823173ec1SDavid du Colombier 		if((unit->part = malloc(sizeof(SDpart)*SDnpart)) == nil){
8923173ec1SDavid du Colombier 			if(parttrace)
9023173ec1SDavid du Colombier 				print("malloc failed\n");
9123173ec1SDavid du Colombier 			return;
9223173ec1SDavid du Colombier 		}
9323173ec1SDavid du Colombier 		partno = 0;
9423173ec1SDavid du Colombier 	}
9523173ec1SDavid du Colombier 
9623173ec1SDavid du Colombier 	/*
9723173ec1SDavid du Colombier 	 * Check there is a free slot and size and extent are valid.
9823173ec1SDavid du Colombier 	 */
9923173ec1SDavid du Colombier 	if(partno == -1 || start > end || end > unit->sectors){
10023173ec1SDavid du Colombier 		print("cannot add %s!%s [%llud,%llud) to disk [0,%llud): %s\n",
10123173ec1SDavid du Colombier 			unit->name, name, start, end, unit->sectors,
10223173ec1SDavid du Colombier 			partno==-1 ? "no free partitions" : "partition boundaries out of range");
10323173ec1SDavid du Colombier 		return;
10423173ec1SDavid du Colombier 	}
10523173ec1SDavid du Colombier 	pp = &unit->part[partno];
10623173ec1SDavid du Colombier 	pp->start = start;
10723173ec1SDavid du Colombier 	pp->end = end;
10823173ec1SDavid du Colombier 	strncpy(pp->name, name, NAMELEN);
10923173ec1SDavid du Colombier 	pp->valid = 1;
11023173ec1SDavid du Colombier 	unit->npart++;
11123173ec1SDavid du Colombier 
11223173ec1SDavid du Colombier 	/* update devsd's in-memory partition table */
11323173ec1SDavid du Colombier 	if (fprint(unit->ctl, "part %s %lld %lld\n", name, start, end) < 0)
11489c5a6d2SDavid du Colombier 		fprint(2, "can't update %s's devsd partition table for %s: %r\n",
11589c5a6d2SDavid du Colombier 			unit->name, name);
116*217e9e83SDavid du Colombier 	dprint("part %s %lld %lld\n", name, start, end);
11723173ec1SDavid du Colombier }
11823173ec1SDavid du Colombier 
11923173ec1SDavid du Colombier static long
sdread(SDunit * unit,SDpart * pp,void * va,long len,vlong off)12023173ec1SDavid du Colombier sdread(SDunit *unit, SDpart *pp, void* va, long len, vlong off)
12123173ec1SDavid du Colombier {
122b4124be8SDavid du Colombier 	long l, secsize;
12323173ec1SDavid du Colombier 	uvlong bno, nb;
12423173ec1SDavid du Colombier 
12523173ec1SDavid du Colombier 	/*
12623173ec1SDavid du Colombier 	 * Check the request is within partition bounds.
12723173ec1SDavid du Colombier 	 */
128b4124be8SDavid du Colombier 	secsize = unit->secsize;
129b4124be8SDavid du Colombier 	if (secsize == 0)
13023173ec1SDavid du Colombier 		sysfatal("sdread: zero sector size");
131b4124be8SDavid du Colombier 	bno = off/secsize + pp->start;
132b4124be8SDavid du Colombier 	nb = (off+len+secsize-1)/secsize + pp->start - bno;
13323173ec1SDavid du Colombier 	if(bno+nb > pp->end)
13423173ec1SDavid du Colombier 		nb = pp->end - bno;
13523173ec1SDavid du Colombier 	if(bno >= pp->end || nb == 0)
13623173ec1SDavid du Colombier 		return 0;
13723173ec1SDavid du Colombier 
138b4124be8SDavid du Colombier 	seek(unit->data, bno * secsize, 0);
13923173ec1SDavid du Colombier 	assert(va);				/* "sdread" */
14023173ec1SDavid du Colombier 	l = read(unit->data, va, len);
14123173ec1SDavid du Colombier 	if (l < 0)
14223173ec1SDavid du Colombier 		return 0;
14323173ec1SDavid du Colombier 	return l;
14423173ec1SDavid du Colombier }
14523173ec1SDavid du Colombier 
14623173ec1SDavid du Colombier static int
sdreadblk(SDunit * unit,SDpart * part,void * a,vlong off,int mbr)14723173ec1SDavid du Colombier sdreadblk(SDunit *unit, SDpart *part, void *a, vlong off, int mbr)
14823173ec1SDavid du Colombier {
14923173ec1SDavid du Colombier 	uchar *b;
15023173ec1SDavid du Colombier 
15123173ec1SDavid du Colombier 	assert(a);			/* sdreadblk */
15223173ec1SDavid du Colombier 	if(sdread(unit, part, a, unit->secsize, off) != unit->secsize){
15323173ec1SDavid du Colombier 		if(trace)
15423173ec1SDavid du Colombier 			print("%s: read %lud at %lld failed\n", unit->name,
15523173ec1SDavid du Colombier 				unit->secsize, (vlong)part->start*unit->secsize+off);
15623173ec1SDavid du Colombier 		return -1;
15723173ec1SDavid du Colombier 	}
15823173ec1SDavid du Colombier 	b = a;
15923173ec1SDavid du Colombier 	if(mbr && (b[0x1FE] != 0x55 || b[0x1FF] != 0xAA)){
16023173ec1SDavid du Colombier 		if(trace)
16123173ec1SDavid du Colombier 			print("%s: bad magic %.2ux %.2ux at %lld\n",
16223173ec1SDavid du Colombier 				unit->name, b[0x1FE], b[0x1FF],
16323173ec1SDavid du Colombier 				(vlong)part->start*unit->secsize+off);
16423173ec1SDavid du Colombier 		return -1;
16523173ec1SDavid du Colombier 	}
16623173ec1SDavid du Colombier 	return 0;
16723173ec1SDavid du Colombier }
16823173ec1SDavid du Colombier 
16923173ec1SDavid du Colombier /*
17023173ec1SDavid du Colombier  *  read partition table.  The partition table is just ascii strings.
17123173ec1SDavid du Colombier  */
17223173ec1SDavid du Colombier #define MAGIC "plan9 partitions"
17323173ec1SDavid du Colombier static void
oldp9part(SDunit * unit)17423173ec1SDavid du Colombier oldp9part(SDunit *unit)
17523173ec1SDavid du Colombier {
17623173ec1SDavid du Colombier 	SDpart *pp;
17723173ec1SDavid du Colombier 	char *field[3], *line[Npart+1];
178b4124be8SDavid du Colombier 	ulong n;
179b4124be8SDavid du Colombier 	uvlong start, end;
18023173ec1SDavid du Colombier 	int i;
18123173ec1SDavid du Colombier 
18223173ec1SDavid du Colombier 	/*
18323173ec1SDavid du Colombier 	 *  We have some partitions already.
18423173ec1SDavid du Colombier 	 */
18523173ec1SDavid du Colombier 	pp = &unit->part[unit->npart];
18623173ec1SDavid du Colombier 
18723173ec1SDavid du Colombier 	/*
18823173ec1SDavid du Colombier 	 * We prefer partition tables on the second to last sector,
18923173ec1SDavid du Colombier 	 * but some old disks use the last sector instead.
19023173ec1SDavid du Colombier 	 */
19123173ec1SDavid du Colombier 	strcpy(pp->name, "partition");
19223173ec1SDavid du Colombier 	pp->start = unit->sectors - 2;
19323173ec1SDavid du Colombier 	pp->end = unit->sectors - 1;
19423173ec1SDavid du Colombier 
195*217e9e83SDavid du Colombier 	dprint("oldp9part %s\n", unit->name);
19623173ec1SDavid du Colombier 	if(sdreadblk(unit, pp, partbuf, 0, 0) < 0)
19723173ec1SDavid du Colombier 		return;
19823173ec1SDavid du Colombier 
19923173ec1SDavid du Colombier 	if(strncmp((char*)partbuf, MAGIC, sizeof(MAGIC)-1) != 0) {
20023173ec1SDavid du Colombier 		/* not found on 2nd last sector; look on last sector */
20123173ec1SDavid du Colombier 		pp->start++;
20223173ec1SDavid du Colombier 		pp->end++;
20323173ec1SDavid du Colombier 		if(sdreadblk(unit, pp, partbuf, 0, 0) < 0)
20423173ec1SDavid du Colombier 			return;
20523173ec1SDavid du Colombier 		if(strncmp((char*)partbuf, MAGIC, sizeof(MAGIC)-1) != 0)
20623173ec1SDavid du Colombier 			return;
20723173ec1SDavid du Colombier 		print("%s: using old plan9 partition table on last sector\n", unit->name);
20823173ec1SDavid du Colombier 	}else
20923173ec1SDavid du Colombier 		print("%s: using old plan9 partition table on 2nd-to-last sector\n", unit->name);
21023173ec1SDavid du Colombier 
21123173ec1SDavid du Colombier 	/* we found a partition table, so add a partition partition */
21223173ec1SDavid du Colombier 	unit->npart++;
21323173ec1SDavid du Colombier 	partbuf[unit->secsize-1] = '\0';
21423173ec1SDavid du Colombier 
21523173ec1SDavid du Colombier 	/*
21623173ec1SDavid du Colombier 	 * parse partition table
21723173ec1SDavid du Colombier 	 */
21823173ec1SDavid du Colombier 	n = gettokens((char*)partbuf, line, Npart+1, "\n");
21923173ec1SDavid du Colombier 	if(n && strncmp(line[0], MAGIC, sizeof(MAGIC)-1) == 0){
22023173ec1SDavid du Colombier 		for(i = 1; i < n && unit->npart < SDnpart; i++){
22123173ec1SDavid du Colombier 			if(gettokens(line[i], field, 3, " ") != 3)
22223173ec1SDavid du Colombier 				break;
22323173ec1SDavid du Colombier 			start = strtoull(field[1], 0, 0);
22423173ec1SDavid du Colombier 			end = strtoull(field[2], 0, 0);
22523173ec1SDavid du Colombier 			if(start >= end || end > unit->sectors)
22623173ec1SDavid du Colombier 				break;
22723173ec1SDavid du Colombier 			sdaddpart(unit, field[0], start, end);
22823173ec1SDavid du Colombier 		}
22923173ec1SDavid du Colombier 	}
23023173ec1SDavid du Colombier }
23123173ec1SDavid du Colombier 
23223173ec1SDavid du Colombier static SDpart*
sdfindpart(SDunit * unit,char * name)23323173ec1SDavid du Colombier sdfindpart(SDunit *unit, char *name)
23423173ec1SDavid du Colombier {
23523173ec1SDavid du Colombier 	int i;
23623173ec1SDavid du Colombier 
23723173ec1SDavid du Colombier 	if(parttrace)
238b4124be8SDavid du Colombier 		print("findpart %d %s %s: ", unit->npart, unit->name, name);
23923173ec1SDavid du Colombier 	for(i=0; i<unit->npart; i++) {
24023173ec1SDavid du Colombier 		if(parttrace)
24123173ec1SDavid du Colombier 			print("%s...", unit->part[i].name);
24223173ec1SDavid du Colombier 		if(strcmp(unit->part[i].name, name) == 0){
24323173ec1SDavid du Colombier 			if(parttrace)
24423173ec1SDavid du Colombier 				print("\n");
24523173ec1SDavid du Colombier 			return &unit->part[i];
24623173ec1SDavid du Colombier 		}
24723173ec1SDavid du Colombier 	}
24823173ec1SDavid du Colombier 	if(parttrace)
24923173ec1SDavid du Colombier 		print("not found\n");
25023173ec1SDavid du Colombier 	return nil;
25123173ec1SDavid du Colombier }
25223173ec1SDavid du Colombier 
253b4124be8SDavid du Colombier /*
254b4124be8SDavid du Colombier  * look for a plan 9 partition table on drive `unit' in the second
255b4124be8SDavid du Colombier  * sector (sector 1) of partition `name'.
256b4124be8SDavid du Colombier  * if found, add the partitions defined in the table.
257b4124be8SDavid du Colombier  */
25823173ec1SDavid du Colombier static void
p9part(SDunit * unit,char * name)25923173ec1SDavid du Colombier p9part(SDunit *unit, char *name)
26023173ec1SDavid du Colombier {
26123173ec1SDavid du Colombier 	SDpart *p;
26223173ec1SDavid du Colombier 	char *field[4], *line[Npart+1];
26323173ec1SDavid du Colombier 	uvlong start, end;
26423173ec1SDavid du Colombier 	int i, n;
26523173ec1SDavid du Colombier 
266*217e9e83SDavid du Colombier 	dprint("p9part %s %s\n", unit->name, name);
26723173ec1SDavid du Colombier 	p = sdfindpart(unit, name);
26823173ec1SDavid du Colombier 	if(p == nil)
26923173ec1SDavid du Colombier 		return;
27023173ec1SDavid du Colombier 
27123173ec1SDavid du Colombier 	if(sdreadblk(unit, p, partbuf, unit->secsize, 0) < 0)
27223173ec1SDavid du Colombier 		return;
27323173ec1SDavid du Colombier 	partbuf[unit->secsize-1] = '\0';
27423173ec1SDavid du Colombier 
27523173ec1SDavid du Colombier 	if(strncmp((char*)partbuf, "part ", 5) != 0)
27623173ec1SDavid du Colombier 		return;
27723173ec1SDavid du Colombier 
27823173ec1SDavid du Colombier 	n = gettokens((char*)partbuf, line, Npart+1, "\n");
27923173ec1SDavid du Colombier 	if(n == 0)
28023173ec1SDavid du Colombier 		return;
28123173ec1SDavid du Colombier 	for(i = 0; i < n && unit->npart < SDnpart; i++){
28223173ec1SDavid du Colombier 		if(strncmp(line[i], "part ", 5) != 0)
28323173ec1SDavid du Colombier 			break;
28423173ec1SDavid du Colombier 		if(gettokens(line[i], field, 4, " ") != 4)
28523173ec1SDavid du Colombier 			break;
28623173ec1SDavid du Colombier 		start = strtoull(field[2], 0, 0);
28723173ec1SDavid du Colombier 		end   = strtoull(field[3], 0, 0);
28823173ec1SDavid du Colombier 		if(start >= end || end > unit->sectors)
28923173ec1SDavid du Colombier 			break;
29023173ec1SDavid du Colombier 		sdaddpart(unit, field[1], p->start+start, p->start+end);
29123173ec1SDavid du Colombier 	}
29223173ec1SDavid du Colombier }
29323173ec1SDavid du Colombier 
29423173ec1SDavid du Colombier static int
isdos(int t)29523173ec1SDavid du Colombier isdos(int t)
29623173ec1SDavid du Colombier {
29723173ec1SDavid du Colombier 	return t==FAT12 || t==FAT16 || t==FATHUGE || t==FAT32 || t==FAT32X;
29823173ec1SDavid du Colombier }
29923173ec1SDavid du Colombier 
30023173ec1SDavid du Colombier static int
isextend(int t)30123173ec1SDavid du Colombier isextend(int t)
30223173ec1SDavid du Colombier {
30323173ec1SDavid du Colombier 	return t==EXTEND || t==EXTHUGE || t==LEXTEND;
30423173ec1SDavid du Colombier }
30523173ec1SDavid du Colombier 
30623173ec1SDavid du Colombier /*
30723173ec1SDavid du Colombier  * Fetch the first dos and all plan9 partitions out of the MBR partition table.
30823173ec1SDavid du Colombier  * We return -1 if we did not find a plan9 partition.
30923173ec1SDavid du Colombier  */
31023173ec1SDavid du Colombier static int
mbrpart(SDunit * unit)31123173ec1SDavid du Colombier mbrpart(SDunit *unit)
31223173ec1SDavid du Colombier {
31323173ec1SDavid du Colombier 	Dospart *dp;
314b4124be8SDavid du Colombier 	uvlong taboffset, start, end;
315b4124be8SDavid du Colombier 	uvlong firstxpart, nxtxpart;
31623173ec1SDavid du Colombier 	int havedos, i, nplan9;
31723173ec1SDavid du Colombier 	char name[10];
31823173ec1SDavid du Colombier 
31923173ec1SDavid du Colombier 	taboffset = 0;
32023173ec1SDavid du Colombier 	dp = (Dospart*)&mbrbuf[0x1BE];
32123173ec1SDavid du Colombier 	{
32223173ec1SDavid du Colombier 		/* get the MBR (allowing for DMDDO) */
32323173ec1SDavid du Colombier 		if(sdreadblk(unit, &unit->part[0], mbrbuf,
32423173ec1SDavid du Colombier 		    (vlong)taboffset * unit->secsize, 1) < 0)
32523173ec1SDavid du Colombier 			return -1;
32623173ec1SDavid du Colombier 		for(i=0; i<4; i++)
32723173ec1SDavid du Colombier 			if(dp[i].type == DMDDO) {
32823173ec1SDavid du Colombier 				if(trace)
32923173ec1SDavid du Colombier 					print("DMDDO partition found\n");
33023173ec1SDavid du Colombier 				taboffset = 63;
33123173ec1SDavid du Colombier 				if(sdreadblk(unit, &unit->part[0], mbrbuf,
33223173ec1SDavid du Colombier 				    (vlong)taboffset * unit->secsize, 1) < 0)
33323173ec1SDavid du Colombier 					return -1;
33423173ec1SDavid du Colombier 				i = -1;	/* start over */
33523173ec1SDavid du Colombier 			}
33623173ec1SDavid du Colombier 	}
33723173ec1SDavid du Colombier 
33823173ec1SDavid du Colombier 	/*
33923173ec1SDavid du Colombier 	 * Read the partitions, first from the MBR and then
34023173ec1SDavid du Colombier 	 * from successive extended partition tables.
34123173ec1SDavid du Colombier 	 */
34223173ec1SDavid du Colombier 	nplan9 = 0;
34323173ec1SDavid du Colombier 	havedos = 0;
34423173ec1SDavid du Colombier 	firstxpart = 0;
34523173ec1SDavid du Colombier 	for(;;) {
34623173ec1SDavid du Colombier 		if(sdreadblk(unit, &unit->part[0], mbrbuf,
34723173ec1SDavid du Colombier 		    (vlong)taboffset * unit->secsize, 1) < 0)
34823173ec1SDavid du Colombier 			return -1;
34923173ec1SDavid du Colombier 		if(trace) {
35023173ec1SDavid du Colombier 			if(firstxpart)
351b4124be8SDavid du Colombier 				print("%s ext %llud ", unit->name, taboffset);
35223173ec1SDavid du Colombier 			else
35323173ec1SDavid du Colombier 				print("%s mbr ", unit->name);
35423173ec1SDavid du Colombier 		}
35523173ec1SDavid du Colombier 		nxtxpart = 0;
35623173ec1SDavid du Colombier 		for(i=0; i<4; i++) {
35723173ec1SDavid du Colombier 			if(trace)
35823173ec1SDavid du Colombier 				print("dp %d...", dp[i].type);
35923173ec1SDavid du Colombier 			start = taboffset+GLONG(dp[i].start);
36023173ec1SDavid du Colombier 			end = start+GLONG(dp[i].len);
36123173ec1SDavid du Colombier 
36223173ec1SDavid du Colombier 			if(dp[i].type == PLAN9) {
36323173ec1SDavid du Colombier 				if(nplan9 == 0)
36423173ec1SDavid du Colombier 					strcpy(name, "plan9");
36523173ec1SDavid du Colombier 				else
36623173ec1SDavid du Colombier 					sprint(name, "plan9.%d", nplan9);
36723173ec1SDavid du Colombier 				sdaddpart(unit, name, start, end);
36823173ec1SDavid du Colombier 				p9part(unit, name);
36923173ec1SDavid du Colombier 				nplan9++;
37023173ec1SDavid du Colombier 			}
37123173ec1SDavid du Colombier 
37223173ec1SDavid du Colombier 			/*
37323173ec1SDavid du Colombier 			 * We used to take the active partition (and then the first
37423173ec1SDavid du Colombier 			 * when none are active).  We have to take the first here,
37523173ec1SDavid du Colombier 			 * so that the partition we call ``dos'' agrees with the
37623173ec1SDavid du Colombier 			 * partition disk/fdisk calls ``dos''.
37723173ec1SDavid du Colombier 			 */
37823173ec1SDavid du Colombier 			if(havedos==0 && isdos(dp[i].type)){
37923173ec1SDavid du Colombier 				havedos = 1;
38023173ec1SDavid du Colombier 				sdaddpart(unit, "dos", start, end);
38123173ec1SDavid du Colombier 			}
38223173ec1SDavid du Colombier 
38323173ec1SDavid du Colombier 			/* nxtxpart is relative to firstxpart (or 0), not taboffset */
38423173ec1SDavid du Colombier 			if(isextend(dp[i].type)){
38523173ec1SDavid du Colombier 				nxtxpart = start-taboffset+firstxpart;
38623173ec1SDavid du Colombier 				if(trace)
387b4124be8SDavid du Colombier 					print("link %llud...", nxtxpart);
38823173ec1SDavid du Colombier 			}
38923173ec1SDavid du Colombier 		}
39023173ec1SDavid du Colombier 		if(trace)
39123173ec1SDavid du Colombier 			print("\n");
39223173ec1SDavid du Colombier 
39323173ec1SDavid du Colombier 		if(!nxtxpart)
39423173ec1SDavid du Colombier 			break;
39523173ec1SDavid du Colombier 		if(!firstxpart)
39623173ec1SDavid du Colombier 			firstxpart = nxtxpart;
39723173ec1SDavid du Colombier 		taboffset = nxtxpart;
39823173ec1SDavid du Colombier 	}
39923173ec1SDavid du Colombier 	return nplan9 ? 0 : -1;
40023173ec1SDavid du Colombier }
40123173ec1SDavid du Colombier 
40223173ec1SDavid du Colombier /*
40323173ec1SDavid du Colombier  * To facilitate booting from CDs, we create a partition for
40423173ec1SDavid du Colombier  * the boot floppy image embedded in a bootable CD.
40523173ec1SDavid du Colombier  */
40623173ec1SDavid du Colombier static int
part9660(SDunit * unit)40723173ec1SDavid du Colombier part9660(SDunit *unit)
40823173ec1SDavid du Colombier {
40923173ec1SDavid du Colombier 	uchar buf[Maxsec];
41023173ec1SDavid du Colombier 	ulong a, n;
41123173ec1SDavid du Colombier 	uchar *p;
41223173ec1SDavid du Colombier 
41323173ec1SDavid du Colombier 	if(unit->secsize != Cdsec)
41423173ec1SDavid du Colombier 		return -1;
41523173ec1SDavid du Colombier 
41623173ec1SDavid du Colombier 	if(sdread(unit, &unit->part[0], buf, Cdsec, 17*Cdsec) < 0)
41723173ec1SDavid du Colombier 		return -1;
41823173ec1SDavid du Colombier 
41923173ec1SDavid du Colombier 	if(buf[0] || strcmp((char*)buf+1, "CD001\x01EL TORITO SPECIFICATION") != 0)
42023173ec1SDavid du Colombier 		return -1;
42123173ec1SDavid du Colombier 
42223173ec1SDavid du Colombier 
42323173ec1SDavid du Colombier 	p = buf+0x47;
42423173ec1SDavid du Colombier 	a = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
42523173ec1SDavid du Colombier 
42623173ec1SDavid du Colombier 	if(sdread(unit, &unit->part[0], buf, Cdsec, a*Cdsec) < 0)
42723173ec1SDavid du Colombier 		return -1;
42823173ec1SDavid du Colombier 
42923173ec1SDavid du Colombier 	if(memcmp(buf, "\x01\x00\x00\x00", 4) != 0
43023173ec1SDavid du Colombier 	|| memcmp(buf+30, "\x55\xAA", 2) != 0
43123173ec1SDavid du Colombier 	|| buf[0x20] != 0x88)
43223173ec1SDavid du Colombier 		return -1;
43323173ec1SDavid du Colombier 
43423173ec1SDavid du Colombier 	p = buf+0x28;
43523173ec1SDavid du Colombier 	a = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
43623173ec1SDavid du Colombier 
43723173ec1SDavid du Colombier 	switch(buf[0x21]){
43823173ec1SDavid du Colombier 	case 0x01:
43923173ec1SDavid du Colombier 		n = 1200*1024;
44023173ec1SDavid du Colombier 		break;
44123173ec1SDavid du Colombier 	case 0x02:
44223173ec1SDavid du Colombier 		n = 1440*1024;
44323173ec1SDavid du Colombier 		break;
44423173ec1SDavid du Colombier 	case 0x03:
44523173ec1SDavid du Colombier 		n = 2880*1024;
44623173ec1SDavid du Colombier 		break;
44723173ec1SDavid du Colombier 	default:
44823173ec1SDavid du Colombier 		return -1;
44923173ec1SDavid du Colombier 	}
45023173ec1SDavid du Colombier 	n /= Cdsec;
45123173ec1SDavid du Colombier 
45223173ec1SDavid du Colombier 	print("found partition %s!cdboot; %lud+%lud\n", unit->name, a, n);
45323173ec1SDavid du Colombier 	sdaddpart(unit, "cdboot", a, a+n);
45423173ec1SDavid du Colombier 	return 0;
45523173ec1SDavid du Colombier }
45623173ec1SDavid du Colombier 
45723173ec1SDavid du Colombier enum {
45823173ec1SDavid du Colombier 	NEW = 1<<0,
45923173ec1SDavid du Colombier 	OLD = 1<<1
46023173ec1SDavid du Colombier };
46123173ec1SDavid du Colombier 
46223173ec1SDavid du Colombier /*
46323173ec1SDavid du Colombier  * read unit->data to look for partition tables.
46423173ec1SDavid du Colombier  * if found, stash partitions in environment and write them to ctl too.
46523173ec1SDavid du Colombier  */
46623173ec1SDavid du Colombier static void
partition(SDunit * unit)46723173ec1SDavid du Colombier partition(SDunit *unit)
46823173ec1SDavid du Colombier {
46923173ec1SDavid du Colombier 	int type;
47023173ec1SDavid du Colombier 	char *p;
47123173ec1SDavid du Colombier 
47223173ec1SDavid du Colombier 	if(unit->part == 0)
47323173ec1SDavid du Colombier 		return;
47423173ec1SDavid du Colombier 
47523173ec1SDavid du Colombier 	if(part9660(unit) == 0)
47623173ec1SDavid du Colombier 		return;
47723173ec1SDavid du Colombier 
47823173ec1SDavid du Colombier 	p = getenv("partition");
47923173ec1SDavid du Colombier 	if(p != nil && strncmp(p, "new", 3) == 0)
48023173ec1SDavid du Colombier 		type = NEW;
48123173ec1SDavid du Colombier 	else if(p != nil && strncmp(p, "old", 3) == 0)
48223173ec1SDavid du Colombier 		type = OLD;
48323173ec1SDavid du Colombier 	else
48423173ec1SDavid du Colombier 		type = NEW|OLD;
48523173ec1SDavid du Colombier 
48623173ec1SDavid du Colombier 	if(mbrbuf == nil) {
48723173ec1SDavid du Colombier 		mbrbuf = malloc(Maxsec);
48823173ec1SDavid du Colombier 		partbuf = malloc(Maxsec);
48923173ec1SDavid du Colombier 		if(mbrbuf==nil || partbuf==nil) {
49023173ec1SDavid du Colombier 			free(mbrbuf);
49123173ec1SDavid du Colombier 			free(partbuf);
49223173ec1SDavid du Colombier 			partbuf = mbrbuf = nil;
49323173ec1SDavid du Colombier 			return;
49423173ec1SDavid du Colombier 		}
49523173ec1SDavid du Colombier 	}
49623173ec1SDavid du Colombier 
49723173ec1SDavid du Colombier 	/*
49823173ec1SDavid du Colombier 	 * there might be no mbr (e.g. on a very large device), so look for
49923173ec1SDavid du Colombier 	 * a bare plan 9 partition table if mbrpart fails.
50023173ec1SDavid du Colombier 	 */
50123173ec1SDavid du Colombier 	if((type & NEW) && mbrpart(unit) >= 0){
50223173ec1SDavid du Colombier 		/* nothing to do */
50323173ec1SDavid du Colombier 	}
50423173ec1SDavid du Colombier 	else if (type & NEW)
50523173ec1SDavid du Colombier 		p9part(unit, "data");
50623173ec1SDavid du Colombier 	else if(type & OLD)
50723173ec1SDavid du Colombier 		oldp9part(unit);
50823173ec1SDavid du Colombier }
50923173ec1SDavid du Colombier 
51023173ec1SDavid du Colombier static void
rdgeom(SDunit * unit)51123173ec1SDavid du Colombier rdgeom(SDunit *unit)
51223173ec1SDavid du Colombier {
51323173ec1SDavid du Colombier 	char *line;
51423173ec1SDavid du Colombier 	char *flds[5];
51523173ec1SDavid du Colombier 	Biobuf bb;
51623173ec1SDavid du Colombier 	Biobuf *bp;
51723173ec1SDavid du Colombier 	static char geom[] = "geometry ";
51823173ec1SDavid du Colombier 
51923173ec1SDavid du Colombier 	bp = &bb;
52023173ec1SDavid du Colombier 	seek(unit->ctl, 0, 0);
52123173ec1SDavid du Colombier 	Binit(bp, unit->ctl, OREAD);
52223173ec1SDavid du Colombier 	while((line = Brdline(bp, '\n')) != nil){
52323173ec1SDavid du Colombier 		line[Blinelen(bp) - 1] = '\0';
52423173ec1SDavid du Colombier 		if (strncmp(line, geom, sizeof geom - 1) == 0)
52523173ec1SDavid du Colombier 			break;
52623173ec1SDavid du Colombier 	}
52723173ec1SDavid du Colombier 	if (line != nil && tokenize(line, flds, nelem(flds)) >= 3) {
52823173ec1SDavid du Colombier 		unit->sectors = atoll(flds[1]);
52923173ec1SDavid du Colombier 		unit->secsize = atoll(flds[2]);
53023173ec1SDavid du Colombier 	}
53123173ec1SDavid du Colombier 	Bterm(bp);
53223173ec1SDavid du Colombier 	seek(unit->ctl, 0, 0);
53323173ec1SDavid du Colombier }
53423173ec1SDavid du Colombier 
53523173ec1SDavid du Colombier static void
setpartitions(char * name,int ctl,int data)53623173ec1SDavid du Colombier setpartitions(char *name, int ctl, int data)
53723173ec1SDavid du Colombier {
53823173ec1SDavid du Colombier 	SDunit sdunit;
53923173ec1SDavid du Colombier 	SDunit *unit;
54023173ec1SDavid du Colombier 	SDpart *part0;
54123173ec1SDavid du Colombier 
54223173ec1SDavid du Colombier 	unit = &sdunit;
54323173ec1SDavid du Colombier 	memset(unit, 0, sizeof *unit);
54423173ec1SDavid du Colombier 	unit->ctl = ctl;
54523173ec1SDavid du Colombier 	unit->data = data;
54623173ec1SDavid du Colombier 
54723173ec1SDavid du Colombier 	unit->secsize = Normsec;	/* default: won't work for CDs */
54823173ec1SDavid du Colombier 	unit->sectors = ~0ull;
54923173ec1SDavid du Colombier 	rdgeom(unit);
55023173ec1SDavid du Colombier 	strncpy(unit->name, name, sizeof unit->name);
55123173ec1SDavid du Colombier 	unit->part = mallocz(sizeof(SDpart) * SDnpart, 1);
55223173ec1SDavid du Colombier 
55323173ec1SDavid du Colombier 	part0 = &unit->part[0];
55423173ec1SDavid du Colombier 	part0->end = unit->sectors - 1;
55523173ec1SDavid du Colombier 	strcpy(part0->name, "data");
55623173ec1SDavid du Colombier 	part0->valid = 1;
55723173ec1SDavid du Colombier 	unit->npart++;
55823173ec1SDavid du Colombier 
55923173ec1SDavid du Colombier 	mbrbuf = malloc(Maxsec);
56023173ec1SDavid du Colombier 	partbuf = malloc(Maxsec);
56123173ec1SDavid du Colombier 	partition(unit);
56223173ec1SDavid du Colombier 	free(unit->part);
56323173ec1SDavid du Colombier }
56423173ec1SDavid du Colombier 
56523173ec1SDavid du Colombier /*
56623173ec1SDavid du Colombier  * read disk partition tables so that readnvram via factotum
56723173ec1SDavid du Colombier  * can see them.
56823173ec1SDavid du Colombier  */
56923173ec1SDavid du Colombier int
readparts(void)57023173ec1SDavid du Colombier readparts(void)
57123173ec1SDavid du Colombier {
57223173ec1SDavid du Colombier 	int i, n, ctl, data, fd;
57323173ec1SDavid du Colombier 	char *name, *ctlname, *dataname;
57423173ec1SDavid du Colombier 	Dir *dir;
57523173ec1SDavid du Colombier 
57623173ec1SDavid du Colombier 	fd = open("/dev", OREAD);
57723173ec1SDavid du Colombier 	if(fd < 0)
57823173ec1SDavid du Colombier 		return -1;
57923173ec1SDavid du Colombier 	n = dirreadall(fd, &dir);
58023173ec1SDavid du Colombier 	close(fd);
58123173ec1SDavid du Colombier 
58223173ec1SDavid du Colombier 	for(i = 0; i < n; i++) {
58323173ec1SDavid du Colombier 		name = dir[i].name;
58423173ec1SDavid du Colombier 		if (strncmp(name, "sd", 2) != 0)
58523173ec1SDavid du Colombier 			continue;
58623173ec1SDavid du Colombier 
58723173ec1SDavid du Colombier 		ctlname  = smprint("/dev/%s/ctl", name);
58823173ec1SDavid du Colombier 		dataname = smprint("/dev/%s/data", name);
58923173ec1SDavid du Colombier 		if (ctlname == nil || dataname == nil) {
59023173ec1SDavid du Colombier 			free(ctlname);
59123173ec1SDavid du Colombier 			free(dataname);
59223173ec1SDavid du Colombier 			continue;
59323173ec1SDavid du Colombier 		}
59423173ec1SDavid du Colombier 
59523173ec1SDavid du Colombier 		ctl  = open(ctlname, ORDWR);
59623173ec1SDavid du Colombier 		data = open(dataname, OREAD);
59723173ec1SDavid du Colombier 		free(ctlname);
59823173ec1SDavid du Colombier 		free(dataname);
59923173ec1SDavid du Colombier 
60023173ec1SDavid du Colombier 		if (ctl >= 0 && data >= 0)
60123173ec1SDavid du Colombier 			setpartitions(dataname, ctl, data);
60223173ec1SDavid du Colombier 		close(ctl);
60323173ec1SDavid du Colombier 		close(data);
60423173ec1SDavid du Colombier 	}
60523173ec1SDavid du Colombier 	free(dir);
60623173ec1SDavid du Colombier 	return 0;
60723173ec1SDavid du Colombier }
608