174a4d8c2SCharles.Forsyth #include "u.h"
274a4d8c2SCharles.Forsyth #include "lib.h"
374a4d8c2SCharles.Forsyth #include "mem.h"
474a4d8c2SCharles.Forsyth #include "dat.h"
574a4d8c2SCharles.Forsyth #include "fns.h"
674a4d8c2SCharles.Forsyth
774a4d8c2SCharles.Forsyth #include "sd.h"
874a4d8c2SCharles.Forsyth #include "fs.h"
974a4d8c2SCharles.Forsyth
1074a4d8c2SCharles.Forsyth enum {
1174a4d8c2SCharles.Forsyth Npart = 32
1274a4d8c2SCharles.Forsyth };
1374a4d8c2SCharles.Forsyth
1474a4d8c2SCharles.Forsyth uchar *mbrbuf, *partbuf;
1574a4d8c2SCharles.Forsyth int nbuf;
1674a4d8c2SCharles.Forsyth #define trace 0
1774a4d8c2SCharles.Forsyth
1874a4d8c2SCharles.Forsyth int
tsdbio(SDunit * unit,SDpart * part,void * a,vlong off,int mbr)1974a4d8c2SCharles.Forsyth tsdbio(SDunit *unit, SDpart *part, void *a, vlong off, int mbr)
2074a4d8c2SCharles.Forsyth {
2174a4d8c2SCharles.Forsyth uchar *b;
2274a4d8c2SCharles.Forsyth
2374a4d8c2SCharles.Forsyth if(sdbio(unit, part, a, unit->secsize, off) != unit->secsize){
2474a4d8c2SCharles.Forsyth if(trace)
2574a4d8c2SCharles.Forsyth print("%s: read %lud at %lld failed\n", unit->name,
2674a4d8c2SCharles.Forsyth unit->secsize, (vlong)part->start*unit->secsize+off);
2774a4d8c2SCharles.Forsyth return -1;
2874a4d8c2SCharles.Forsyth }
2974a4d8c2SCharles.Forsyth b = a;
3074a4d8c2SCharles.Forsyth if(mbr && (b[0x1FE] != 0x55 || b[0x1FF] != 0xAA)){
3174a4d8c2SCharles.Forsyth if(trace)
3274a4d8c2SCharles.Forsyth print("%s: bad magic %.2ux %.2ux at %lld\n",
3374a4d8c2SCharles.Forsyth unit->name, b[0x1FE], b[0x1FF],
3474a4d8c2SCharles.Forsyth (vlong)part->start*unit->secsize+off);
3574a4d8c2SCharles.Forsyth return -1;
3674a4d8c2SCharles.Forsyth }
3774a4d8c2SCharles.Forsyth return 0;
3874a4d8c2SCharles.Forsyth }
3974a4d8c2SCharles.Forsyth
4074a4d8c2SCharles.Forsyth /*
4174a4d8c2SCharles.Forsyth * read partition table. The partition table is just ascii strings.
4274a4d8c2SCharles.Forsyth */
4374a4d8c2SCharles.Forsyth #define MAGIC "plan9 partitions"
4474a4d8c2SCharles.Forsyth static void
oldp9part(SDunit * unit)4574a4d8c2SCharles.Forsyth oldp9part(SDunit *unit)
4674a4d8c2SCharles.Forsyth {
4774a4d8c2SCharles.Forsyth SDpart *pp;
4874a4d8c2SCharles.Forsyth char *field[3], *line[Npart+1];
4974a4d8c2SCharles.Forsyth ulong n, start, end;
5074a4d8c2SCharles.Forsyth int i;
5174a4d8c2SCharles.Forsyth
5274a4d8c2SCharles.Forsyth /*
5374a4d8c2SCharles.Forsyth * We have some partitions already.
5474a4d8c2SCharles.Forsyth */
5574a4d8c2SCharles.Forsyth pp = &unit->part[unit->npart];
5674a4d8c2SCharles.Forsyth
5774a4d8c2SCharles.Forsyth /*
5874a4d8c2SCharles.Forsyth * We prefer partition tables on the second to last sector,
5974a4d8c2SCharles.Forsyth * but some old disks use the last sector instead.
6074a4d8c2SCharles.Forsyth */
6174a4d8c2SCharles.Forsyth strcpy(pp->name, "partition");
6274a4d8c2SCharles.Forsyth pp->start = unit->sectors - 2;
6374a4d8c2SCharles.Forsyth pp->end = unit->sectors - 1;
6474a4d8c2SCharles.Forsyth
6574a4d8c2SCharles.Forsyth if(tsdbio(unit, pp, partbuf, 0, 0) < 0)
6674a4d8c2SCharles.Forsyth return;
6774a4d8c2SCharles.Forsyth
6874a4d8c2SCharles.Forsyth if(strncmp((char*)partbuf, MAGIC, sizeof(MAGIC)-1) != 0) {
6974a4d8c2SCharles.Forsyth /* not found on 2nd last sector; look on last sector */
7074a4d8c2SCharles.Forsyth pp->start++;
7174a4d8c2SCharles.Forsyth pp->end++;
7274a4d8c2SCharles.Forsyth if(tsdbio(unit, pp, partbuf, 0, 0) < 0)
7374a4d8c2SCharles.Forsyth return;
7474a4d8c2SCharles.Forsyth if(strncmp((char*)partbuf, MAGIC, sizeof(MAGIC)-1) != 0)
7574a4d8c2SCharles.Forsyth return;
7674a4d8c2SCharles.Forsyth print("%s: using old plan9 partition table on last sector\n", unit->name);
7774a4d8c2SCharles.Forsyth }else
7874a4d8c2SCharles.Forsyth print("%s: using old plan9 partition table on 2nd-to-last sector\n", unit->name);
7974a4d8c2SCharles.Forsyth
8074a4d8c2SCharles.Forsyth /* we found a partition table, so add a partition partition */
8174a4d8c2SCharles.Forsyth unit->npart++;
8274a4d8c2SCharles.Forsyth partbuf[unit->secsize-1] = '\0';
8374a4d8c2SCharles.Forsyth
8474a4d8c2SCharles.Forsyth /*
8574a4d8c2SCharles.Forsyth * parse partition table
8674a4d8c2SCharles.Forsyth */
8774a4d8c2SCharles.Forsyth n = getfields((char*)partbuf, line, Npart+1, '\n');
8874a4d8c2SCharles.Forsyth if(n && strncmp(line[0], MAGIC, sizeof(MAGIC)-1) == 0){
8974a4d8c2SCharles.Forsyth for(i = 1; i < n && unit->npart < SDnpart; i++){
9074a4d8c2SCharles.Forsyth if(getfields(line[i], field, 3, ' ') != 3)
9174a4d8c2SCharles.Forsyth break;
92*8a8c2d74SCharles.Forsyth start = strtoull(field[1], 0, 0);
93*8a8c2d74SCharles.Forsyth end = strtoull(field[2], 0, 0);
9474a4d8c2SCharles.Forsyth if(start >= end || end > unit->sectors)
9574a4d8c2SCharles.Forsyth break;
9674a4d8c2SCharles.Forsyth sdaddpart(unit, field[0], start, end);
9774a4d8c2SCharles.Forsyth }
9874a4d8c2SCharles.Forsyth }
9974a4d8c2SCharles.Forsyth }
10074a4d8c2SCharles.Forsyth
10174a4d8c2SCharles.Forsyth static void
p9part(SDunit * unit,char * name)10274a4d8c2SCharles.Forsyth p9part(SDunit *unit, char *name)
10374a4d8c2SCharles.Forsyth {
10474a4d8c2SCharles.Forsyth SDpart *p;
10574a4d8c2SCharles.Forsyth char *field[4], *line[Npart+1];
106*8a8c2d74SCharles.Forsyth uvlong start, end;
10774a4d8c2SCharles.Forsyth int i, n;
10874a4d8c2SCharles.Forsyth
10974a4d8c2SCharles.Forsyth p = sdfindpart(unit, name);
11074a4d8c2SCharles.Forsyth if(p == nil)
11174a4d8c2SCharles.Forsyth return;
11274a4d8c2SCharles.Forsyth
11374a4d8c2SCharles.Forsyth if(tsdbio(unit, p, partbuf, unit->secsize, 0) < 0)
11474a4d8c2SCharles.Forsyth return;
11574a4d8c2SCharles.Forsyth partbuf[unit->secsize-1] = '\0';
11674a4d8c2SCharles.Forsyth
11774a4d8c2SCharles.Forsyth if(strncmp((char*)partbuf, "part ", 5) != 0)
11874a4d8c2SCharles.Forsyth return;
11974a4d8c2SCharles.Forsyth
12074a4d8c2SCharles.Forsyth n = getfields((char*)partbuf, line, Npart+1, '\n');
12174a4d8c2SCharles.Forsyth if(n == 0)
12274a4d8c2SCharles.Forsyth return;
12374a4d8c2SCharles.Forsyth for(i = 0; i < n && unit->npart < SDnpart; i++){
12474a4d8c2SCharles.Forsyth if(strncmp(line[i], "part ", 5) != 0)
12574a4d8c2SCharles.Forsyth break;
12674a4d8c2SCharles.Forsyth if(getfields(line[i], field, 4, ' ') != 4)
12774a4d8c2SCharles.Forsyth break;
128*8a8c2d74SCharles.Forsyth start = strtoull(field[2], 0, 0);
129*8a8c2d74SCharles.Forsyth end = strtoull(field[3], 0, 0);
13074a4d8c2SCharles.Forsyth if(start >= end || end > unit->sectors)
13174a4d8c2SCharles.Forsyth break;
13274a4d8c2SCharles.Forsyth sdaddpart(unit, field[1], p->start+start, p->start+end);
13374a4d8c2SCharles.Forsyth }
13474a4d8c2SCharles.Forsyth }
13574a4d8c2SCharles.Forsyth
13674a4d8c2SCharles.Forsyth int
isdos(int t)13774a4d8c2SCharles.Forsyth isdos(int t)
13874a4d8c2SCharles.Forsyth {
13974a4d8c2SCharles.Forsyth return t==FAT12 || t==FAT16 || t==FATHUGE || t==FAT32 || t==FAT32X;
14074a4d8c2SCharles.Forsyth }
14174a4d8c2SCharles.Forsyth
14274a4d8c2SCharles.Forsyth int
isextend(int t)14374a4d8c2SCharles.Forsyth isextend(int t)
14474a4d8c2SCharles.Forsyth {
14574a4d8c2SCharles.Forsyth return t==EXTEND || t==EXTHUGE || t==LEXTEND;
14674a4d8c2SCharles.Forsyth }
14774a4d8c2SCharles.Forsyth
14874a4d8c2SCharles.Forsyth /*
14974a4d8c2SCharles.Forsyth * Fetch the first dos and all plan9 partitions out of the MBR partition table.
15074a4d8c2SCharles.Forsyth * We return -1 if we did not find a plan9 partition.
15174a4d8c2SCharles.Forsyth */
15274a4d8c2SCharles.Forsyth static int
mbrpart(SDunit * unit)15374a4d8c2SCharles.Forsyth mbrpart(SDunit *unit)
15474a4d8c2SCharles.Forsyth {
15574a4d8c2SCharles.Forsyth Dospart *dp;
15674a4d8c2SCharles.Forsyth ulong taboffset, start, end;
15774a4d8c2SCharles.Forsyth ulong firstxpart, nxtxpart;
15874a4d8c2SCharles.Forsyth int havedos, i, nplan9;
15974a4d8c2SCharles.Forsyth char name[10];
16074a4d8c2SCharles.Forsyth
16174a4d8c2SCharles.Forsyth taboffset = 0;
16274a4d8c2SCharles.Forsyth dp = (Dospart*)&mbrbuf[0x1BE];
16374a4d8c2SCharles.Forsyth if(1) {
16474a4d8c2SCharles.Forsyth /* get the MBR (allowing for DMDDO) */
16574a4d8c2SCharles.Forsyth if(tsdbio(unit, &unit->part[0], mbrbuf, (vlong)taboffset*unit->secsize, 1) < 0)
16674a4d8c2SCharles.Forsyth return -1;
16774a4d8c2SCharles.Forsyth for(i=0; i<4; i++)
16874a4d8c2SCharles.Forsyth if(dp[i].type == DMDDO) {
16974a4d8c2SCharles.Forsyth if(trace)
17074a4d8c2SCharles.Forsyth print("DMDDO partition found\n");
17174a4d8c2SCharles.Forsyth taboffset = 63;
17274a4d8c2SCharles.Forsyth if(tsdbio(unit, &unit->part[0], mbrbuf, (vlong)taboffset*unit->secsize, 1) < 0)
17374a4d8c2SCharles.Forsyth return -1;
17474a4d8c2SCharles.Forsyth i = -1; /* start over */
17574a4d8c2SCharles.Forsyth }
17674a4d8c2SCharles.Forsyth }
17774a4d8c2SCharles.Forsyth
17874a4d8c2SCharles.Forsyth /*
17974a4d8c2SCharles.Forsyth * Read the partitions, first from the MBR and then
18074a4d8c2SCharles.Forsyth * from successive extended partition tables.
18174a4d8c2SCharles.Forsyth */
18274a4d8c2SCharles.Forsyth nplan9 = 0;
18374a4d8c2SCharles.Forsyth havedos = 0;
18474a4d8c2SCharles.Forsyth firstxpart = 0;
18574a4d8c2SCharles.Forsyth for(;;) {
18674a4d8c2SCharles.Forsyth if(tsdbio(unit, &unit->part[0], mbrbuf, (vlong)taboffset*unit->secsize, 1) < 0)
18774a4d8c2SCharles.Forsyth return -1;
18874a4d8c2SCharles.Forsyth if(trace) {
18974a4d8c2SCharles.Forsyth if(firstxpart)
19074a4d8c2SCharles.Forsyth print("%s ext %lud ", unit->name, taboffset);
19174a4d8c2SCharles.Forsyth else
19274a4d8c2SCharles.Forsyth print("%s mbr ", unit->name);
19374a4d8c2SCharles.Forsyth }
19474a4d8c2SCharles.Forsyth nxtxpart = 0;
19574a4d8c2SCharles.Forsyth for(i=0; i<4; i++) {
19674a4d8c2SCharles.Forsyth if(trace)
19774a4d8c2SCharles.Forsyth print("dp %d...", dp[i].type);
19874a4d8c2SCharles.Forsyth start = taboffset+GLONG(dp[i].start);
19974a4d8c2SCharles.Forsyth end = start+GLONG(dp[i].len);
20074a4d8c2SCharles.Forsyth
20174a4d8c2SCharles.Forsyth if(dp[i].type == PLAN9) {
20274a4d8c2SCharles.Forsyth if(nplan9 == 0)
20374a4d8c2SCharles.Forsyth strcpy(name, "plan9");
20474a4d8c2SCharles.Forsyth else
20574a4d8c2SCharles.Forsyth sprint(name, "plan9.%d", nplan9);
20674a4d8c2SCharles.Forsyth sdaddpart(unit, name, start, end);
20774a4d8c2SCharles.Forsyth p9part(unit, name);
20874a4d8c2SCharles.Forsyth nplan9++;
20974a4d8c2SCharles.Forsyth }
21074a4d8c2SCharles.Forsyth
21174a4d8c2SCharles.Forsyth /*
21274a4d8c2SCharles.Forsyth * We used to take the active partition (and then the first
21374a4d8c2SCharles.Forsyth * when none are active). We have to take the first here,
21474a4d8c2SCharles.Forsyth * so that the partition we call ``dos'' agrees with the
21574a4d8c2SCharles.Forsyth * partition disk/fdisk calls ``dos''.
21674a4d8c2SCharles.Forsyth */
21774a4d8c2SCharles.Forsyth if(havedos==0 && isdos(dp[i].type)){
21874a4d8c2SCharles.Forsyth havedos = 1;
21974a4d8c2SCharles.Forsyth sdaddpart(unit, "dos", start, end);
22074a4d8c2SCharles.Forsyth }
22174a4d8c2SCharles.Forsyth
22274a4d8c2SCharles.Forsyth /* nxtxpart is relative to firstxpart (or 0), not taboffset */
22374a4d8c2SCharles.Forsyth if(isextend(dp[i].type)){
22474a4d8c2SCharles.Forsyth nxtxpart = start-taboffset+firstxpart;
22574a4d8c2SCharles.Forsyth if(trace)
22674a4d8c2SCharles.Forsyth print("link %lud...", nxtxpart);
22774a4d8c2SCharles.Forsyth }
22874a4d8c2SCharles.Forsyth }
22974a4d8c2SCharles.Forsyth if(trace)
23074a4d8c2SCharles.Forsyth print("\n");
23174a4d8c2SCharles.Forsyth
23274a4d8c2SCharles.Forsyth if(!nxtxpart)
23374a4d8c2SCharles.Forsyth break;
23474a4d8c2SCharles.Forsyth if(!firstxpart)
23574a4d8c2SCharles.Forsyth firstxpart = nxtxpart;
23674a4d8c2SCharles.Forsyth taboffset = nxtxpart;
23774a4d8c2SCharles.Forsyth }
23874a4d8c2SCharles.Forsyth return nplan9 ? 0 : -1;
23974a4d8c2SCharles.Forsyth }
24074a4d8c2SCharles.Forsyth
24174a4d8c2SCharles.Forsyth /*
24274a4d8c2SCharles.Forsyth * To facilitate booting from CDs, we create a partition for
24374a4d8c2SCharles.Forsyth * the boot floppy image embedded in a bootable CD.
24474a4d8c2SCharles.Forsyth */
24574a4d8c2SCharles.Forsyth static int
part9660(SDunit * unit)24674a4d8c2SCharles.Forsyth part9660(SDunit *unit)
24774a4d8c2SCharles.Forsyth {
24874a4d8c2SCharles.Forsyth uchar buf[2048];
24974a4d8c2SCharles.Forsyth ulong a, n;
25074a4d8c2SCharles.Forsyth uchar *p;
25174a4d8c2SCharles.Forsyth
25274a4d8c2SCharles.Forsyth if(unit->secsize != 2048)
25374a4d8c2SCharles.Forsyth return -1;
25474a4d8c2SCharles.Forsyth
25574a4d8c2SCharles.Forsyth if(sdbio(unit, &unit->part[0], buf, 2048, 17*2048) < 0)
25674a4d8c2SCharles.Forsyth return -1;
25774a4d8c2SCharles.Forsyth
25874a4d8c2SCharles.Forsyth if(buf[0] || strcmp((char*)buf+1, "CD001\x01EL TORITO SPECIFICATION") != 0)
25974a4d8c2SCharles.Forsyth return -1;
26074a4d8c2SCharles.Forsyth
26174a4d8c2SCharles.Forsyth
26274a4d8c2SCharles.Forsyth p = buf+0x47;
26374a4d8c2SCharles.Forsyth a = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
26474a4d8c2SCharles.Forsyth
26574a4d8c2SCharles.Forsyth if(sdbio(unit, &unit->part[0], buf, 2048, a*2048) < 0)
26674a4d8c2SCharles.Forsyth return -1;
26774a4d8c2SCharles.Forsyth
26874a4d8c2SCharles.Forsyth if(memcmp(buf, "\x01\x00\x00\x00", 4) != 0
26974a4d8c2SCharles.Forsyth || memcmp(buf+30, "\x55\xAA", 2) != 0
27074a4d8c2SCharles.Forsyth || buf[0x20] != 0x88)
27174a4d8c2SCharles.Forsyth return -1;
27274a4d8c2SCharles.Forsyth
27374a4d8c2SCharles.Forsyth p = buf+0x28;
27474a4d8c2SCharles.Forsyth a = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
27574a4d8c2SCharles.Forsyth
27674a4d8c2SCharles.Forsyth switch(buf[0x21]){
27774a4d8c2SCharles.Forsyth case 0x01:
27874a4d8c2SCharles.Forsyth n = 1200*1024;
27974a4d8c2SCharles.Forsyth break;
28074a4d8c2SCharles.Forsyth case 0x02:
28174a4d8c2SCharles.Forsyth n = 1440*1024;
28274a4d8c2SCharles.Forsyth break;
28374a4d8c2SCharles.Forsyth case 0x03:
28474a4d8c2SCharles.Forsyth n = 2880*1024;
28574a4d8c2SCharles.Forsyth break;
28674a4d8c2SCharles.Forsyth default:
28774a4d8c2SCharles.Forsyth return -1;
28874a4d8c2SCharles.Forsyth }
28974a4d8c2SCharles.Forsyth n /= 2048;
29074a4d8c2SCharles.Forsyth
29174a4d8c2SCharles.Forsyth print("found partition %s!cdboot; %lud+%lud\n", unit->name, a, n);
29274a4d8c2SCharles.Forsyth sdaddpart(unit, "cdboot", a, a+n);
29374a4d8c2SCharles.Forsyth return 0;
29474a4d8c2SCharles.Forsyth }
29574a4d8c2SCharles.Forsyth
29674a4d8c2SCharles.Forsyth enum {
29774a4d8c2SCharles.Forsyth NEW = 1<<0,
29874a4d8c2SCharles.Forsyth OLD = 1<<1
29974a4d8c2SCharles.Forsyth };
30074a4d8c2SCharles.Forsyth
30174a4d8c2SCharles.Forsyth void
partition(SDunit * unit)30274a4d8c2SCharles.Forsyth partition(SDunit *unit)
30374a4d8c2SCharles.Forsyth {
30474a4d8c2SCharles.Forsyth int type;
30574a4d8c2SCharles.Forsyth char *p;
30674a4d8c2SCharles.Forsyth
30774a4d8c2SCharles.Forsyth if(unit->part == 0)
30874a4d8c2SCharles.Forsyth return;
30974a4d8c2SCharles.Forsyth
31074a4d8c2SCharles.Forsyth if(part9660(unit) == 0)
31174a4d8c2SCharles.Forsyth return;
31274a4d8c2SCharles.Forsyth
31374a4d8c2SCharles.Forsyth p = getconf("partition");
31474a4d8c2SCharles.Forsyth if(p == nil)
31574a4d8c2SCharles.Forsyth p = defaultpartition;
31674a4d8c2SCharles.Forsyth
31774a4d8c2SCharles.Forsyth if(p != nil && strncmp(p, "new", 3) == 0)
31874a4d8c2SCharles.Forsyth type = NEW;
31974a4d8c2SCharles.Forsyth else if(p != nil && strncmp(p, "old", 3) == 0)
32074a4d8c2SCharles.Forsyth type = OLD;
32174a4d8c2SCharles.Forsyth else
32274a4d8c2SCharles.Forsyth type = NEW|OLD;
32374a4d8c2SCharles.Forsyth
32474a4d8c2SCharles.Forsyth if(nbuf < unit->secsize) {
32574a4d8c2SCharles.Forsyth free(mbrbuf);
32674a4d8c2SCharles.Forsyth free(partbuf);
32774a4d8c2SCharles.Forsyth mbrbuf = malloc(unit->secsize);
32874a4d8c2SCharles.Forsyth partbuf = malloc(unit->secsize);
32974a4d8c2SCharles.Forsyth if(mbrbuf==nil || partbuf==nil) {
33074a4d8c2SCharles.Forsyth free(mbrbuf);
33174a4d8c2SCharles.Forsyth free(partbuf);
33274a4d8c2SCharles.Forsyth partbuf = mbrbuf = nil;
33374a4d8c2SCharles.Forsyth nbuf = 0;
33474a4d8c2SCharles.Forsyth return;
33574a4d8c2SCharles.Forsyth }
33674a4d8c2SCharles.Forsyth nbuf = unit->secsize;
33774a4d8c2SCharles.Forsyth }
33874a4d8c2SCharles.Forsyth
33974a4d8c2SCharles.Forsyth if((type & NEW) && mbrpart(unit) >= 0){
34074a4d8c2SCharles.Forsyth /* nothing to do */;
34174a4d8c2SCharles.Forsyth }
34274a4d8c2SCharles.Forsyth else if(type & OLD)
34374a4d8c2SCharles.Forsyth oldp9part(unit);
34474a4d8c2SCharles.Forsyth }
345