123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596 |
- /*
- * read disk partition tables, intended for early use on systems
- * that don't use 9load. borrowed from 9load.
- */
- #include <u.h>
- #include <libc.h>
- #include <auth.h>
- #include <fcall.h>
- #include <bio.h>
- #include "../boot/boot.h"
- typedef struct Fs Fs;
- #include "/sys/src/boot/pc/dosfs.h"
- #define GSHORT(p) (((p)[1]<<8)|(p)[0])
- #define GLONG(p) ((GSHORT((p)+2)<<16)|GSHORT(p))
- #define trace 0
- enum {
- parttrace = 0,
- Npart = 64,
- SDnpart = Npart,
- Maxsec = 2048,
- Cdsec = 2048,
- Normsec = 512, /* disks */
- NAMELEN = 256, /* hack */
- };
- typedef struct SDpart SDpart;
- typedef struct SDunit SDunit;
- typedef struct SDpart {
- uvlong start;
- uvlong end;
- char name[NAMELEN];
- int valid;
- } SDpart;
- typedef struct SDunit {
- int ctl; /* fds */
- int data;
- char name[NAMELEN];
- uvlong sectors;
- ulong secsize;
- SDpart* part;
- int npart; /* of valid partitions */
- } SDunit;
- static uchar *mbrbuf, *partbuf;
- static void
- sdaddpart(SDunit* unit, char* name, uvlong start, uvlong end)
- {
- SDpart *pp;
- int i, partno;
- if(parttrace)
- print("add %d %s %s %lld %lld\n", unit->npart, unit->name, name, start, end);
- /*
- * Check name not already used
- * and look for a free slot.
- */
- if(unit->part != nil){
- partno = -1;
- for(i = 0; i < SDnpart; i++){
- pp = &unit->part[i];
- if(!pp->valid){
- if(partno == -1)
- partno = i;
- break;
- }
- if(strcmp(name, pp->name) == 0){
- if(pp->start == start && pp->end == end){
- if(parttrace)
- print("already present\n");
- return;
- }
- }
- }
- }else{
- if((unit->part = malloc(sizeof(SDpart)*SDnpart)) == nil){
- if(parttrace)
- print("malloc failed\n");
- return;
- }
- partno = 0;
- }
- /*
- * Check there is a free slot and size and extent are valid.
- */
- if(partno == -1 || start > end || end > unit->sectors){
- print("cannot add %s!%s [%llud,%llud) to disk [0,%llud): %s\n",
- unit->name, name, start, end, unit->sectors,
- partno==-1 ? "no free partitions" : "partition boundaries out of range");
- return;
- }
- pp = &unit->part[partno];
- pp->start = start;
- pp->end = end;
- strncpy(pp->name, name, NAMELEN);
- pp->valid = 1;
- unit->npart++;
- /* update devsd's in-memory partition table */
- if (fprint(unit->ctl, "part %s %lld %lld\n", name, start, end) < 0)
- fprint(2, "can't update devsd's partition table\n");
- }
- static long
- sdread(SDunit *unit, SDpart *pp, void* va, long len, vlong off)
- {
- long l;
- uvlong bno, nb;
- /*
- * Check the request is within partition bounds.
- */
- if (unit->secsize == 0)
- sysfatal("sdread: zero sector size");
- bno = (off/unit->secsize) + pp->start;
- nb = ((off+len+unit->secsize-1)/unit->secsize) + pp->start - bno;
- if(bno+nb > pp->end)
- nb = pp->end - bno;
- if(bno >= pp->end || nb == 0)
- return 0;
- seek(unit->data, off, 0);
- assert(va); /* "sdread" */
- l = read(unit->data, va, len);
- if (l < 0)
- return 0;
- return l;
- }
- static int
- sdreadblk(SDunit *unit, SDpart *part, void *a, vlong off, int mbr)
- {
- uchar *b;
- assert(a); /* sdreadblk */
- if(sdread(unit, part, a, unit->secsize, off) != unit->secsize){
- if(trace)
- print("%s: read %lud at %lld failed\n", unit->name,
- unit->secsize, (vlong)part->start*unit->secsize+off);
- return -1;
- }
- b = a;
- if(mbr && (b[0x1FE] != 0x55 || b[0x1FF] != 0xAA)){
- if(trace)
- print("%s: bad magic %.2ux %.2ux at %lld\n",
- unit->name, b[0x1FE], b[0x1FF],
- (vlong)part->start*unit->secsize+off);
- return -1;
- }
- return 0;
- }
- /*
- * read partition table. The partition table is just ascii strings.
- */
- #define MAGIC "plan9 partitions"
- static void
- oldp9part(SDunit *unit)
- {
- SDpart *pp;
- char *field[3], *line[Npart+1];
- ulong n, start, end;
- int i;
- /*
- * We have some partitions already.
- */
- pp = &unit->part[unit->npart];
- /*
- * We prefer partition tables on the second to last sector,
- * but some old disks use the last sector instead.
- */
- strcpy(pp->name, "partition");
- pp->start = unit->sectors - 2;
- pp->end = unit->sectors - 1;
- if(sdreadblk(unit, pp, partbuf, 0, 0) < 0)
- return;
- if(strncmp((char*)partbuf, MAGIC, sizeof(MAGIC)-1) != 0) {
- /* not found on 2nd last sector; look on last sector */
- pp->start++;
- pp->end++;
- if(sdreadblk(unit, pp, partbuf, 0, 0) < 0)
- return;
- if(strncmp((char*)partbuf, MAGIC, sizeof(MAGIC)-1) != 0)
- return;
- print("%s: using old plan9 partition table on last sector\n", unit->name);
- }else
- print("%s: using old plan9 partition table on 2nd-to-last sector\n", unit->name);
- /* we found a partition table, so add a partition partition */
- unit->npart++;
- partbuf[unit->secsize-1] = '\0';
- /*
- * parse partition table
- */
- n = gettokens((char*)partbuf, line, Npart+1, "\n");
- if(n && strncmp(line[0], MAGIC, sizeof(MAGIC)-1) == 0){
- for(i = 1; i < n && unit->npart < SDnpart; i++){
- if(gettokens(line[i], field, 3, " ") != 3)
- break;
- start = strtoull(field[1], 0, 0);
- end = strtoull(field[2], 0, 0);
- if(start >= end || end > unit->sectors)
- break;
- sdaddpart(unit, field[0], start, end);
- }
- }
- }
- static SDpart*
- sdfindpart(SDunit *unit, char *name)
- {
- int i;
- if(parttrace)
- print("findpart %d %s %s\t\n", unit->npart, unit->name, name);
- for(i=0; i<unit->npart; i++) {
- if(parttrace)
- print("%s...", unit->part[i].name);
- if(strcmp(unit->part[i].name, name) == 0){
- if(parttrace)
- print("\n");
- return &unit->part[i];
- }
- }
- if(parttrace)
- print("not found\n");
- return nil;
- }
- static void
- p9part(SDunit *unit, char *name)
- {
- SDpart *p;
- char *field[4], *line[Npart+1];
- uvlong start, end;
- int i, n;
- p = sdfindpart(unit, name);
- if(p == nil)
- return;
- if(sdreadblk(unit, p, partbuf, unit->secsize, 0) < 0)
- return;
- partbuf[unit->secsize-1] = '\0';
- if(strncmp((char*)partbuf, "part ", 5) != 0)
- return;
- n = gettokens((char*)partbuf, line, Npart+1, "\n");
- if(n == 0)
- return;
- for(i = 0; i < n && unit->npart < SDnpart; i++){
- if(strncmp(line[i], "part ", 5) != 0)
- break;
- if(gettokens(line[i], field, 4, " ") != 4)
- break;
- start = strtoull(field[2], 0, 0);
- end = strtoull(field[3], 0, 0);
- if(start >= end || end > unit->sectors)
- break;
- sdaddpart(unit, field[1], p->start+start, p->start+end);
- }
- }
- static int
- isdos(int t)
- {
- return t==FAT12 || t==FAT16 || t==FATHUGE || t==FAT32 || t==FAT32X;
- }
- static int
- isextend(int t)
- {
- return t==EXTEND || t==EXTHUGE || t==LEXTEND;
- }
- /*
- * Fetch the first dos and all plan9 partitions out of the MBR partition table.
- * We return -1 if we did not find a plan9 partition.
- */
- static int
- mbrpart(SDunit *unit)
- {
- Dospart *dp;
- ulong taboffset, start, end;
- ulong firstxpart, nxtxpart;
- int havedos, i, nplan9;
- char name[10];
- taboffset = 0;
- dp = (Dospart*)&mbrbuf[0x1BE];
- {
- /* get the MBR (allowing for DMDDO) */
- if(sdreadblk(unit, &unit->part[0], mbrbuf,
- (vlong)taboffset * unit->secsize, 1) < 0)
- return -1;
- for(i=0; i<4; i++)
- if(dp[i].type == DMDDO) {
- if(trace)
- print("DMDDO partition found\n");
- taboffset = 63;
- if(sdreadblk(unit, &unit->part[0], mbrbuf,
- (vlong)taboffset * unit->secsize, 1) < 0)
- return -1;
- i = -1; /* start over */
- }
- }
- /*
- * Read the partitions, first from the MBR and then
- * from successive extended partition tables.
- */
- nplan9 = 0;
- havedos = 0;
- firstxpart = 0;
- for(;;) {
- if(sdreadblk(unit, &unit->part[0], mbrbuf,
- (vlong)taboffset * unit->secsize, 1) < 0)
- return -1;
- if(trace) {
- if(firstxpart)
- print("%s ext %lud ", unit->name, taboffset);
- else
- print("%s mbr ", unit->name);
- }
- nxtxpart = 0;
- for(i=0; i<4; i++) {
- if(trace)
- print("dp %d...", dp[i].type);
- start = taboffset+GLONG(dp[i].start);
- end = start+GLONG(dp[i].len);
- if(dp[i].type == PLAN9) {
- if(nplan9 == 0)
- strcpy(name, "plan9");
- else
- sprint(name, "plan9.%d", nplan9);
- sdaddpart(unit, name, start, end);
- p9part(unit, name);
- nplan9++;
- }
- /*
- * We used to take the active partition (and then the first
- * when none are active). We have to take the first here,
- * so that the partition we call ``dos'' agrees with the
- * partition disk/fdisk calls ``dos''.
- */
- if(havedos==0 && isdos(dp[i].type)){
- havedos = 1;
- sdaddpart(unit, "dos", start, end);
- }
- /* nxtxpart is relative to firstxpart (or 0), not taboffset */
- if(isextend(dp[i].type)){
- nxtxpart = start-taboffset+firstxpart;
- if(trace)
- print("link %lud...", nxtxpart);
- }
- }
- if(trace)
- print("\n");
- if(!nxtxpart)
- break;
- if(!firstxpart)
- firstxpart = nxtxpart;
- taboffset = nxtxpart;
- }
- return nplan9 ? 0 : -1;
- }
- /*
- * To facilitate booting from CDs, we create a partition for
- * the boot floppy image embedded in a bootable CD.
- */
- static int
- part9660(SDunit *unit)
- {
- uchar buf[Maxsec];
- ulong a, n;
- uchar *p;
- if(unit->secsize != Cdsec)
- return -1;
- if(sdread(unit, &unit->part[0], buf, Cdsec, 17*Cdsec) < 0)
- return -1;
- if(buf[0] || strcmp((char*)buf+1, "CD001\x01EL TORITO SPECIFICATION") != 0)
- return -1;
-
- p = buf+0x47;
- a = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
- if(sdread(unit, &unit->part[0], buf, Cdsec, a*Cdsec) < 0)
- return -1;
- if(memcmp(buf, "\x01\x00\x00\x00", 4) != 0
- || memcmp(buf+30, "\x55\xAA", 2) != 0
- || buf[0x20] != 0x88)
- return -1;
- p = buf+0x28;
- a = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
- switch(buf[0x21]){
- case 0x01:
- n = 1200*1024;
- break;
- case 0x02:
- n = 1440*1024;
- break;
- case 0x03:
- n = 2880*1024;
- break;
- default:
- return -1;
- }
- n /= Cdsec;
- print("found partition %s!cdboot; %lud+%lud\n", unit->name, a, n);
- sdaddpart(unit, "cdboot", a, a+n);
- return 0;
- }
- enum {
- NEW = 1<<0,
- OLD = 1<<1
- };
- /*
- * read unit->data to look for partition tables.
- * if found, stash partitions in environment and write them to ctl too.
- */
- static void
- partition(SDunit *unit)
- {
- int type;
- char *p;
- if(unit->part == 0)
- return;
- if(part9660(unit) == 0)
- return;
- p = getenv("partition");
- if(p != nil && strncmp(p, "new", 3) == 0)
- type = NEW;
- else if(p != nil && strncmp(p, "old", 3) == 0)
- type = OLD;
- else
- type = NEW|OLD;
- if(mbrbuf == nil) {
- mbrbuf = malloc(Maxsec);
- partbuf = malloc(Maxsec);
- if(mbrbuf==nil || partbuf==nil) {
- free(mbrbuf);
- free(partbuf);
- partbuf = mbrbuf = nil;
- return;
- }
- }
- /*
- * there might be no mbr (e.g. on a very large device), so look for
- * a bare plan 9 partition table if mbrpart fails.
- */
- if((type & NEW) && mbrpart(unit) >= 0){
- /* nothing to do */
- }
- else if (type & NEW)
- p9part(unit, "data");
- else if(type & OLD)
- oldp9part(unit);
- }
- static void
- rdgeom(SDunit *unit)
- {
- char *line;
- char *flds[5];
- Biobuf bb;
- Biobuf *bp;
- static char geom[] = "geometry ";
- bp = &bb;
- seek(unit->ctl, 0, 0);
- Binit(bp, unit->ctl, OREAD);
- while((line = Brdline(bp, '\n')) != nil){
- line[Blinelen(bp) - 1] = '\0';
- if (strncmp(line, geom, sizeof geom - 1) == 0)
- break;
- }
- if (line != nil && tokenize(line, flds, nelem(flds)) >= 3) {
- unit->sectors = atoll(flds[1]);
- unit->secsize = atoll(flds[2]);
- }
- Bterm(bp);
- seek(unit->ctl, 0, 0);
- }
- static void
- setpartitions(char *name, int ctl, int data)
- {
- SDunit sdunit;
- SDunit *unit;
- SDpart *part0;
- unit = &sdunit;
- memset(unit, 0, sizeof *unit);
- unit->ctl = ctl;
- unit->data = data;
- unit->secsize = Normsec; /* default: won't work for CDs */
- unit->sectors = ~0ull;
- rdgeom(unit);
- strncpy(unit->name, name, sizeof unit->name);
- unit->part = mallocz(sizeof(SDpart) * SDnpart, 1);
- part0 = &unit->part[0];
- part0->end = unit->sectors - 1;
- strcpy(part0->name, "data");
- part0->valid = 1;
- unit->npart++;
- mbrbuf = malloc(Maxsec);
- partbuf = malloc(Maxsec);
- partition(unit);
- free(unit->part);
- }
- /*
- * read disk partition tables so that readnvram via factotum
- * can see them.
- */
- int
- readparts(void)
- {
- int i, n, ctl, data, fd;
- char *name, *ctlname, *dataname;
- Dir *dir;
- fd = open("/dev", OREAD);
- if(fd < 0)
- return -1;
- n = dirreadall(fd, &dir);
- close(fd);
- for(i = 0; i < n; i++) {
- name = dir[i].name;
- if (strncmp(name, "sd", 2) != 0)
- continue;
- ctlname = smprint("/dev/%s/ctl", name);
- dataname = smprint("/dev/%s/data", name);
- if (ctlname == nil || dataname == nil) {
- free(ctlname);
- free(dataname);
- continue;
- }
- ctl = open(ctlname, ORDWR);
- data = open(dataname, OREAD);
- free(ctlname);
- free(dataname);
- if (ctl >= 0 && data >= 0)
- setpartitions(dataname, ctl, data);
- close(ctl);
- close(data);
- }
- free(dir);
- return 0;
- }
|