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