123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- /*
- * partfs - serve an underlying file, with devsd-style partitions
- */
- #include <u.h>
- #include <libc.h>
- #include <auth.h>
- #include <fcall.h>
- #include <thread.h>
- #include <9p.h>
- typedef struct Part Part;
- struct Part
- {
- int inuse;
- int vers;
- uint32_t mode;
- char *name;
- int64_t offset; /* in sectors */
- int64_t length; /* in sectors */
- };
- enum
- {
- Qroot = 0,
- Qdir,
- Qctl,
- Qpart,
- };
- int fd = -1, ctlfd = -1;
- int rdonly;
- uint32_t ctlmode = 0666;
- uint32_t time0;
- int64_t nsect, sectsize;
- char *inquiry = "partfs hard drive";
- char *sdname = "sdXX";
- Part tab[64];
- char*
- ctlstring(void)
- {
- Part *p;
- Fmt fmt;
- fmtstrinit(&fmt);
- fmtprint(&fmt, "inquiry %s\n", inquiry);
- fmtprint(&fmt, "geometry %lld %lld\n", nsect, sectsize);
- for (p = tab; p < tab + nelem(tab); p++)
- if (p->inuse)
- fmtprint(&fmt, "part %s %lld %lld\n",
- p->name, p->offset, p->length);
- return fmtstrflush(&fmt);
- }
- int
- addpart(char *name, int64_t start, int64_t end)
- {
- Part *p;
- if(start < 0 || start > end || end > nsect){
- werrstr("bad partition boundaries");
- return -1;
- }
- if (strcmp(name, "ctl") == 0 || strcmp(name, "data") == 0) {
- werrstr("partition name already in use");
- return -1;
- }
- for (p = tab; p < tab + nelem(tab) && p->inuse; p++)
- if (strcmp(p->name, name) == 0) {
- werrstr("partition name already in use");
- return -1;
- }
- if(p == tab + nelem(tab)){
- werrstr("no free partition slots");
- return -1;
- }
- p->inuse = 1;
- free(p->name);
- p->name = estrdup9p(name);
- p->offset = start;
- p->length = end - start;
- p->mode = ctlmode;
- p->vers++;
- return 0;
- }
- int
- delpart(char *s)
- {
- Part *p;
- for (p = tab; p < tab + nelem(tab); p++)
- if(p->inuse && strcmp(p->name, s) == 0)
- break;
- if(p == tab + nelem(tab)){
- werrstr("partition not found");
- return -1;
- }
- p->inuse = 0;
- free(p->name);
- p->name = nil;
- return 0;
- }
- static void
- addparts(char *buf)
- {
- char *f[4], *p, *q;
- /*
- * 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.
- */
- for(p = buf; p != nil; p = q){
- if(q = strchr(p, '/'))
- *q++ = '\0';
- if(tokenize(p, f, nelem(f)) >= 3 &&
- addpart(f[0], strtoull(f[1], 0, 0), strtoull(f[2], 0, 0)) < 0)
- fprint(2, "%s: addpart %s: %r\n", argv0, f[0]);
- }
- }
- static void
- ctlwrite0(Req *r, char *msg, Cmdbuf *cb)
- {
- int64_t start, end;
- Part *p;
- r->ofcall.count = r->ifcall.count;
- if(cb->nf < 1){
- respond(r, "empty control message");
- return;
- }
- if(strcmp(cb->f[0], "part") == 0){
- if(cb->nf != 4){
- respondcmderror(r, cb, "part takes 3 args");
- return;
- }
- start = strtoll(cb->f[2], 0, 0);
- end = strtoll(cb->f[3], 0, 0);
- if(addpart(cb->f[1], start, end) < 0){
- respondcmderror(r, cb, "%r");
- return;
- }
- }
- else if(strcmp(cb->f[0], "delpart") == 0){
- if(cb->nf != 2){
- respondcmderror(r, cb, "delpart takes 1 arg");
- return;
- }
- if(delpart(cb->f[1]) < 0){
- respondcmderror(r, cb, "%r");
- return;
- }
- }
- else if(strcmp(cb->f[0], "inquiry") == 0){
- if(cb->nf != 2){
- respondcmderror(r, cb, "inquiry takes 1 arg");
- return;
- }
- free(inquiry);
- inquiry = estrdup9p(cb->f[1]);
- }
- else if(strcmp(cb->f[0], "geometry") == 0){
- if(cb->nf != 3){
- respondcmderror(r, cb, "geometry takes 2 args");
- return;
- }
- nsect = strtoll(cb->f[1], 0, 0);
- sectsize = strtoll(cb->f[2], 0, 0);
- if(tab[0].inuse && strcmp(tab[0].name, "data") == 0 &&
- tab[0].vers == 0){
- tab[0].offset = 0;
- tab[0].length = nsect;
- }
- for(p = tab; p < tab + nelem(tab); p++)
- if(p->inuse && p->offset + p->length > nsect){
- p->inuse = 0;
- free(p->name);
- p->name = nil;
- }
- } else
- /* pass through to underlying ctl file, if any */
- if (write(ctlfd, msg, r->ifcall.count) != r->ifcall.count) {
- respondcmderror(r, cb, "%r");
- return;
- }
- respond(r, nil);
- }
- void
- ctlwrite(Req *r)
- {
- char *msg;
- Cmdbuf *cb;
- r->ofcall.count = r->ifcall.count;
- msg = emalloc9p(r->ifcall.count+1);
- memmove(msg, r->ifcall.data, r->ifcall.count);
- msg[r->ifcall.count] = '\0';
- cb = parsecmd(r->ifcall.data, r->ifcall.count);
- ctlwrite0(r, msg, cb);
- free(cb);
- free(msg);
- }
- int
- rootgen(int off, Dir *d, void *v)
- {
- memset(d, 0, sizeof *d);
- d->atime = time0;
- d->mtime = time0;
- if(off == 0){
- d->name = estrdup9p(sdname);
- d->mode = DMDIR|0777;
- d->qid.path = Qdir;
- d->qid.type = QTDIR;
- d->uid = estrdup9p("partfs");
- d->gid = estrdup9p("partfs");
- d->muid = estrdup9p("");
- return 0;
- }
- return -1;
- }
- int
- dirgen(int off, Dir *d, void *v)
- {
- int n;
- Part *p;
- memset(d, 0, sizeof *d);
- d->atime = time0;
- d->mtime = time0;
- if(off == 0){
- d->name = estrdup9p("ctl");
- d->mode = ctlmode;
- d->qid.path = Qctl;
- goto Have;
- }
- off--;
- n = 0;
- for(p = tab; p < tab + nelem(tab); p++, n++){
- if(!p->inuse)
- continue;
- if(n == off){
- d->name = estrdup9p(p->name);
- d->length = p->length*sectsize;
- d->mode = p->mode;
- d->qid.path = Qpart + p - tab;
- d->qid.vers = p->vers;
- goto Have;
- }
- }
- return -1;
- Have:
- d->uid = estrdup9p("partfs");
- d->gid = estrdup9p("partfs");
- d->muid = estrdup9p("");
- return 0;
- }
- int
- rdwrpart(Req *r)
- {
- int q;
- int32_t count, tot;
- int64_t offset;
- uint8_t *dat;
- Part *p;
- q = r->fid->qid.path - Qpart;
- if(q < 0 || q > nelem(tab) || !tab[q].inuse ||
- tab[q].vers != r->fid->qid.vers){
- respond(r, "unknown partition");
- return -1;
- }
- p = &tab[q];
- offset = r->ifcall.offset;
- count = r->ifcall.count;
- if(offset < 0){
- respond(r, "negative offset");
- return -1;
- }
- if(count < 0){
- respond(r, "negative count");
- return -1;
- }
- if(offset > p->length*sectsize){
- respond(r, "offset past end of partition");
- return -1;
- }
- if(offset+count > p->length*sectsize)
- count = p->length*sectsize - offset;
- offset += p->offset*sectsize;
- if(r->ifcall.type == Tread)
- dat = (uint8_t*)r->ofcall.data;
- else
- dat = (uint8_t*)r->ifcall.data;
- /* pass i/o through to underlying file */
- seek(fd, offset, 0);
- if (r->ifcall.type == Twrite) {
- tot = write(fd, dat, count);
- if (tot != count) {
- respond(r, "%r");
- return -1;
- }
- } else {
- tot = read(fd, dat, count);
- if (tot < 0) {
- respond(r, "%r");
- return -1;
- }
- }
- r->ofcall.count = tot;
- respond(r, nil);
- return 0;
- }
- void
- fsread(Req *r)
- {
- char *s;
- switch((int)r->fid->qid.path){
- case Qroot:
- dirread9p(r, rootgen, nil);
- break;
- case Qdir:
- dirread9p(r, dirgen, nil);
- break;
- case Qctl:
- s = ctlstring();
- readstr(r, s);
- free(s);
- break;
- default:
- rdwrpart(r);
- return;
- }
- respond(r, nil);
- }
- void
- fswrite(Req *r)
- {
- switch((int)r->fid->qid.path){
- case Qroot:
- case Qdir:
- respond(r, "write to a directory?");
- break;
- case Qctl:
- ctlwrite(r);
- break;
- default:
- rdwrpart(r);
- break;
- }
- }
- void
- fsopen(Req *r)
- {
- if(r->ifcall.mode&ORCLOSE)
- respond(r, "cannot open ORCLOSE");
- switch((int)r->fid->qid.path){
- case Qroot:
- case Qdir:
- if(r->ifcall.mode != OREAD){
- respond(r, "bad mode for directory open");
- return;
- }
- }
- respond(r, nil);
- }
- void
- fsstat(Req *r)
- {
- int q;
- Dir *d;
- Part *p;
- d = &r->d;
- memset(d, 0, sizeof *d);
- d->qid = r->fid->qid;
- d->atime = d->mtime = time0;
- q = r->fid->qid.path;
- switch(q){
- case Qroot:
- d->name = estrdup9p("/");
- d->mode = DMDIR|0777;
- break;
- case Qdir:
- d->name = estrdup9p(sdname);
- d->mode = DMDIR|0777;
- break;
- case Qctl:
- d->name = estrdup9p("ctl");
- d->mode = 0666;
- break;
- default:
- q -= Qpart;
- if(q < 0 || q > nelem(tab) || tab[q].inuse == 0 ||
- r->fid->qid.vers != tab[q].vers){
- respond(r, "partition no longer exists");
- return;
- }
- p = &tab[q];
- d->name = estrdup9p(p->name);
- d->length = p->length * sectsize;
- d->mode = p->mode;
- break;
- }
- d->uid = estrdup9p("partfs");
- d->gid = estrdup9p("partfs");
- d->muid = estrdup9p("");
- respond(r, nil);
- }
- void
- fsattach(Req *r)
- {
- char *spec;
- spec = r->ifcall.aname;
- if(spec && spec[0]){
- respond(r, "invalid attach specifier");
- return;
- }
- r->ofcall.qid = (Qid){Qroot, 0, QTDIR};
- r->fid->qid = r->ofcall.qid;
- respond(r, nil);
- }
- char*
- fswalk1(Fid *fid, char *name, Qid *qid)
- {
- Part *p;
- switch((int)fid->qid.path){
- case Qroot:
- if(strcmp(name, sdname) == 0){
- fid->qid.path = Qdir;
- fid->qid.type = QTDIR;
- *qid = fid->qid;
- return nil;
- }
- break;
- case Qdir:
- if(strcmp(name, "ctl") == 0){
- fid->qid.path = Qctl;
- fid->qid.vers = 0;
- fid->qid.type = 0;
- *qid = fid->qid;
- return nil;
- }
- for(p = tab; p < tab + nelem(tab); p++)
- if(p->inuse && strcmp(p->name, name) == 0){
- fid->qid.path = p - tab + Qpart;
- fid->qid.vers = p->vers;
- fid->qid.type = 0;
- *qid = fid->qid;
- return nil;
- }
- break;
- }
- return "file not found";
- }
- Srv fs = {
- .attach=fsattach,
- .open= fsopen,
- .read= fsread,
- .write= fswrite,
- .stat= fsstat,
- .walk1= fswalk1,
- };
- char *mtpt = "/dev";
- char *srvname;
- void
- usage(void)
- {
- fprint(2, "usage: %s [-Dr] [-d sdname] [-m mtpt] [-p 9parts] "
- "[-s srvname] diskimage\n", argv0);
- fprint(2, "\tdefault mtpt is /dev\n");
- exits("usage");
- }
- void
- main(int argc, char **argv)
- {
- int isdir;
- char *file, *cname, *parts;
- Dir *dir;
- quotefmtinstall();
- time0 = time(0);
- parts = nil;
- ARGBEGIN{
- case 'D':
- chatty9p++;
- break;
- case 'd':
- sdname = EARGF(usage());
- break;
- case 'm':
- mtpt = EARGF(usage());
- break;
- case 'p':
- parts = EARGF(usage());
- break;
- case 'r':
- rdonly = 1;
- break;
- case 's':
- srvname = EARGF(usage());
- break;
- default:
- usage();
- }ARGEND
- if(argc != 1)
- usage();
- file = argv[0];
- dir = dirstat(file);
- if(!dir)
- sysfatal("%s: %r", file);
- isdir = (dir->mode & DMDIR) != 0;
- free(dir);
- if (isdir) {
- cname = smprint("%s/ctl", file);
- if ((ctlfd = open(cname, ORDWR)) < 0)
- sysfatal("open %s: %r", cname);
- file = smprint("%s/data", file);
- }
- if((fd = open(file, rdonly? OREAD: ORDWR)) < 0)
- sysfatal("open %s: %r", file);
- sectsize = 512; /* conventional */
- dir = dirfstat(fd);
- if (dir)
- nsect = dir->length / sectsize;
- free(dir);
- inquiry = estrdup9p(inquiry);
- tab[0].inuse = 1;
- tab[0].name = estrdup9p("data");
- tab[0].mode = 0666;
- tab[0].length = nsect;
- /*
- * hack for booting from usb: add 9load partitions.
- */
- if(parts != nil)
- addparts(parts);
- postmountsrv(&fs, srvname, mtpt, MBEFORE);
- exits(nil);
- }
|