/* * 9P file server for the control file system. * This provides a control file system with just * a vol file to get/set status for volumes. * * BUG: there is no way (yet) to update constraints. * This requires the addition of a "set" command. */ #include #include #include #include #include #include #include "names.h" #include "vols.h" Fs ctlfs; uvlong Ctldirqid= 0x000000008c000001ULL; uvlong Ctlqid= 0x000000008d000000ULL; static Dir* ctldirstat(int isdir) { Dir* d; char* s; char* n; d = emalloc(sizeof(Dir)+ 4 + 4 + 4 + 4); memset(d, 0, sizeof(Dir)); s = (char*)d; n = s + sizeof(Dir); d->name = n; strcpy(n, "vol"); n += 4; d->uid = n; strcpy(n, "sys"); n += 4; d->gid = n; strcpy(n, "sys"); n += 4; d->muid = n; strcpy(n, "sys"); // depends on the qid. if (isdir){ d->qid.type = QTDIR; d->qid.path = Ctldirqid; d->mode = DMDIR|0555; } else { d->qid.type = 0; d->qid.path = Ctlqid; d->qid.vers = epoch.ref; d->mode = 0660; } return d; } static int statop(Fs* , Frpc* fop) { fop->r.tag = fop->f.tag; fop->r.type= Rstat; fop->d = ctldirstat(fop->fid->qid.type&QTDIR); return 1; } static char* volsmprint(void) { static char buf[16*1024]; int i; char* s; Vol* v; qlock(&volslck); s = buf; *s = 0; for (i = 0; i < nvols; i++){ v = vols[i]; if (v->dead && !v->disabled) continue; if (v->dead || v->disabled) s = seprint(s, buf+sizeof(buf), "#%V ", v); else s = seprint(s, buf+sizeof(buf), "%V ", v); if (vols[i]->disabled) s = seprint(s, buf+sizeof(buf), "# disabled"); else if (vols[i]->dead) s = seprint(s, buf+sizeof(buf), "# dead"); s = seprint(s, buf+sizeof(buf), "\n"); } qunlock(&volslck); qlock(&mvolslck); for (i = 0; i < nmvols; i++) if (mvols[i]) s = seprint(s, buf+sizeof(buf), "# %W\n", mvols[i]); qunlock(&mvolslck); return estrdup(buf); } static int openop(Fs*, Frpc* fop) { Fid* fid; static Dir* root; if (root == nil) root = ctldirstat(0); fid = fop->fid; fop->r.tag= fop->f.tag; if (fid->qid.type&QTDIR){ if ((fop->f.mode&3) != OREAD){ rpcerr(fop, Eperm); return -1; } if (fid->ureadbuf == nil){ fid->ureadbuf = emalloc(128); fid->ureadlen = convD2M(root, (uchar*)fid->ureadbuf, 128); } } else { fid->ureadbuf = volsmprint(); fid->ureadlen = strlen(fid->ureadbuf); } fop->r.type= Ropen; fop->r.qid = fid->qid; fop->r.iounit = 8*1024; return 0; } static int readop(Fs* , Frpc* m) { long off, len; m->r.tag = m->f.tag; m->r.type= Rread; m->r.data= (char*)m->buf; m->r.count = 0; off = m->f.offset; len = m->fid->ureadlen; if (off >= len || !m->f.count) return 0; if (m->fid->qid.type&QTDIR){ if (m->f.count >= len && off == 0){ memmove(m->r.data, m->fid->ureadbuf, len); m->r.count = len; } } else { if (off + m->f.count > len) m->f.count = len - off; m->r.count = m->f.count; memmove(m->r.data, m->fid->ureadbuf+off, m->r.count); } return m->r.count; } static int writeop(Fs* fs, Frpc* fop) { int n; if (fop->fid->qid.type&QTDIR) return noop(fs, fop); fop->r.tag = fop->f.tag; fop->r.type= Rwrite; n = fop->f.count; if (n < 0) n = 0; if (n > 1024) n = 1024; fop->r.count = n; fop->f.data[n] = 0; cmdline(fop->f.data, "/dev/vol", 0); return n; } static int walkop(Fs* , Frpc* m) { int dir; int i; dir = (m->fid->qid.type&QTDIR); m->r.tag = m->f.tag; m->r.type = Rwalk; m->r.nwqid = 0; for(i = 0; i < m->f.nwname && i < MAXWELEM; i++) if(strcmp(m->f.wname[i], "..") == 0){ dir = 1; m->r.wqid[m->r.nwqid].path = Ctldirqid; m->r.wqid[m->r.nwqid++].type = QTDIR; } else if (dir && !strcmp(m->f.wname[i], "vol")){ dir = 0; m->r.wqid[m->r.nwqid].path = Ctlqid; m->r.wqid[m->r.nwqid++].type = 0; } else break; if (!m->f.nwname || m->r.nwqid > 0) return 1; rpcerr(m, Enotexist); return 0; } static int clunkop(Fs*, Frpc* fop) { free(fop->fid->ureadbuf); fop->fid->ureadbuf = nil; fop->r.tag = fop->f.tag; fop->r.type= Rclunk; return 0; } static int flushop(Fs*, Frpc* fop) { fop->r.tag = fop->f.tag; fop->r.type= Rflush; return 0; } typedef int (*Frpcf)(Fs*, Frpc*); Frpcf ctlfsops[Tmax] = { [Topen] openop, [Twalk] walkop, [Tcreate] noop, [Tclunk] clunkop, [Tread] readop, [Twrite] writeop, [Tremove] noop, [Tstat] statop, [Twstat] noop, [Tflush] flushop, };