static int sdinitpart(SDunit* unit) { int nf; uvlong start, end; char *f[4], *p, *q, buf[10]; if(unit->sectors > 0){ unit->sectors = unit->secsize = 0; sdincvers(unit); } /* device must be connected or not; other values are trouble */ if(unit->inquiry[0] & 0xC0) /* see SDinq0periphqual */ return 0; switch(unit->inquiry[0] & SDinq0periphtype){ case SDperdisk: case SDperworm: case SDpercd: case SDpermo: break; default: return 0; } if(unit->dev->ifc->online) unit->dev->ifc->online(unit); if(unit->sectors){ sdincvers(unit); sdaddpart(unit, "data", 0, unit->sectors); /* * Use partitions passed from boot program, * e.g. * sdC0part=dos 63 123123/plan9 123123 456456 * This happens before /boot sets hostname so the * partitions will have the null-string for user. * The gen functions patch it up. */ snprint(buf, sizeof buf, "%spart", unit->name); for(p = getconf(buf); p != nil; p = q){ if(q = strchr(p, '/')) *q++ = '\0'; nf = tokenize(p, f, nelem(f)); if(nf < 3) continue; start = strtoull(f[1], 0, 0); end = strtoull(f[2], 0, 0); if(!waserror()){ sdaddpart(unit, f[0], start, end); poperror(); } } } return 1; }
static int sdinitpart(SDunit* unit) { int nf; uvlong start, end; char *f[4], *p, *q, buf[10]; if(unit->sectors > 0){ unit->sectors = unit->secsize = 0; sdincvers(unit); } if(unit->inquiry[0] & 0xC0) return 0; switch(unit->inquiry[0] & 0x1F){ case 0x00: /* DA */ case 0x04: /* WORM */ case 0x05: /* CD-ROM */ case 0x07: /* MO */ break; default: return 0; } if(unit->dev->ifc->online) unit->dev->ifc->online(unit); if(unit->sectors){ sdincvers(unit); sdaddpart(unit, "data", 0, unit->sectors); /* * Use partitions passed from boot program, * e.g. * sdC0part=dos 63 123123/plan9 123123 456456 * This happens before /boot sets hostname so the * partitions will have the null-string for user. * The gen functions patch it up. */ snprint(buf, sizeof buf, "%spart", unit->name); for(p = getconf(buf); p != nil; p = q){ if(q = strchr(p, '/')) *q++ = '\0'; nf = tokenize(p, f, nelem(f)); if(nf < 3) continue; start = strtoull(f[1], 0, 0); end = strtoull(f[2], 0, 0); if(!waserror()){ sdaddpart(unit, f[0], start, end); poperror(); } } } return 1; }
static int sdinitpart(SDunit* unit) { unit->sectors = unit->secsize = 0; unit->npart = 0; if(unit->part){ free(unit->part); unit->part = nil; } if(unit->inquiry[0] & 0xC0) return 0; switch(unit->inquiry[0] & 0x1F){ case 0x00: /* DA */ case 0x04: /* WORM */ case 0x05: /* CD-ROM */ case 0x07: /* MO */ break; default: return 0; } if(unit->dev->ifc->online == nil || unit->dev->ifc->online(unit) == 0) return 0; sdaddpart(unit, "data", 0, unit->sectors); return 1; }
static void p9part(SDunit *unit, char *name) { SDpart *p; char *field[4], *line[Npart+1]; uint32_t start, end; int i, n; p = sdfindpart(unit, name); if(p == nil) return; if(tsdbio(unit, p, partbuf, unit->secsize, 0) < 0) return; partbuf[unit->secsize-1] = '\0'; if(strncmp((char*)partbuf, "part ", 5) != 0) return; n = getfields((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(getfields(line[i], field, 4, ' ') != 4) break; start = strtoul(field[2], 0, 0); end = strtoul(field[3], 0, 0); if(start >= end || end > unit->sectors) break; sdaddpart(unit, field[1], p->start+start, p->start+end); } }
/* * look for a plan 9 partition table on drive `unit' in the second * sector (sector 1) of partition `name'. * if found, add the partitions defined in the table. */ static void p9part(SDunit *unit, char *name) { SDpart *p; char *field[4], *line[Npart+1]; uvlong start, end; int i, n; dprint("p9part %s %s\n", unit->name, name); 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 void oldp9part(SDunit *unit) { SDpart *pp; char *field[3], *line[Npart+1]; ulong n; uvlong 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; dprint("oldp9part %s\n", unit->name); 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); } } }
/* * To facilitate booting from CDs, we create a partition for * the boot floppy image embedded in a bootable CD. */ static int part9660(SDunit *unit) { uint8_t buf[2048]; uint32_t a, n; uint8_t *p; if(unit->secsize != 2048) return -1; if(sdbio(unit, &unit->part[0], buf, 2048, 17*2048) < 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(sdbio(unit, &unit->part[0], buf, 2048, a*2048) < 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 /= 2048; print("found partition %s!cdboot; %lud+%lud\n", unit->name, a, n); sdaddpart(unit, "cdboot", a, a+n); return 0; }
static void psdaddpart(PSDunit* unit, char* name, uvlong start, uvlong end) { int len, nw; sdaddpart(unit, name, start, end); /* update devsd's in-memory partition table. */ len = snprint(buf, sizeof buf, "part %s %lld %lld\n", name, start, end); nw = devtab[unit->ctlc->type]->write(unit->ctlc, buf, len, unit->ctlc->offset); if (nw != len) print("can't update devsd's partition table\n"); if (Debugboot) print("part %s %lld %lld\n", name, start, end); }
/* * 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; uint32_t taboffset, start, end; uint32_t firstxpart, nxtxpart; int havedos, i, nplan9; char name[10]; taboffset = 0; dp = (Dospart*)&mbrbuf[0x1BE]; if(1) { /* get the MBR (allowing for DMDDO) */ if(tsdbio(unit, &unit->part[0], mbrbuf, (int64_t)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(tsdbio(unit, &unit->part[0], mbrbuf, (int64_t)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(tsdbio(unit, &unit->part[0], mbrbuf, (int64_t)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; }
static long sdwrite(Chan* c, void* a, long n, vlong off) { char *f0; int i; uvlong end, start; Cmdbuf *cb; SDifc *ifc; SDreq *req; SDunit *unit; SDev *sdev; switch(TYPE(c->qid)){ default: error(Eperm); case Qtopctl: cb = parsecmd(a, n); if(waserror()){ free(cb); nexterror(); } if(cb->nf == 0) error("empty control message"); f0 = cb->f[0]; cb->f++; cb->nf--; if(strcmp(f0, "config") == 0){ /* wormhole into ugly legacy interface */ legacytopctl(cb); poperror(); free(cb); break; } /* * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb), * where sdifc[i]->name=="ata" and cb contains the args. */ ifc = nil; sdev = nil; for(i=0; sdifc[i]; i++){ if(strcmp(sdifc[i]->name, f0) == 0){ ifc = sdifc[i]; sdev = nil; goto subtopctl; } } /* * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb), * where sdifc[i] and sdev match controller letter "1", * and cb contains the args. */ if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){ if((sdev = sdgetdev(f0[2])) != nil){ ifc = sdev->ifc; goto subtopctl; } } error("unknown interface"); subtopctl: if(waserror()){ if(sdev) decref(&sdev->r); nexterror(); } if(ifc->wtopctl) ifc->wtopctl(sdev, cb); else error(Ebadctl); poperror(); poperror(); if (sdev) decref(&sdev->r); free(cb); break; case Qctl: cb = parsecmd(a, n); sdev = sdgetdev(DEV(c->qid)); if(sdev == nil) error(Enonexist); unit = sdev->unit[UNIT(c->qid)]; qlock(&unit->ctl); if(waserror()){ qunlock(&unit->ctl); decref(&sdev->r); free(cb); nexterror(); } if(unit->vers != c->qid.vers) error(Echange); if(cb->nf < 1) error(Ebadctl); if(strcmp(cb->f[0], "part") == 0){ if(cb->nf != 4) error(Ebadctl); if(unit->sectors == 0 && !sdinitpart(unit)) error(Eio); start = strtoull(cb->f[2], 0, 0); end = strtoull(cb->f[3], 0, 0); sdaddpart(unit, cb->f[1], start, end); } else if(strcmp(cb->f[0], "delpart") == 0){ if(cb->nf != 2 || unit->part == nil) error(Ebadctl); sddelpart(unit, cb->f[1]); } else if(unit->dev->ifc->wctl) unit->dev->ifc->wctl(unit, cb); else error(Ebadctl); qunlock(&unit->ctl); decref(&sdev->r); poperror(); free(cb); break; case Qraw: sdev = sdgetdev(DEV(c->qid)); if(sdev == nil) error(Enonexist); unit = sdev->unit[UNIT(c->qid)]; qlock(&unit->raw); if(waserror()){ qunlock(&unit->raw); decref(&sdev->r); nexterror(); } switch(unit->state){ case Rawcmd: if(n < 6 || n > sizeof(req->cmd)) error(Ebadarg); if((req = malloc(sizeof(SDreq))) == nil) error(Enomem); req->unit = unit; memmove(req->cmd, a, n); req->clen = n; req->flags = SDnosense; req->status = ~0; unit->req = req; unit->state = Rawdata; break; case Rawstatus: unit->state = Rawcmd; free(unit->req); unit->req = nil; error(Ebadusefd); case Rawdata: unit->state = Rawstatus; unit->req->write = 1; n = sdrio(unit->req, a, n); } qunlock(&unit->raw); decref(&sdev->r); poperror(); break; case Qpart: return sdbio(c, 1, a, n, off); } return n; }