<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv=Content-Type content="text/html; charset=utf8"> <title>/usr/web/sources/contrib/geoff/3cmdfs.c - Plan 9 from Bell Labs</title> <!-- THIS FILE IS AUTOMATICALLY GENERATED. --> <!-- EDIT sources.tr INSTEAD. --> </meta> </head> <body> <p style="margin-top: 0; margin-bottom: 0.17in"></p> <p style="line-height: 1.2em; margin-left: 1.00in; text-indent: 0.00in; margin-right: 1.00in; margin-top: 0; margin-bottom: 0; text-align: center;"> <span style="font-size: 10pt"><a href="/plan9/">Plan 9 from Bell Labs</a>’s /usr/web/sources/contrib/geoff/3cmdfs.c</span></p> <p style="margin-top: 0; margin-bottom: 0.17in"></p> <p style="margin-top: 0; margin-bottom: 0.17in"></p> <center><font size=-1> Copyright © 2009 Alcatel-Lucent.<br /> Distributed under the <a href="/plan9/license.html">Lucent Public License version 1.02</a>. <br /> <a href="/plan9/download.html">Download the Plan 9 distribution.</a> </font> </center> <p style="margin-top: 0; margin-bottom: 0.17in"></p> <table width="100%" cellspacing=0 border=0><tr><td align="center"> <table cellspacing=0 cellpadding=5 bgcolor="#eeeeff"><tr><td align="left"> <pre> <!-- END HEADER --> /* * cmdfs mntpt cmd - mount this file server, writes into which become * writes to a pipe to cmd. a new cmd is started for each open * of mntpt/pipe, but only one is permitted at a time. */ #include <u.h> #include <libc.h> #include <bio.h> #include <auth.h> #include <fcall.h> #include <thread.h> #include <9p.h> #define TEMPDIR "/n/temp" #define TEMPFILE "pipe" enum { Rd, Wr, Auxmag = 0xb1ffd00d, /* none genuine without it */ }; enum { Open, Create, }; /* * I think Aux should contain a reference count, but we're getting away * without one for now. */ typedef struct { int fd; /* write here to reach cmd */ int pid; /* of cmd */ ulong magic; } Aux; static Tree *filetree; static int verbose; static char *mntpt = TEMPDIR, *cmd = ""; static void* emalloc(long sz) { void *v = mallocz(sz, 1); if (v == nil) sysfatal("malloc %lud fails\n", sz); return v; } static char* estrdup(char *s) { s = strdup(s); if (s == nil) sysfatal("strdup (%.10s) fails\n", s); return s; } static File* fcreatewalk(File *f, char *name, char *u, char *g, ulong m) { char elem[NAMELEN]; char *p; File *nf; if (verbose) fprint(2, "fcreatewalk %s\n", name); incref(&f->ref); while (f && (p = strchr(name, '/'))) { memmove(elem, name, p-name); elem[p-name] = '\0'; name = p+1; if (strcmp(elem, "") == 0) continue; /* this would be a race if we were multithreaded */ if (verbose) fprint(2, "fcreatewalk: fwalk/fcreate1 %s\n", elem); decref(&f->ref); nf = fwalk(f, elem); if (nf == nil) nf = fcreate(f, elem, u, g, CHDIR|0775); f = nf; } if (f == nil) return nil; if (verbose) fprint(2, "fcreatewalk: fwalk/fcreate2 %s\n", name); if (nf = fwalk(f, name)) { decref(&f->ref); return nf; } /* another race */ decref(&f->ref); return fcreate(f, name, u, g, CHEXCL|m); } static void createfile(char *name) { File *root = filetree->root; File *f = fcreatewalk(root, name, root->uid, root->gid, 0664); if (f == nil) sysfatal("creating %s: %r", name); f->aux = nil; // unused f->mtime = f->atime = time(nil); f->length = 0; decref(&f->ref); } // run cmd with fd0 & fd1 as stdin and stdout (then close them in parent) int connect(char *cmd, int fd0, int fd1, int closeme) { int pid = rfork(RFFDG|RFREND|RFPROC|RFNOWAIT); switch (pid) { case -1: sysfatal("fork %s: %r", cmd); return -1; default: close(fd0); close(fd1); return pid; case 0: close(closeme); dup(fd0, 0); dup(fd1, 1); close(fd0); close(fd1); execl("/bin/rc", "rc", "-c", cmd, nil); sysfatal("exec %s: %r", cmd); return 0; } } static Aux * newconn(char *cmd) { int pipefds[2]; Aux *aux; if (pipe(pipefds) < 0) sysfatal("can't make a pipe: %r"); aux = emalloc(sizeof(Aux)); aux->pid = connect(cmd, pipefds[Rd], dup(1, -1), pipefds[Wr]); aux->fd = pipefds[Wr]; aux->magic = Auxmag; // close(pipefds[Rd]); if (verbose) fprint(2, "newconn: allocated new aux %lux\n", (ulong)aux); return aux; } static void setupfile(int what, Req *req, Fid *fid, char *name, int omode, ulong perm, Qid *qid) { File *file = fid->file, *root = filetree->root; if (qid->path&CHDIR) perm |= CHDIR|0111; if (verbose) fprint(2, "setupfile: %s file %lux\n", name, (ulong)file); if (what == Create) { if (file != nil) fclose(file); /* * fcreate assigns qids, starting paths at zero for both * dir.s and plain files, so we just have to have faith * despite the bogus-looking qids we get at first from it. */ fid->file = file = fcreate(root, name, root->uid, root->gid, CHEXCL|perm); } assert(file != nil); *qid = fid->qid = file->qid; if (file->aux == nil && !(perm&CHDIR) && (omode&OMASK) == OWRITE) file->aux = newconn(cmd); respond(req, nil); } /* * "pipe" is created by hand in main(), so fileopen will be called for it, * thus some setup will have to be done in setupfile in either case. */ static void fileopen(Req *req, Fid *fid, int omode, Qid *qid) { setupfile(Open, req, fid, TEMPFILE, omode, 0664, qid); } static void filecreate(Req *req, Fid *fid, char *name, int omode, ulong perm, Qid *qid) { setupfile(Create, req, fid, name, omode, perm, qid); } /* shouldn't be called; paranoia */ static void fileread(Req *r, Fid *fid, void *buf, long *count, vlong offset) { char err[ERRLEN]; if (fid->qid.path&CHDIR) { // Dir d; // convD2M(&d, &fid->file->Dir); (void) fdirread(fid->file, buf, count, offset); respond(r, nil); } strncpy(err, "can't read from commands", ERRLEN); respond(r, err); } static void filewrite(Req *r, Fid *fid, void *buf, long *count, vlong offset) { long n; char err[ERRLEN]; Aux *aux = nil; File *file = fid->file; USED(offset); werrstr(""); if (file != nil) aux = file->aux; assert(aux == nil || aux->magic == Auxmag); if (aux == nil || (n = write(aux->fd, buf, *count)) != *count) { err[0] = '\0'; errstr(err); respond(r, err); } else { file->qid.vers++; file->mtime = time(nil); *count = n; respond(r, nil); } } static void fileclunkaux(Fid *fid) { File *file = fid->file; Aux *aux = nil; if (file != nil) aux = file->aux; if (aux == nil) return; assert(aux->magic == Auxmag); if (verbose) fprint(2, "fileclunkaux: freeing aux %lux for file %lux\n", (ulong)aux, (ulong)fid->file); close(aux->fd); /* let cmd run to completion */ aux->fd = -1; aux->pid = -1; /* we don't care when it finishes */ aux->magic = 0; free(aux); file->aux = nil; } Srv filesrv = { .open= fileopen, .create=filecreate, .read= fileread, .write= filewrite, .clunkaux=fileclunkaux, }; static void usage(void) { fprint(2, "usage: %s [-abcC] [-m mntpt] cmd\n", argv0); exits("usage"); } void main(int argc, char **argv) { char *user = getuser(); ulong flag = MBEFORE; ARGBEGIN { case 'a': flag |= MAFTER; break; case 'b': flag |= MBEFORE; break; case 'c': flag |= MCREATE; break; case 'C': flag |= MCACHE; break; case 'm': mntpt = ARGF(); break; case 'v': verbose = 1; break; default: usage(); break; } ARGEND; if (argc != 1) usage(); cmd = argv[0]; filetree = filesrv.tree = mktree(user, user, CHDIR|0775); createfile(TEMPFILE); postmountsrv(&filesrv, nil, mntpt, flag); exits(0); } <!-- BEGIN TAIL --> </pre> </td></tr></table> </td></tr></table> <p style="margin-top: 0; margin-bottom: 0.17in"></p> <p style="line-height: 1.2em; margin-left: 1.00in; text-indent: 0.00in; margin-right: 1.00in; margin-top: 0; margin-bottom: 0; text-align: center;"> <span style="font-size: 10pt"></span></p> <p style="margin-top: 0; margin-bottom: 0.50in"></p> <p style="margin-top: 0; margin-bottom: 0.33in"></p> <center><table border="0"><tr> <td valign="middle"><a href="http://www.alcatel-lucent.com/"><img border="0" src="/plan9/img/logo_ft.gif" alt="Bell Labs" /> </a></td> <td valign="middle"><a href="http://www.opensource.org"><img border="0" alt="OSI certified" src="/plan9/img/osi-certified-60x50.gif" /> </a></td> <td><img style="padding-right: 45px;" alt="Powered by Plan 9" src="/plan9/img/power36.gif" /> </td> </tr></table></center> <p style="margin-top: 0; margin-bottom: 0.17in"></p> <center> <span style="font-size: 10pt">(<a href="/plan9/">Return to Plan 9 Home Page</a>)</span> </center> <p style="margin-top: 0; margin-bottom: 0.17in"></p> <center><font size=-1> <span style="font-size: 10pt"><a href="http://www.lucent.com/copyright.html">Copyright</a></span> <span style="font-size: 10pt">© 2009 Alcatel-Lucent.</span> <span style="font-size: 10pt">All Rights Reserved.</span> <br /> <span style="font-size: 10pt">Comments to</span> <span style="font-size: 10pt"><a href="mailto:webmaster@plan9.bell-labs.com">webmaster@plan9.bell-labs.com</a>.</span> </font></center> </body> </html>