13e12c5d1SDavid du Colombier /*
23e12c5d1SDavid du Colombier * cpu.c - Make a connection to a cpu server
33e12c5d1SDavid du Colombier *
4219b2ee8SDavid du Colombier * Invoked by listen as 'cpu -R | -N service net netdir'
5219b2ee8SDavid du Colombier * by users as 'cpu [-h system] [-c cmd args ...]'
63e12c5d1SDavid du Colombier */
73e12c5d1SDavid du Colombier
83e12c5d1SDavid du Colombier #include <u.h>
93e12c5d1SDavid du Colombier #include <libc.h>
103e12c5d1SDavid du Colombier #include <bio.h>
113e12c5d1SDavid du Colombier #include <auth.h>
127dd7cddfSDavid du Colombier #include <fcall.h>
1359cc4ca5SDavid du Colombier #include <libsec.h>
143e12c5d1SDavid du Colombier
15*2ec6491fSDavid du Colombier #define Maxfdata (16*1024)
169800bf03SDavid du Colombier #define MaxStr 128
179a747e4fSDavid du Colombier
187fc543e0SDavid du Colombier void remoteside(void);
193e12c5d1SDavid du Colombier void fatal(int, char*, ...);
207dd7cddfSDavid du Colombier void lclnoteproc(int);
217dd7cddfSDavid du Colombier void rmtnoteproc(void);
223e12c5d1SDavid du Colombier void catcher(void*, char*);
233e12c5d1SDavid du Colombier void usage(void);
243e12c5d1SDavid du Colombier void writestr(int, char*, char*, int);
25219b2ee8SDavid du Colombier int readstr(int, char*, int);
263e12c5d1SDavid du Colombier char *rexcall(int*, char*, char*);
2759cc4ca5SDavid du Colombier int setamalg(char*);
28d9306527SDavid du Colombier char *keyspec = "";
293e12c5d1SDavid du Colombier
303e12c5d1SDavid du Colombier int notechan;
3142bd533dSDavid du Colombier int exportpid;
329800bf03SDavid du Colombier char *system;
333e12c5d1SDavid du Colombier int cflag;
34219b2ee8SDavid du Colombier int dbg;
359a747e4fSDavid du Colombier char *user;
367a3484c3SDavid du Colombier char *patternfile;
37d1be6b08SDavid du Colombier char *origargs;
383e12c5d1SDavid du Colombier
399a747e4fSDavid du Colombier char *srvname = "ncpu";
403e12c5d1SDavid du Colombier char *exportfs = "/bin/exportfs";
4159cc4ca5SDavid du Colombier char *ealgs = "rc4_256 sha1";
423e12c5d1SDavid du Colombier
439a747e4fSDavid du Colombier /* message size for exportfs; may be larger so we can do big graphics in CPU window */
449a747e4fSDavid du Colombier int msgsize = Maxfdata+IOHDRSZ;
459a747e4fSDavid du Colombier
467dd7cddfSDavid du Colombier /* authentication mechanisms */
477dd7cddfSDavid du Colombier static int netkeyauth(int);
487dd7cddfSDavid du Colombier static int netkeysrvauth(int, char*);
4959cc4ca5SDavid du Colombier static int p9auth(int);
5059cc4ca5SDavid du Colombier static int srvp9auth(int, char*);
519a747e4fSDavid du Colombier static int noauth(int);
529a747e4fSDavid du Colombier static int srvnoauth(int, char*);
537dd7cddfSDavid du Colombier
547dd7cddfSDavid du Colombier typedef struct AuthMethod AuthMethod;
557dd7cddfSDavid du Colombier struct AuthMethod {
567dd7cddfSDavid du Colombier char *name; /* name of method */
577dd7cddfSDavid du Colombier int (*cf)(int); /* client side authentication */
587dd7cddfSDavid du Colombier int (*sf)(int, char*); /* server side authentication */
597dd7cddfSDavid du Colombier } authmethod[] =
607dd7cddfSDavid du Colombier {
619a747e4fSDavid du Colombier { "p9", p9auth, srvp9auth,},
629a747e4fSDavid du Colombier { "netkey", netkeyauth, netkeysrvauth,},
639a747e4fSDavid du Colombier // { "none", noauth, srvnoauth,},
647dd7cddfSDavid du Colombier { nil, nil}
657dd7cddfSDavid du Colombier };
667dd7cddfSDavid du Colombier AuthMethod *am = authmethod; /* default is p9 */
677dd7cddfSDavid du Colombier
689a747e4fSDavid du Colombier char *p9authproto = "p9any";
699a747e4fSDavid du Colombier
707dd7cddfSDavid du Colombier int setam(char*);
717dd7cddfSDavid du Colombier
723e12c5d1SDavid du Colombier void
usage(void)73219b2ee8SDavid du Colombier usage(void)
74219b2ee8SDavid du Colombier {
7587a56857SDavid du Colombier fprint(2, "usage: cpu [-h system] [-u user] [-a authmethod] "
7687a56857SDavid du Colombier "[-e 'crypt hash'] [-k keypattern] [-P patternfile] "
7787a56857SDavid du Colombier "[-c cmd arg ...]\n");
78219b2ee8SDavid du Colombier exits("usage");
79219b2ee8SDavid du Colombier }
80219b2ee8SDavid du Colombier
81d1be6b08SDavid du Colombier /*
82d1be6b08SDavid du Colombier * reading /proc/pid/args yields either "name args" or "name [display args]",
83d1be6b08SDavid du Colombier * so return only args or display args.
84d1be6b08SDavid du Colombier */
85d1be6b08SDavid du Colombier static char *
procgetname(void)86d1be6b08SDavid du Colombier procgetname(void)
87d1be6b08SDavid du Colombier {
88d1be6b08SDavid du Colombier int fd, n;
89d1be6b08SDavid du Colombier char *lp, *rp;
90d1be6b08SDavid du Colombier char buf[256];
91d1be6b08SDavid du Colombier
92d1be6b08SDavid du Colombier snprint(buf, sizeof buf, "#p/%d/args", getpid());
93d1be6b08SDavid du Colombier if((fd = open(buf, OREAD)) < 0)
94d1be6b08SDavid du Colombier return strdup("");
95d1be6b08SDavid du Colombier *buf = '\0';
96d1be6b08SDavid du Colombier n = read(fd, buf, sizeof buf-1);
97d1be6b08SDavid du Colombier close(fd);
98d1be6b08SDavid du Colombier if (n >= 0)
99d1be6b08SDavid du Colombier buf[n] = '\0';
100d1be6b08SDavid du Colombier if ((lp = strchr(buf, '[')) == nil || (rp = strrchr(buf, ']')) == nil) {
101d1be6b08SDavid du Colombier lp = strchr(buf, ' ');
102d1be6b08SDavid du Colombier if (lp == nil)
103d1be6b08SDavid du Colombier return strdup("");
104d1be6b08SDavid du Colombier else
105d1be6b08SDavid du Colombier return strdup(lp+1);
106d1be6b08SDavid du Colombier }
107d1be6b08SDavid du Colombier *rp = '\0';
108d1be6b08SDavid du Colombier return strdup(lp+1);
109d1be6b08SDavid du Colombier }
110d1be6b08SDavid du Colombier
111d1be6b08SDavid du Colombier /*
112d1be6b08SDavid du Colombier * based on libthread's threadsetname, but drags in less library code.
113d1be6b08SDavid du Colombier * actually just sets the arguments displayed.
114d1be6b08SDavid du Colombier */
115d1be6b08SDavid du Colombier void
procsetname(char * fmt,...)116d1be6b08SDavid du Colombier procsetname(char *fmt, ...)
117d1be6b08SDavid du Colombier {
118d1be6b08SDavid du Colombier int fd;
119d1be6b08SDavid du Colombier char *cmdname;
120d1be6b08SDavid du Colombier char buf[128];
121d1be6b08SDavid du Colombier va_list arg;
122d1be6b08SDavid du Colombier
123d1be6b08SDavid du Colombier va_start(arg, fmt);
124d1be6b08SDavid du Colombier cmdname = vsmprint(fmt, arg);
125d1be6b08SDavid du Colombier va_end(arg);
126d1be6b08SDavid du Colombier if (cmdname == nil)
127d1be6b08SDavid du Colombier return;
128d1be6b08SDavid du Colombier snprint(buf, sizeof buf, "#p/%d/args", getpid());
129d1be6b08SDavid du Colombier if((fd = open(buf, OWRITE)) >= 0){
130d1be6b08SDavid du Colombier write(fd, cmdname, strlen(cmdname)+1);
131d1be6b08SDavid du Colombier close(fd);
132d1be6b08SDavid du Colombier }
133d1be6b08SDavid du Colombier free(cmdname);
134d1be6b08SDavid du Colombier }
135d1be6b08SDavid du Colombier
136219b2ee8SDavid du Colombier void
main(int argc,char ** argv)1373e12c5d1SDavid du Colombier main(int argc, char **argv)
1383e12c5d1SDavid du Colombier {
1399800bf03SDavid du Colombier char dat[MaxStr], buf[MaxStr], cmd[MaxStr], *p, *err;
140759d2aa8SDavid du Colombier int ac, fd, ms, data;
1417a3484c3SDavid du Colombier char *av[10];
1423e12c5d1SDavid du Colombier
143d1be6b08SDavid du Colombier quotefmtinstall();
144d1be6b08SDavid du Colombier origargs = procgetname();
1459a747e4fSDavid du Colombier /* see if we should use a larger message size */
1469a747e4fSDavid du Colombier fd = open("/dev/draw", OREAD);
1479a747e4fSDavid du Colombier if(fd > 0){
1489a747e4fSDavid du Colombier ms = iounit(fd);
1499a747e4fSDavid du Colombier if(msgsize < ms+IOHDRSZ)
1509a747e4fSDavid du Colombier msgsize = ms+IOHDRSZ;
1519a747e4fSDavid du Colombier close(fd);
1529a747e4fSDavid du Colombier }
1539a747e4fSDavid du Colombier
1549a747e4fSDavid du Colombier user = getuser();
1559a747e4fSDavid du Colombier if(user == nil)
1569a747e4fSDavid du Colombier fatal(1, "can't read user name");
1573e12c5d1SDavid du Colombier ARGBEGIN{
1587dd7cddfSDavid du Colombier case 'a':
1599a747e4fSDavid du Colombier p = EARGF(usage());
1607dd7cddfSDavid du Colombier if(setam(p) < 0)
1619a747e4fSDavid du Colombier fatal(0, "unknown auth method %s", p);
1627dd7cddfSDavid du Colombier break;
16359cc4ca5SDavid du Colombier case 'e':
1649a747e4fSDavid du Colombier ealgs = EARGF(usage());
16559cc4ca5SDavid du Colombier if(*ealgs == 0 || strcmp(ealgs, "clear") == 0)
16659cc4ca5SDavid du Colombier ealgs = nil;
16759cc4ca5SDavid du Colombier break;
168219b2ee8SDavid du Colombier case 'd':
169219b2ee8SDavid du Colombier dbg++;
170219b2ee8SDavid du Colombier break;
1717dd7cddfSDavid du Colombier case 'f':
1729a747e4fSDavid du Colombier /* ignored but accepted for compatibility */
1739a747e4fSDavid du Colombier break;
1743e12c5d1SDavid du Colombier case 'R': /* From listen */
1757fc543e0SDavid du Colombier remoteside();
1763e12c5d1SDavid du Colombier break;
1773e12c5d1SDavid du Colombier case 'h':
1789800bf03SDavid du Colombier system = EARGF(usage());
1793e12c5d1SDavid du Colombier break;
1803e12c5d1SDavid du Colombier case 'c':
1813e12c5d1SDavid du Colombier cflag++;
1823e12c5d1SDavid du Colombier cmd[0] = '!';
1833e12c5d1SDavid du Colombier cmd[1] = '\0';
1843e12c5d1SDavid du Colombier while(p = ARGF()) {
1853e12c5d1SDavid du Colombier strcat(cmd, " ");
1863e12c5d1SDavid du Colombier strcat(cmd, p);
1873e12c5d1SDavid du Colombier }
1883e12c5d1SDavid du Colombier break;
189d9306527SDavid du Colombier case 'k':
190f366f900SDavid du Colombier keyspec = smprint("%s %s", keyspec, EARGF(usage()));
191d9306527SDavid du Colombier break;
192b280a0acSDavid du Colombier case 'P':
1937a3484c3SDavid du Colombier patternfile = EARGF(usage());
1947a3484c3SDavid du Colombier break;
19567493d07SDavid du Colombier case 'u':
19667493d07SDavid du Colombier user = EARGF(usage());
197f366f900SDavid du Colombier keyspec = smprint("%s user=%s", keyspec, user);
19867493d07SDavid du Colombier break;
19959cc4ca5SDavid du Colombier default:
20059cc4ca5SDavid du Colombier usage();
2013e12c5d1SDavid du Colombier }ARGEND;
2023e12c5d1SDavid du Colombier
2039a747e4fSDavid du Colombier
2043e12c5d1SDavid du Colombier if(argc != 0)
2053e12c5d1SDavid du Colombier usage();
2063e12c5d1SDavid du Colombier
2079800bf03SDavid du Colombier if(system == nil) {
2083e12c5d1SDavid du Colombier p = getenv("cpu");
2093e12c5d1SDavid du Colombier if(p == 0)
2103e12c5d1SDavid du Colombier fatal(0, "set $cpu");
2119800bf03SDavid du Colombier system = p;
2123e12c5d1SDavid du Colombier }
2133e12c5d1SDavid du Colombier
2143e12c5d1SDavid du Colombier if(err = rexcall(&data, system, srvname))
2153e12c5d1SDavid du Colombier fatal(1, "%s: %s", err, system);
2163e12c5d1SDavid du Colombier
217d1be6b08SDavid du Colombier procsetname("%s", origargs);
2183e12c5d1SDavid du Colombier /* Tell the remote side the command to execute and where our working directory is */
2193e12c5d1SDavid du Colombier if(cflag)
2203e12c5d1SDavid du Colombier writestr(data, cmd, "command", 0);
2213e12c5d1SDavid du Colombier if(getwd(dat, sizeof(dat)) == 0)
2223e12c5d1SDavid du Colombier writestr(data, "NO", "dir", 0);
2233e12c5d1SDavid du Colombier else
2243e12c5d1SDavid du Colombier writestr(data, dat, "dir", 0);
2253e12c5d1SDavid du Colombier
2267dd7cddfSDavid du Colombier /* start up a process to pass along notes */
2277dd7cddfSDavid du Colombier lclnoteproc(data);
2283e12c5d1SDavid du Colombier
22959cc4ca5SDavid du Colombier /*
23059cc4ca5SDavid du Colombier * Wait for the other end to execute and start our file service
23159cc4ca5SDavid du Colombier * of /mnt/term
23259cc4ca5SDavid du Colombier */
233219b2ee8SDavid du Colombier if(readstr(data, buf, sizeof(buf)) < 0)
234fb7f0c93SDavid du Colombier fatal(1, "waiting for FS: %r");
2353e12c5d1SDavid du Colombier if(strncmp("FS", buf, 2) != 0) {
2363e12c5d1SDavid du Colombier print("remote cpu: %s", buf);
2373e12c5d1SDavid du Colombier exits(buf);
2383e12c5d1SDavid du Colombier }
2393e12c5d1SDavid du Colombier
2403e12c5d1SDavid du Colombier /* Begin serving the gnot namespace */
2413e12c5d1SDavid du Colombier close(0);
2423e12c5d1SDavid du Colombier dup(data, 0);
2433e12c5d1SDavid du Colombier close(data);
244759d2aa8SDavid du Colombier
2459a747e4fSDavid du Colombier sprint(buf, "%d", msgsize);
2467a3484c3SDavid du Colombier ac = 0;
247759d2aa8SDavid du Colombier av[ac++] = exportfs;
2487a3484c3SDavid du Colombier av[ac++] = "-m";
249759d2aa8SDavid du Colombier av[ac++] = buf;
250219b2ee8SDavid du Colombier if(dbg)
2517a3484c3SDavid du Colombier av[ac++] = "-d";
2527a3484c3SDavid du Colombier if(patternfile != nil){
253b280a0acSDavid du Colombier av[ac++] = "-P";
2547a3484c3SDavid du Colombier av[ac++] = patternfile;
2557a3484c3SDavid du Colombier }
256759d2aa8SDavid du Colombier av[ac] = nil;
2577a3484c3SDavid du Colombier exec(exportfs, av);
2583e12c5d1SDavid du Colombier fatal(1, "starting exportfs");
2593e12c5d1SDavid du Colombier }
2603e12c5d1SDavid du Colombier
2613e12c5d1SDavid du Colombier void
fatal(int syserr,char * fmt,...)2623e12c5d1SDavid du Colombier fatal(int syserr, char *fmt, ...)
2633e12c5d1SDavid du Colombier {
2649a747e4fSDavid du Colombier Fmt f;
2659a747e4fSDavid du Colombier char *str;
2667dd7cddfSDavid du Colombier va_list arg;
2673e12c5d1SDavid du Colombier
2689a747e4fSDavid du Colombier fmtstrinit(&f);
2699a747e4fSDavid du Colombier fmtprint(&f, "cpu: ");
2707dd7cddfSDavid du Colombier va_start(arg, fmt);
2719a747e4fSDavid du Colombier fmtvprint(&f, fmt, arg);
2727dd7cddfSDavid du Colombier va_end(arg);
2733e12c5d1SDavid du Colombier if(syserr)
2749a747e4fSDavid du Colombier fmtprint(&f, ": %r");
2759a747e4fSDavid du Colombier str = fmtstrflush(&f);
27687a56857SDavid du Colombier
27787a56857SDavid du Colombier fprint(2, "%s\n", str);
27887a56857SDavid du Colombier syslog(0, "cpu", str);
2799a747e4fSDavid du Colombier exits(str);
2803e12c5d1SDavid du Colombier }
2813e12c5d1SDavid du Colombier
2827dd7cddfSDavid du Colombier char *negstr = "negotiating authentication method";
283219b2ee8SDavid du Colombier
2843e12c5d1SDavid du Colombier /* Invoked with stdin, stdout and stderr connected to the network connection */
2853e12c5d1SDavid du Colombier void
remoteside(void)2867fc543e0SDavid du Colombier remoteside(void)
2873e12c5d1SDavid du Colombier {
2889800bf03SDavid du Colombier char user[MaxStr], home[MaxStr], buf[MaxStr], xdir[MaxStr], cmd[MaxStr];
2893e12c5d1SDavid du Colombier int i, n, fd, badchdir, gotcmd;
2903e12c5d1SDavid du Colombier
291da51d93aSDavid du Colombier rfork(RFENVG);
292da51d93aSDavid du Colombier putenv("service", "cpu");
29359cc4ca5SDavid du Colombier fd = 0;
29459cc4ca5SDavid du Colombier
2957dd7cddfSDavid du Colombier /* negotiate authentication mechanism */
29659cc4ca5SDavid du Colombier n = readstr(fd, cmd, sizeof(cmd));
2977dd7cddfSDavid du Colombier if(n < 0)
2987dd7cddfSDavid du Colombier fatal(1, "authenticating");
29959cc4ca5SDavid du Colombier if(setamalg(cmd) < 0){
3009a747e4fSDavid du Colombier writestr(fd, "unsupported auth method", nil, 0);
3017dd7cddfSDavid du Colombier fatal(1, "bad auth method %s", cmd);
3027dd7cddfSDavid du Colombier } else
30359cc4ca5SDavid du Colombier writestr(fd, "", "", 1);
3047dd7cddfSDavid du Colombier
30559cc4ca5SDavid du Colombier fd = (*am->sf)(fd, user);
30659cc4ca5SDavid du Colombier if(fd < 0)
307219b2ee8SDavid du Colombier fatal(1, "srvauth");
3083e12c5d1SDavid du Colombier
3093e12c5d1SDavid du Colombier /* Set environment values for the user */
3103e12c5d1SDavid du Colombier putenv("user", user);
3113e12c5d1SDavid du Colombier sprint(home, "/usr/%s", user);
3123e12c5d1SDavid du Colombier putenv("home", home);
3133e12c5d1SDavid du Colombier
3149a747e4fSDavid du Colombier /* Now collect invoking cpu's current directory or possibly a command */
3153e12c5d1SDavid du Colombier gotcmd = 0;
31659cc4ca5SDavid du Colombier if(readstr(fd, xdir, sizeof(xdir)) < 0)
317219b2ee8SDavid du Colombier fatal(1, "dir/cmd");
3183e12c5d1SDavid du Colombier if(xdir[0] == '!') {
3193e12c5d1SDavid du Colombier strcpy(cmd, &xdir[1]);
3203e12c5d1SDavid du Colombier gotcmd = 1;
32159cc4ca5SDavid du Colombier if(readstr(fd, xdir, sizeof(xdir)) < 0)
322219b2ee8SDavid du Colombier fatal(1, "dir");
3233e12c5d1SDavid du Colombier }
3243e12c5d1SDavid du Colombier
3253e12c5d1SDavid du Colombier /* Establish the new process at the current working directory of the
3263e12c5d1SDavid du Colombier * gnot */
3273e12c5d1SDavid du Colombier badchdir = 0;
3283e12c5d1SDavid du Colombier if(strcmp(xdir, "NO") == 0)
3293e12c5d1SDavid du Colombier chdir(home);
3303e12c5d1SDavid du Colombier else if(chdir(xdir) < 0) {
3313e12c5d1SDavid du Colombier badchdir = 1;
3323e12c5d1SDavid du Colombier chdir(home);
3333e12c5d1SDavid du Colombier }
3343e12c5d1SDavid du Colombier
3353e12c5d1SDavid du Colombier /* Start the gnot serving its namespace */
33659cc4ca5SDavid du Colombier writestr(fd, "FS", "FS", 0);
33759cc4ca5SDavid du Colombier writestr(fd, "/", "exportfs dir", 0);
3383e12c5d1SDavid du Colombier
33959cc4ca5SDavid du Colombier n = read(fd, buf, sizeof(buf));
3403e12c5d1SDavid du Colombier if(n != 2 || buf[0] != 'O' || buf[1] != 'K')
3413e12c5d1SDavid du Colombier exits("remote tree");
3423e12c5d1SDavid du Colombier
3439a747e4fSDavid du Colombier /* make sure buffers are big by doing fversion explicitly; pick a huge number; other side will trim */
3449a747e4fSDavid du Colombier strcpy(buf, VERSION9P);
3459a747e4fSDavid du Colombier if(fversion(fd, 64*1024, buf, sizeof buf) < 0)
3469a747e4fSDavid du Colombier exits("fversion failed");
3479a747e4fSDavid du Colombier if(mount(fd, -1, "/mnt/term", MCREATE|MREPL, "") < 0)
3483e12c5d1SDavid du Colombier exits("mount failed");
3499a747e4fSDavid du Colombier
3503e12c5d1SDavid du Colombier close(fd);
3513e12c5d1SDavid du Colombier
3527dd7cddfSDavid du Colombier /* the remote noteproc uses the mount so it must follow it */
3537dd7cddfSDavid du Colombier rmtnoteproc();
3547dd7cddfSDavid du Colombier
3553e12c5d1SDavid du Colombier for(i = 0; i < 3; i++)
3563e12c5d1SDavid du Colombier close(i);
3573e12c5d1SDavid du Colombier
3589a747e4fSDavid du Colombier if(open("/mnt/term/dev/cons", OREAD) != 0)
3593e12c5d1SDavid du Colombier exits("open stdin");
3609a747e4fSDavid du Colombier if(open("/mnt/term/dev/cons", OWRITE) != 1)
3613e12c5d1SDavid du Colombier exits("open stdout");
3623e12c5d1SDavid du Colombier dup(1, 2);
3633e12c5d1SDavid du Colombier
3643e12c5d1SDavid du Colombier if(badchdir)
3653e12c5d1SDavid du Colombier print("cpu: failed to chdir to '%s'\n", xdir);
3663e12c5d1SDavid du Colombier
3673e12c5d1SDavid du Colombier if(gotcmd)
368f19e7b74SDavid du Colombier execl("/bin/rc", "rc", "-lc", cmd, nil);
3693e12c5d1SDavid du Colombier else
370f19e7b74SDavid du Colombier execl("/bin/rc", "rc", "-li", nil);
3713e12c5d1SDavid du Colombier fatal(1, "exec shell");
3723e12c5d1SDavid du Colombier }
3733e12c5d1SDavid du Colombier
3743e12c5d1SDavid du Colombier char*
rexcall(int * fd,char * host,char * service)3753e12c5d1SDavid du Colombier rexcall(int *fd, char *host, char *service)
3763e12c5d1SDavid du Colombier {
3773e12c5d1SDavid du Colombier char *na;
3789800bf03SDavid du Colombier char dir[MaxStr];
3799a747e4fSDavid du Colombier char err[ERRMAX];
3809800bf03SDavid du Colombier char msg[MaxStr];
3817dd7cddfSDavid du Colombier int n;
3823e12c5d1SDavid du Colombier
3833e12c5d1SDavid du Colombier na = netmkaddr(host, 0, service);
384d1be6b08SDavid du Colombier procsetname("dialing %s", na);
3857dd7cddfSDavid du Colombier if((*fd = dial(na, 0, dir, 0)) < 0)
3863e12c5d1SDavid du Colombier return "can't dial";
3877dd7cddfSDavid du Colombier
3887dd7cddfSDavid du Colombier /* negotiate authentication mechanism */
38959cc4ca5SDavid du Colombier if(ealgs != nil)
39059cc4ca5SDavid du Colombier snprint(msg, sizeof(msg), "%s %s", am->name, ealgs);
39159cc4ca5SDavid du Colombier else
39259cc4ca5SDavid du Colombier snprint(msg, sizeof(msg), "%s", am->name);
393d1be6b08SDavid du Colombier procsetname("writing %s", msg);
39459cc4ca5SDavid du Colombier writestr(*fd, msg, negstr, 0);
395d1be6b08SDavid du Colombier procsetname("awaiting auth method");
3969a747e4fSDavid du Colombier n = readstr(*fd, err, sizeof err);
3977dd7cddfSDavid du Colombier if(n < 0)
3987dd7cddfSDavid du Colombier return negstr;
3997dd7cddfSDavid du Colombier if(*err){
4007dd7cddfSDavid du Colombier werrstr(err);
4017dd7cddfSDavid du Colombier return negstr;
4027dd7cddfSDavid du Colombier }
4037dd7cddfSDavid du Colombier
4047dd7cddfSDavid du Colombier /* authenticate */
405d1be6b08SDavid du Colombier procsetname("%s: auth via %s", origargs, am->name);
40659cc4ca5SDavid du Colombier *fd = (*am->cf)(*fd);
40759cc4ca5SDavid du Colombier if(*fd < 0)
408219b2ee8SDavid du Colombier return "can't authenticate";
4093e12c5d1SDavid du Colombier return 0;
4103e12c5d1SDavid du Colombier }
4113e12c5d1SDavid du Colombier
4123e12c5d1SDavid du Colombier void
writestr(int fd,char * str,char * thing,int ignore)4133e12c5d1SDavid du Colombier writestr(int fd, char *str, char *thing, int ignore)
4143e12c5d1SDavid du Colombier {
4153e12c5d1SDavid du Colombier int l, n;
4163e12c5d1SDavid du Colombier
4173e12c5d1SDavid du Colombier l = strlen(str);
4183e12c5d1SDavid du Colombier n = write(fd, str, l+1);
4193e12c5d1SDavid du Colombier if(!ignore && n < 0)
4203e12c5d1SDavid du Colombier fatal(1, "writing network: %s", thing);
4213e12c5d1SDavid du Colombier }
4223e12c5d1SDavid du Colombier
423219b2ee8SDavid du Colombier int
readstr(int fd,char * str,int len)424219b2ee8SDavid du Colombier readstr(int fd, char *str, int len)
4253e12c5d1SDavid du Colombier {
4263e12c5d1SDavid du Colombier int n;
4273e12c5d1SDavid du Colombier
4283e12c5d1SDavid du Colombier while(len) {
4293e12c5d1SDavid du Colombier n = read(fd, str, 1);
430219b2ee8SDavid du Colombier if(n < 0)
431219b2ee8SDavid du Colombier return -1;
4323e12c5d1SDavid du Colombier if(*str == '\0')
433219b2ee8SDavid du Colombier return 0;
4343e12c5d1SDavid du Colombier str++;
4353e12c5d1SDavid du Colombier len--;
4363e12c5d1SDavid du Colombier }
437219b2ee8SDavid du Colombier return -1;
4383e12c5d1SDavid du Colombier }
4397dd7cddfSDavid du Colombier
4407dd7cddfSDavid du Colombier static int
readln(char * buf,int n)4417dd7cddfSDavid du Colombier readln(char *buf, int n)
4427dd7cddfSDavid du Colombier {
4439a747e4fSDavid du Colombier int i;
4449a747e4fSDavid du Colombier char *p;
4457dd7cddfSDavid du Colombier
4469a747e4fSDavid du Colombier n--; /* room for \0 */
4479a747e4fSDavid du Colombier p = buf;
4489a747e4fSDavid du Colombier for(i=0; i<n; i++){
4497dd7cddfSDavid du Colombier if(read(0, p, 1) != 1)
4507dd7cddfSDavid du Colombier break;
4519a747e4fSDavid du Colombier if(*p == '\n' || *p == '\r')
4529a747e4fSDavid du Colombier break;
4537dd7cddfSDavid du Colombier p++;
4547dd7cddfSDavid du Colombier }
4559a747e4fSDavid du Colombier *p = '\0';
4567dd7cddfSDavid du Colombier return p-buf;
4577dd7cddfSDavid du Colombier }
4587dd7cddfSDavid du Colombier
45959cc4ca5SDavid du Colombier /*
46059cc4ca5SDavid du Colombier * user level challenge/response
46159cc4ca5SDavid du Colombier */
4627dd7cddfSDavid du Colombier static int
netkeyauth(int fd)4637dd7cddfSDavid du Colombier netkeyauth(int fd)
4647dd7cddfSDavid du Colombier {
4659a747e4fSDavid du Colombier char chall[32];
4669a747e4fSDavid du Colombier char resp[32];
4677dd7cddfSDavid du Colombier
4689800bf03SDavid du Colombier strecpy(chall, chall+sizeof chall, getuser());
4697dd7cddfSDavid du Colombier print("user[%s]: ", chall);
4707dd7cddfSDavid du Colombier if(readln(resp, sizeof(resp)) < 0)
4717dd7cddfSDavid du Colombier return -1;
4727dd7cddfSDavid du Colombier if(*resp != 0)
4737dd7cddfSDavid du Colombier strcpy(chall, resp);
4747dd7cddfSDavid du Colombier writestr(fd, chall, "challenge/response", 1);
4757dd7cddfSDavid du Colombier
4767dd7cddfSDavid du Colombier for(;;){
4777dd7cddfSDavid du Colombier if(readstr(fd, chall, sizeof chall) < 0)
4787dd7cddfSDavid du Colombier break;
4797dd7cddfSDavid du Colombier if(*chall == 0)
48059cc4ca5SDavid du Colombier return fd;
4817dd7cddfSDavid du Colombier print("challenge: %s\nresponse: ", chall);
4827dd7cddfSDavid du Colombier if(readln(resp, sizeof(resp)) < 0)
4837dd7cddfSDavid du Colombier break;
4847dd7cddfSDavid du Colombier writestr(fd, resp, "challenge/response", 1);
4857dd7cddfSDavid du Colombier }
4867dd7cddfSDavid du Colombier return -1;
4877dd7cddfSDavid du Colombier }
4887dd7cddfSDavid du Colombier
4897dd7cddfSDavid du Colombier static int
netkeysrvauth(int fd,char * user)4907dd7cddfSDavid du Colombier netkeysrvauth(int fd, char *user)
4917dd7cddfSDavid du Colombier {
4929a747e4fSDavid du Colombier char response[32];
4939a747e4fSDavid du Colombier Chalstate *ch;
4947dd7cddfSDavid du Colombier int tries;
4959a747e4fSDavid du Colombier AuthInfo *ai;
4967dd7cddfSDavid du Colombier
4979a747e4fSDavid du Colombier if(readstr(fd, user, 32) < 0)
4987dd7cddfSDavid du Colombier return -1;
4997dd7cddfSDavid du Colombier
5009a747e4fSDavid du Colombier ai = nil;
5019a747e4fSDavid du Colombier ch = nil;
5027dd7cddfSDavid du Colombier for(tries = 0; tries < 10; tries++){
5039a747e4fSDavid du Colombier if((ch = auth_challenge("proto=p9cr role=server user=%q", user)) == nil)
5047dd7cddfSDavid du Colombier return -1;
5059a747e4fSDavid du Colombier writestr(fd, ch->chal, "challenge", 1);
5067dd7cddfSDavid du Colombier if(readstr(fd, response, sizeof response) < 0)
5077dd7cddfSDavid du Colombier return -1;
5089a747e4fSDavid du Colombier ch->resp = response;
5099a747e4fSDavid du Colombier ch->nresp = strlen(response);
5109a747e4fSDavid du Colombier if((ai = auth_response(ch)) != nil)
5117dd7cddfSDavid du Colombier break;
5127dd7cddfSDavid du Colombier }
5139a747e4fSDavid du Colombier auth_freechal(ch);
5149a747e4fSDavid du Colombier if(ai == nil)
5157dd7cddfSDavid du Colombier return -1;
5167dd7cddfSDavid du Colombier writestr(fd, "", "challenge", 1);
5179a747e4fSDavid du Colombier if(auth_chuid(ai, 0) < 0)
5189a747e4fSDavid du Colombier fatal(1, "newns");
5199a747e4fSDavid du Colombier auth_freeAI(ai);
52059cc4ca5SDavid du Colombier return fd;
52159cc4ca5SDavid du Colombier }
52259cc4ca5SDavid du Colombier
52359cc4ca5SDavid du Colombier static void
mksecret(char * t,uchar * f)52459cc4ca5SDavid du Colombier mksecret(char *t, uchar *f)
52559cc4ca5SDavid du Colombier {
52659cc4ca5SDavid du Colombier sprint(t, "%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
52759cc4ca5SDavid du Colombier f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9]);
52859cc4ca5SDavid du Colombier }
52959cc4ca5SDavid du Colombier
53059cc4ca5SDavid du Colombier /*
53159cc4ca5SDavid du Colombier * plan9 authentication followed by rc4 encryption
53259cc4ca5SDavid du Colombier */
53359cc4ca5SDavid du Colombier static int
p9auth(int fd)53459cc4ca5SDavid du Colombier p9auth(int fd)
53559cc4ca5SDavid du Colombier {
53659cc4ca5SDavid du Colombier uchar key[16];
53759cc4ca5SDavid du Colombier uchar digest[SHA1dlen];
53859cc4ca5SDavid du Colombier char fromclientsecret[21];
53959cc4ca5SDavid du Colombier char fromserversecret[21];
54059cc4ca5SDavid du Colombier int i;
5419a747e4fSDavid du Colombier AuthInfo *ai;
54259cc4ca5SDavid du Colombier
543d1be6b08SDavid du Colombier procsetname("%s: auth_proxy proto=%q role=client %s",
544d1be6b08SDavid du Colombier origargs, p9authproto, keyspec);
545d9306527SDavid du Colombier ai = auth_proxy(fd, auth_getkey, "proto=%q role=client %s", p9authproto, keyspec);
5469a747e4fSDavid du Colombier if(ai == nil)
54759cc4ca5SDavid du Colombier return -1;
548c403fce2SDavid du Colombier if(ai->nsecret < 8){
549c403fce2SDavid du Colombier werrstr("negotiated secret too short");
550c403fce2SDavid du Colombier return -1;
551c403fce2SDavid du Colombier }
552c403fce2SDavid du Colombier memmove(key+4, ai->secret, 8);
55359cc4ca5SDavid du Colombier if(ealgs == nil)
55459cc4ca5SDavid du Colombier return fd;
55559cc4ca5SDavid du Colombier
55659cc4ca5SDavid du Colombier /* exchange random numbers */
55759cc4ca5SDavid du Colombier srand(truerand());
55859cc4ca5SDavid du Colombier for(i = 0; i < 4; i++)
55959cc4ca5SDavid du Colombier key[i] = rand();
560d1be6b08SDavid du Colombier procsetname("writing p9 key");
56159cc4ca5SDavid du Colombier if(write(fd, key, 4) != 4)
56259cc4ca5SDavid du Colombier return -1;
563d1be6b08SDavid du Colombier procsetname("reading p9 key");
56459cc4ca5SDavid du Colombier if(readn(fd, key+12, 4) != 4)
56559cc4ca5SDavid du Colombier return -1;
56659cc4ca5SDavid du Colombier
56759cc4ca5SDavid du Colombier /* scramble into two secrets */
56859cc4ca5SDavid du Colombier sha1(key, sizeof(key), digest, nil);
56959cc4ca5SDavid du Colombier mksecret(fromclientsecret, digest);
57059cc4ca5SDavid du Colombier mksecret(fromserversecret, digest+10);
57159cc4ca5SDavid du Colombier
57259cc4ca5SDavid du Colombier /* set up encryption */
573d1be6b08SDavid du Colombier procsetname("pushssl");
5749a747e4fSDavid du Colombier i = pushssl(fd, ealgs, fromclientsecret, fromserversecret, nil);
5759a747e4fSDavid du Colombier if(i < 0)
5769a747e4fSDavid du Colombier werrstr("can't establish ssl connection: %r");
5779a747e4fSDavid du Colombier return i;
5789a747e4fSDavid du Colombier }
5799a747e4fSDavid du Colombier
5809a747e4fSDavid du Colombier static int
noauth(int fd)5819a747e4fSDavid du Colombier noauth(int fd)
5829a747e4fSDavid du Colombier {
5839a747e4fSDavid du Colombier ealgs = nil;
5849a747e4fSDavid du Colombier return fd;
5859a747e4fSDavid du Colombier }
5869a747e4fSDavid du Colombier
5879a747e4fSDavid du Colombier static int
srvnoauth(int fd,char * user)5889a747e4fSDavid du Colombier srvnoauth(int fd, char *user)
5899a747e4fSDavid du Colombier {
5909800bf03SDavid du Colombier strecpy(user, user+MaxStr, getuser());
5919a747e4fSDavid du Colombier ealgs = nil;
592225077b0SDavid du Colombier newns(user, nil);
5939a747e4fSDavid du Colombier return fd;
5949a747e4fSDavid du Colombier }
5959a747e4fSDavid du Colombier
5969a747e4fSDavid du Colombier void
loghex(uchar * p,int n)5979a747e4fSDavid du Colombier loghex(uchar *p, int n)
5989a747e4fSDavid du Colombier {
5999a747e4fSDavid du Colombier char buf[100];
6009a747e4fSDavid du Colombier int i;
6019a747e4fSDavid du Colombier
6029a747e4fSDavid du Colombier for(i = 0; i < n; i++)
6039a747e4fSDavid du Colombier sprint(buf+2*i, "%2.2ux", p[i]);
6049a747e4fSDavid du Colombier syslog(0, "cpu", buf);
60559cc4ca5SDavid du Colombier }
60659cc4ca5SDavid du Colombier
60759cc4ca5SDavid du Colombier static int
srvp9auth(int fd,char * user)60859cc4ca5SDavid du Colombier srvp9auth(int fd, char *user)
60959cc4ca5SDavid du Colombier {
61059cc4ca5SDavid du Colombier uchar key[16];
61159cc4ca5SDavid du Colombier uchar digest[SHA1dlen];
61259cc4ca5SDavid du Colombier char fromclientsecret[21];
61359cc4ca5SDavid du Colombier char fromserversecret[21];
61459cc4ca5SDavid du Colombier int i;
6159a747e4fSDavid du Colombier AuthInfo *ai;
61659cc4ca5SDavid du Colombier
617d9306527SDavid du Colombier ai = auth_proxy(0, nil, "proto=%q role=server %s", p9authproto, keyspec);
6189a747e4fSDavid du Colombier if(ai == nil)
61959cc4ca5SDavid du Colombier return -1;
6209a747e4fSDavid du Colombier if(auth_chuid(ai, nil) < 0)
6219a747e4fSDavid du Colombier return -1;
6229800bf03SDavid du Colombier strecpy(user, user+MaxStr, ai->cuid);
623c403fce2SDavid du Colombier if(ai->nsecret < 8){
624c403fce2SDavid du Colombier werrstr("negotiated secret too short");
625c403fce2SDavid du Colombier return -1;
626c403fce2SDavid du Colombier }
627c403fce2SDavid du Colombier memmove(key+4, ai->secret, 8);
62859cc4ca5SDavid du Colombier
62959cc4ca5SDavid du Colombier if(ealgs == nil)
63059cc4ca5SDavid du Colombier return fd;
63159cc4ca5SDavid du Colombier
63259cc4ca5SDavid du Colombier /* exchange random numbers */
63359cc4ca5SDavid du Colombier srand(truerand());
63459cc4ca5SDavid du Colombier for(i = 0; i < 4; i++)
63559cc4ca5SDavid du Colombier key[i+12] = rand();
63659cc4ca5SDavid du Colombier if(readn(fd, key, 4) != 4)
63759cc4ca5SDavid du Colombier return -1;
63859cc4ca5SDavid du Colombier if(write(fd, key+12, 4) != 4)
63959cc4ca5SDavid du Colombier return -1;
64059cc4ca5SDavid du Colombier
64159cc4ca5SDavid du Colombier /* scramble into two secrets */
64259cc4ca5SDavid du Colombier sha1(key, sizeof(key), digest, nil);
64359cc4ca5SDavid du Colombier mksecret(fromclientsecret, digest);
64459cc4ca5SDavid du Colombier mksecret(fromserversecret, digest+10);
64559cc4ca5SDavid du Colombier
64659cc4ca5SDavid du Colombier /* set up encryption */
6479a747e4fSDavid du Colombier i = pushssl(fd, ealgs, fromserversecret, fromclientsecret, nil);
6489a747e4fSDavid du Colombier if(i < 0)
6499a747e4fSDavid du Colombier werrstr("can't establish ssl connection: %r");
6509a747e4fSDavid du Colombier return i;
6517dd7cddfSDavid du Colombier }
6527dd7cddfSDavid du Colombier
65359cc4ca5SDavid du Colombier /*
65459cc4ca5SDavid du Colombier * set authentication mechanism
65559cc4ca5SDavid du Colombier */
6567dd7cddfSDavid du Colombier int
setam(char * name)6577dd7cddfSDavid du Colombier setam(char *name)
6587dd7cddfSDavid du Colombier {
6597dd7cddfSDavid du Colombier for(am = authmethod; am->name != nil; am++)
6607dd7cddfSDavid du Colombier if(strcmp(am->name, name) == 0)
6617dd7cddfSDavid du Colombier return 0;
6627dd7cddfSDavid du Colombier am = authmethod;
6637dd7cddfSDavid du Colombier return -1;
6647dd7cddfSDavid du Colombier }
6657dd7cddfSDavid du Colombier
66659cc4ca5SDavid du Colombier /*
66759cc4ca5SDavid du Colombier * set authentication mechanism and encryption/hash algs
66859cc4ca5SDavid du Colombier */
66959cc4ca5SDavid du Colombier int
setamalg(char * s)67059cc4ca5SDavid du Colombier setamalg(char *s)
67159cc4ca5SDavid du Colombier {
67259cc4ca5SDavid du Colombier ealgs = strchr(s, ' ');
67359cc4ca5SDavid du Colombier if(ealgs != nil)
67459cc4ca5SDavid du Colombier *ealgs++ = 0;
67559cc4ca5SDavid du Colombier return setam(s);
67659cc4ca5SDavid du Colombier }
67759cc4ca5SDavid du Colombier
6787dd7cddfSDavid du Colombier char *rmtnotefile = "/mnt/term/dev/cpunote";
6797dd7cddfSDavid du Colombier
6807dd7cddfSDavid du Colombier /*
6817dd7cddfSDavid du Colombier * loop reading /mnt/term/dev/note looking for notes.
6827dd7cddfSDavid du Colombier * The child returns to start the shell.
6837dd7cddfSDavid du Colombier */
6847dd7cddfSDavid du Colombier void
rmtnoteproc(void)6857dd7cddfSDavid du Colombier rmtnoteproc(void)
6867dd7cddfSDavid du Colombier {
6877dd7cddfSDavid du Colombier int n, fd, pid, notepid;
6887dd7cddfSDavid du Colombier char buf[256];
6897dd7cddfSDavid du Colombier
6907dd7cddfSDavid du Colombier /* new proc returns to start shell */
6917dd7cddfSDavid du Colombier pid = rfork(RFPROC|RFFDG|RFNOTEG|RFNAMEG|RFMEM);
6927dd7cddfSDavid du Colombier switch(pid){
6937dd7cddfSDavid du Colombier case -1:
6947dd7cddfSDavid du Colombier syslog(0, "cpu", "cpu -R: can't start noteproc: %r");
6957dd7cddfSDavid du Colombier return;
6967dd7cddfSDavid du Colombier case 0:
6977dd7cddfSDavid du Colombier return;
6987dd7cddfSDavid du Colombier }
6997dd7cddfSDavid du Colombier
7007dd7cddfSDavid du Colombier /* new proc reads notes from other side and posts them to shell */
7017dd7cddfSDavid du Colombier switch(notepid = rfork(RFPROC|RFFDG|RFMEM)){
7027dd7cddfSDavid du Colombier case -1:
7037dd7cddfSDavid du Colombier syslog(0, "cpu", "cpu -R: can't start wait proc: %r");
7047dd7cddfSDavid du Colombier _exits(0);
7057dd7cddfSDavid du Colombier case 0:
7067dd7cddfSDavid du Colombier fd = open(rmtnotefile, OREAD);
7077dd7cddfSDavid du Colombier if(fd < 0){
7087dd7cddfSDavid du Colombier syslog(0, "cpu", "cpu -R: can't open %s", rmtnotefile);
7097dd7cddfSDavid du Colombier _exits(0);
7107dd7cddfSDavid du Colombier }
7117dd7cddfSDavid du Colombier
7127dd7cddfSDavid du Colombier for(;;){
7137dd7cddfSDavid du Colombier n = read(fd, buf, sizeof(buf)-1);
7147dd7cddfSDavid du Colombier if(n <= 0){
7157dd7cddfSDavid du Colombier postnote(PNGROUP, pid, "hangup");
7167dd7cddfSDavid du Colombier _exits(0);
7177dd7cddfSDavid du Colombier }
7187dd7cddfSDavid du Colombier buf[n] = 0;
7197dd7cddfSDavid du Colombier postnote(PNGROUP, pid, buf);
7207dd7cddfSDavid du Colombier }
7217dd7cddfSDavid du Colombier }
7227dd7cddfSDavid du Colombier
7237dd7cddfSDavid du Colombier /* original proc waits for shell proc to die and kills note proc */
7247dd7cddfSDavid du Colombier for(;;){
7259a747e4fSDavid du Colombier n = waitpid();
7267dd7cddfSDavid du Colombier if(n < 0 || n == pid)
7277dd7cddfSDavid du Colombier break;
7287dd7cddfSDavid du Colombier }
7297dd7cddfSDavid du Colombier postnote(PNPROC, notepid, "kill");
7307dd7cddfSDavid du Colombier _exits(0);
7317dd7cddfSDavid du Colombier }
7327dd7cddfSDavid du Colombier
7337dd7cddfSDavid du Colombier enum
7347dd7cddfSDavid du Colombier {
7357dd7cddfSDavid du Colombier Qdir,
7367dd7cddfSDavid du Colombier Qcpunote,
7377dd7cddfSDavid du Colombier
7387dd7cddfSDavid du Colombier Nfid = 32,
7397dd7cddfSDavid du Colombier };
7407dd7cddfSDavid du Colombier
7417dd7cddfSDavid du Colombier struct {
7427dd7cddfSDavid du Colombier char *name;
7437dd7cddfSDavid du Colombier Qid qid;
7447dd7cddfSDavid du Colombier ulong perm;
7457dd7cddfSDavid du Colombier } fstab[] =
7467dd7cddfSDavid du Colombier {
7479a747e4fSDavid du Colombier [Qdir] { ".", {Qdir, 0, QTDIR}, DMDIR|0555 },
7487dd7cddfSDavid du Colombier [Qcpunote] { "cpunote", {Qcpunote, 0}, 0444 },
7497dd7cddfSDavid du Colombier };
7507dd7cddfSDavid du Colombier
7517dd7cddfSDavid du Colombier typedef struct Note Note;
7527dd7cddfSDavid du Colombier struct Note
7537dd7cddfSDavid du Colombier {
7547dd7cddfSDavid du Colombier Note *next;
7559a747e4fSDavid du Colombier char msg[ERRMAX];
7567dd7cddfSDavid du Colombier };
7577dd7cddfSDavid du Colombier
7587dd7cddfSDavid du Colombier typedef struct Request Request;
7597dd7cddfSDavid du Colombier struct Request
7607dd7cddfSDavid du Colombier {
7617dd7cddfSDavid du Colombier Request *next;
7627dd7cddfSDavid du Colombier Fcall f;
7637dd7cddfSDavid du Colombier };
7647dd7cddfSDavid du Colombier
7657dd7cddfSDavid du Colombier typedef struct Fid Fid;
7667dd7cddfSDavid du Colombier struct Fid
7677dd7cddfSDavid du Colombier {
7687dd7cddfSDavid du Colombier int fid;
7697dd7cddfSDavid du Colombier int file;
77042bd533dSDavid du Colombier int omode;
7717dd7cddfSDavid du Colombier };
7727dd7cddfSDavid du Colombier Fid fids[Nfid];
7737dd7cddfSDavid du Colombier
7747dd7cddfSDavid du Colombier struct {
7757dd7cddfSDavid du Colombier Lock;
7767dd7cddfSDavid du Colombier Note *nfirst, *nlast;
7777dd7cddfSDavid du Colombier Request *rfirst, *rlast;
7787dd7cddfSDavid du Colombier } nfs;
7797dd7cddfSDavid du Colombier
7807dd7cddfSDavid du Colombier int
fsreply(int fd,Fcall * f)7817dd7cddfSDavid du Colombier fsreply(int fd, Fcall *f)
7827dd7cddfSDavid du Colombier {
7839a747e4fSDavid du Colombier uchar buf[IOHDRSZ+Maxfdata];
7847dd7cddfSDavid du Colombier int n;
7857dd7cddfSDavid du Colombier
7867dd7cddfSDavid du Colombier if(dbg)
787225077b0SDavid du Colombier fprint(2, "notefs: <-%F\n", f);
7889a747e4fSDavid du Colombier n = convS2M(f, buf, sizeof buf);
7897dd7cddfSDavid du Colombier if(n > 0){
7907dd7cddfSDavid du Colombier if(write(fd, buf, n) != n){
7917dd7cddfSDavid du Colombier close(fd);
7927dd7cddfSDavid du Colombier return -1;
7937dd7cddfSDavid du Colombier }
7947dd7cddfSDavid du Colombier }
7957dd7cddfSDavid du Colombier return 0;
7967dd7cddfSDavid du Colombier }
7977dd7cddfSDavid du Colombier
7987dd7cddfSDavid du Colombier /* match a note read request with a note, reply to the request */
7997dd7cddfSDavid du Colombier int
kick(int fd)8007dd7cddfSDavid du Colombier kick(int fd)
8017dd7cddfSDavid du Colombier {
8027dd7cddfSDavid du Colombier Request *rp;
8037dd7cddfSDavid du Colombier Note *np;
8047dd7cddfSDavid du Colombier int rv;
8057dd7cddfSDavid du Colombier
8067dd7cddfSDavid du Colombier for(;;){
8077dd7cddfSDavid du Colombier lock(&nfs);
8087dd7cddfSDavid du Colombier rp = nfs.rfirst;
8097dd7cddfSDavid du Colombier np = nfs.nfirst;
8107dd7cddfSDavid du Colombier if(rp == nil || np == nil){
8117dd7cddfSDavid du Colombier unlock(&nfs);
8127dd7cddfSDavid du Colombier break;
8137dd7cddfSDavid du Colombier }
8147dd7cddfSDavid du Colombier nfs.rfirst = rp->next;
8157dd7cddfSDavid du Colombier nfs.nfirst = np->next;
8167dd7cddfSDavid du Colombier unlock(&nfs);
8177dd7cddfSDavid du Colombier
8187dd7cddfSDavid du Colombier rp->f.type = Rread;
8197dd7cddfSDavid du Colombier rp->f.count = strlen(np->msg);
8207dd7cddfSDavid du Colombier rp->f.data = np->msg;
8217dd7cddfSDavid du Colombier rv = fsreply(fd, &rp->f);
8227dd7cddfSDavid du Colombier free(rp);
8237dd7cddfSDavid du Colombier free(np);
8247dd7cddfSDavid du Colombier if(rv < 0)
8257dd7cddfSDavid du Colombier return -1;
8267dd7cddfSDavid du Colombier }
8277dd7cddfSDavid du Colombier return 0;
8287dd7cddfSDavid du Colombier }
8297dd7cddfSDavid du Colombier
8307dd7cddfSDavid du Colombier void
flushreq(int tag)8317dd7cddfSDavid du Colombier flushreq(int tag)
8327dd7cddfSDavid du Colombier {
8337dd7cddfSDavid du Colombier Request **l, *rp;
8347dd7cddfSDavid du Colombier
8357dd7cddfSDavid du Colombier lock(&nfs);
8367dd7cddfSDavid du Colombier for(l = &nfs.rfirst; *l != nil; l = &(*l)->next){
8377dd7cddfSDavid du Colombier rp = *l;
8387dd7cddfSDavid du Colombier if(rp->f.tag == tag){
8397dd7cddfSDavid du Colombier *l = rp->next;
8407dd7cddfSDavid du Colombier unlock(&nfs);
8417dd7cddfSDavid du Colombier free(rp);
8427dd7cddfSDavid du Colombier return;
8437dd7cddfSDavid du Colombier }
8447dd7cddfSDavid du Colombier }
8457dd7cddfSDavid du Colombier unlock(&nfs);
8467dd7cddfSDavid du Colombier }
8477dd7cddfSDavid du Colombier
8487dd7cddfSDavid du Colombier Fid*
getfid(int fid)8497dd7cddfSDavid du Colombier getfid(int fid)
8507dd7cddfSDavid du Colombier {
8517dd7cddfSDavid du Colombier int i, freefid;
8527dd7cddfSDavid du Colombier
8537dd7cddfSDavid du Colombier freefid = -1;
8547dd7cddfSDavid du Colombier for(i = 0; i < Nfid; i++){
8557dd7cddfSDavid du Colombier if(freefid < 0 && fids[i].file < 0)
8567dd7cddfSDavid du Colombier freefid = i;
8577dd7cddfSDavid du Colombier if(fids[i].fid == fid)
8587dd7cddfSDavid du Colombier return &fids[i];
8597dd7cddfSDavid du Colombier }
8607dd7cddfSDavid du Colombier if(freefid >= 0){
8617dd7cddfSDavid du Colombier fids[freefid].fid = fid;
8627dd7cddfSDavid du Colombier return &fids[freefid];
8637dd7cddfSDavid du Colombier }
8647dd7cddfSDavid du Colombier return nil;
8657dd7cddfSDavid du Colombier }
8667dd7cddfSDavid du Colombier
8677dd7cddfSDavid du Colombier int
fsstat(int fd,Fid * fid,Fcall * f)8687dd7cddfSDavid du Colombier fsstat(int fd, Fid *fid, Fcall *f)
8697dd7cddfSDavid du Colombier {
8707dd7cddfSDavid du Colombier Dir d;
8719a747e4fSDavid du Colombier uchar statbuf[256];
8727dd7cddfSDavid du Colombier
8737dd7cddfSDavid du Colombier memset(&d, 0, sizeof(d));
8749a747e4fSDavid du Colombier d.name = fstab[fid->file].name;
8759a747e4fSDavid du Colombier d.uid = user;
8769a747e4fSDavid du Colombier d.gid = user;
8779a747e4fSDavid du Colombier d.muid = user;
8787dd7cddfSDavid du Colombier d.qid = fstab[fid->file].qid;
8797dd7cddfSDavid du Colombier d.mode = fstab[fid->file].perm;
8807dd7cddfSDavid du Colombier d.atime = d.mtime = time(0);
8819a747e4fSDavid du Colombier f->stat = statbuf;
8829a747e4fSDavid du Colombier f->nstat = convD2M(&d, statbuf, sizeof statbuf);
8837dd7cddfSDavid du Colombier return fsreply(fd, f);
8847dd7cddfSDavid du Colombier }
8857dd7cddfSDavid du Colombier
8867dd7cddfSDavid du Colombier int
fsread(int fd,Fid * fid,Fcall * f)8877dd7cddfSDavid du Colombier fsread(int fd, Fid *fid, Fcall *f)
8887dd7cddfSDavid du Colombier {
8897dd7cddfSDavid du Colombier Dir d;
8909a747e4fSDavid du Colombier uchar buf[256];
8917dd7cddfSDavid du Colombier Request *rp;
8927dd7cddfSDavid du Colombier
8937dd7cddfSDavid du Colombier switch(fid->file){
8947dd7cddfSDavid du Colombier default:
8957dd7cddfSDavid du Colombier return -1;
8967dd7cddfSDavid du Colombier case Qdir:
8979a747e4fSDavid du Colombier if(f->offset == 0 && f->count >0){
8987dd7cddfSDavid du Colombier memset(&d, 0, sizeof(d));
8999a747e4fSDavid du Colombier d.name = fstab[Qcpunote].name;
9009a747e4fSDavid du Colombier d.uid = user;
9019a747e4fSDavid du Colombier d.gid = user;
9029a747e4fSDavid du Colombier d.muid = user;
9037dd7cddfSDavid du Colombier d.qid = fstab[Qcpunote].qid;
9047dd7cddfSDavid du Colombier d.mode = fstab[Qcpunote].perm;
9057dd7cddfSDavid du Colombier d.atime = d.mtime = time(0);
9069a747e4fSDavid du Colombier f->count = convD2M(&d, buf, sizeof buf);
9079a747e4fSDavid du Colombier f->data = (char*)buf;
9087dd7cddfSDavid du Colombier } else
9097dd7cddfSDavid du Colombier f->count = 0;
9107dd7cddfSDavid du Colombier return fsreply(fd, f);
9117dd7cddfSDavid du Colombier case Qcpunote:
9127dd7cddfSDavid du Colombier rp = mallocz(sizeof(*rp), 1);
9137dd7cddfSDavid du Colombier if(rp == nil)
9147dd7cddfSDavid du Colombier return -1;
9157dd7cddfSDavid du Colombier rp->f = *f;
9167dd7cddfSDavid du Colombier lock(&nfs);
9177dd7cddfSDavid du Colombier if(nfs.rfirst == nil)
9187dd7cddfSDavid du Colombier nfs.rfirst = rp;
9197dd7cddfSDavid du Colombier else
9207dd7cddfSDavid du Colombier nfs.rlast->next = rp;
9217dd7cddfSDavid du Colombier nfs.rlast = rp;
9227dd7cddfSDavid du Colombier unlock(&nfs);
9237dd7cddfSDavid du Colombier return kick(fd);;
9247dd7cddfSDavid du Colombier }
9257dd7cddfSDavid du Colombier }
9267dd7cddfSDavid du Colombier
9279a747e4fSDavid du Colombier char Eperm[] = "permission denied";
9289a747e4fSDavid du Colombier char Enofile[] = "out of files";
9299a747e4fSDavid du Colombier char Enotdir[] = "not a directory";
9307dd7cddfSDavid du Colombier
9317dd7cddfSDavid du Colombier void
notefs(int fd)9327dd7cddfSDavid du Colombier notefs(int fd)
9337dd7cddfSDavid du Colombier {
9349a747e4fSDavid du Colombier uchar buf[IOHDRSZ+Maxfdata];
935225077b0SDavid du Colombier int i, n, ncpunote;
9367dd7cddfSDavid du Colombier Fcall f;
937225077b0SDavid du Colombier Qid wqid[MAXWELEM];
9387dd7cddfSDavid du Colombier Fid *fid, *nfid;
9397dd7cddfSDavid du Colombier int doreply;
9407dd7cddfSDavid du Colombier
9417dd7cddfSDavid du Colombier rfork(RFNOTEG);
9429a747e4fSDavid du Colombier fmtinstall('F', fcallfmt);
9437dd7cddfSDavid du Colombier
94442bd533dSDavid du Colombier for(n = 0; n < Nfid; n++){
9457dd7cddfSDavid du Colombier fids[n].file = -1;
94642bd533dSDavid du Colombier fids[n].omode = -1;
94742bd533dSDavid du Colombier }
9487dd7cddfSDavid du Colombier
94942bd533dSDavid du Colombier ncpunote = 0;
9507dd7cddfSDavid du Colombier for(;;){
9519a747e4fSDavid du Colombier n = read9pmsg(fd, buf, sizeof(buf));
9529a747e4fSDavid du Colombier if(n <= 0){
9539a747e4fSDavid du Colombier if(dbg)
9549a747e4fSDavid du Colombier fprint(2, "read9pmsg(%d) returns %d: %r\n", fd, n);
9557dd7cddfSDavid du Colombier break;
9569a747e4fSDavid du Colombier }
95722a127bbSDavid du Colombier if(convM2S(buf, n, &f) <= BIT16SZ)
9587dd7cddfSDavid du Colombier break;
9597dd7cddfSDavid du Colombier if(dbg)
960225077b0SDavid du Colombier fprint(2, "notefs: ->%F\n", &f);
9617dd7cddfSDavid du Colombier doreply = 1;
9627dd7cddfSDavid du Colombier fid = getfid(f.fid);
9637dd7cddfSDavid du Colombier if(fid == nil){
9647dd7cddfSDavid du Colombier nofids:
9657dd7cddfSDavid du Colombier f.type = Rerror;
9669a747e4fSDavid du Colombier f.ename = Enofile;
9677dd7cddfSDavid du Colombier fsreply(fd, &f);
9687dd7cddfSDavid du Colombier continue;
9697dd7cddfSDavid du Colombier }
9707dd7cddfSDavid du Colombier switch(f.type++){
9717dd7cddfSDavid du Colombier default:
9727dd7cddfSDavid du Colombier f.type = Rerror;
9739a747e4fSDavid du Colombier f.ename = "unknown type";
9747dd7cddfSDavid du Colombier break;
9757dd7cddfSDavid du Colombier case Tflush:
9767dd7cddfSDavid du Colombier flushreq(f.oldtag);
9777dd7cddfSDavid du Colombier break;
9789a747e4fSDavid du Colombier case Tversion:
9799a747e4fSDavid du Colombier if(f.msize > IOHDRSZ+Maxfdata)
9809a747e4fSDavid du Colombier f.msize = IOHDRSZ+Maxfdata;
9817dd7cddfSDavid du Colombier break;
9829a747e4fSDavid du Colombier case Tauth:
9839a747e4fSDavid du Colombier f.type = Rerror;
984225077b0SDavid du Colombier f.ename = "authentication not required";
9857dd7cddfSDavid du Colombier break;
9867dd7cddfSDavid du Colombier case Tattach:
9877dd7cddfSDavid du Colombier f.qid = fstab[Qdir].qid;
9887dd7cddfSDavid du Colombier fid->file = Qdir;
9897dd7cddfSDavid du Colombier break;
9909a747e4fSDavid du Colombier case Twalk:
9919a747e4fSDavid du Colombier nfid = nil;
9929a747e4fSDavid du Colombier if(f.newfid != f.fid){
9937dd7cddfSDavid du Colombier nfid = getfid(f.newfid);
9947dd7cddfSDavid du Colombier if(nfid == nil)
9957dd7cddfSDavid du Colombier goto nofids;
9967dd7cddfSDavid du Colombier nfid->file = fid->file;
9977dd7cddfSDavid du Colombier fid = nfid;
9989a747e4fSDavid du Colombier }
999225077b0SDavid du Colombier for(i=0; i<f.nwname && i<MAXWELEM; i++){
10007dd7cddfSDavid du Colombier if(fid->file != Qdir){
10017dd7cddfSDavid du Colombier f.type = Rerror;
10029a747e4fSDavid du Colombier f.ename = Enotdir;
10039a747e4fSDavid du Colombier break;
10047dd7cddfSDavid du Colombier }
1005225077b0SDavid du Colombier if(strcmp(f.wname[i], "..") == 0){
1006225077b0SDavid du Colombier wqid[i] = fstab[Qdir].qid;
10079a747e4fSDavid du Colombier continue;
10089a747e4fSDavid du Colombier }
1009225077b0SDavid du Colombier if(strcmp(f.wname[i], "cpunote") != 0){
1010225077b0SDavid du Colombier if(i == 0){
10119a747e4fSDavid du Colombier f.type = Rerror;
1012225077b0SDavid du Colombier f.ename = "file does not exist";
10139a747e4fSDavid du Colombier }
10149a747e4fSDavid du Colombier break;
10159a747e4fSDavid du Colombier }
1016225077b0SDavid du Colombier fid->file = Qcpunote;
1017225077b0SDavid du Colombier wqid[i] = fstab[Qcpunote].qid;
1018225077b0SDavid du Colombier }
1019225077b0SDavid du Colombier if(nfid != nil && (f.type == Rerror || i < f.nwname))
10209a747e4fSDavid du Colombier nfid ->file = -1;
1021225077b0SDavid du Colombier if(f.type != Rerror){
10229a747e4fSDavid du Colombier f.nwqid = i;
1023225077b0SDavid du Colombier for(i=0; i<f.nwqid; i++)
1024225077b0SDavid du Colombier f.wqid[i] = wqid[i];
1025225077b0SDavid du Colombier }
10267dd7cddfSDavid du Colombier break;
10277dd7cddfSDavid du Colombier case Topen:
10287dd7cddfSDavid du Colombier if(f.mode != OREAD){
10297dd7cddfSDavid du Colombier f.type = Rerror;
10309a747e4fSDavid du Colombier f.ename = Eperm;
1031225077b0SDavid du Colombier break;
10327dd7cddfSDavid du Colombier }
103342bd533dSDavid du Colombier fid->omode = f.mode;
103442bd533dSDavid du Colombier if(fid->file == Qcpunote)
103542bd533dSDavid du Colombier ncpunote++;
103680ee5cbfSDavid du Colombier f.qid = fstab[fid->file].qid;
1037225077b0SDavid du Colombier f.iounit = 0;
10387dd7cddfSDavid du Colombier break;
10397dd7cddfSDavid du Colombier case Tread:
10407dd7cddfSDavid du Colombier if(fsread(fd, fid, &f) < 0)
10417dd7cddfSDavid du Colombier goto err;
10427dd7cddfSDavid du Colombier doreply = 0;
10437dd7cddfSDavid du Colombier break;
10447dd7cddfSDavid du Colombier case Tclunk:
104542bd533dSDavid du Colombier if(fid->omode != -1 && fid->file == Qcpunote){
104642bd533dSDavid du Colombier ncpunote--;
104742bd533dSDavid du Colombier if(ncpunote == 0) /* remote side is done */
104842bd533dSDavid du Colombier goto err;
104942bd533dSDavid du Colombier }
10507dd7cddfSDavid du Colombier fid->file = -1;
105142bd533dSDavid du Colombier fid->omode = -1;
10527dd7cddfSDavid du Colombier break;
10537dd7cddfSDavid du Colombier case Tstat:
10547dd7cddfSDavid du Colombier if(fsstat(fd, fid, &f) < 0)
10557dd7cddfSDavid du Colombier goto err;
10567dd7cddfSDavid du Colombier doreply = 0;
10577dd7cddfSDavid du Colombier break;
1058225077b0SDavid du Colombier case Tcreate:
1059225077b0SDavid du Colombier case Twrite:
1060225077b0SDavid du Colombier case Tremove:
10617dd7cddfSDavid du Colombier case Twstat:
10627dd7cddfSDavid du Colombier f.type = Rerror;
10639a747e4fSDavid du Colombier f.ename = Eperm;
10647dd7cddfSDavid du Colombier break;
10657dd7cddfSDavid du Colombier }
10667dd7cddfSDavid du Colombier if(doreply)
10677dd7cddfSDavid du Colombier if(fsreply(fd, &f) < 0)
10687dd7cddfSDavid du Colombier break;
10697dd7cddfSDavid du Colombier }
10707dd7cddfSDavid du Colombier err:
10719a747e4fSDavid du Colombier if(dbg)
10729a747e4fSDavid du Colombier fprint(2, "notefs exiting: %r\n");
107342bd533dSDavid du Colombier werrstr("success");
10746d87198cSDavid du Colombier postnote(PNGROUP, exportpid, "kill");
107542bd533dSDavid du Colombier if(dbg)
107642bd533dSDavid du Colombier fprint(2, "postnote PNGROUP %d: %r\n", exportpid);
10777dd7cddfSDavid du Colombier close(fd);
10787dd7cddfSDavid du Colombier }
10797dd7cddfSDavid du Colombier
10809a747e4fSDavid du Colombier char notebuf[ERRMAX];
10817dd7cddfSDavid du Colombier
10827dd7cddfSDavid du Colombier void
catcher(void *,char * text)10837dd7cddfSDavid du Colombier catcher(void*, char *text)
10847dd7cddfSDavid du Colombier {
10859a747e4fSDavid du Colombier int n;
10869a747e4fSDavid du Colombier
10879a747e4fSDavid du Colombier n = strlen(text);
10889a747e4fSDavid du Colombier if(n >= sizeof(notebuf))
10899a747e4fSDavid du Colombier n = sizeof(notebuf)-1;
10909a747e4fSDavid du Colombier memmove(notebuf, text, n);
10919a747e4fSDavid du Colombier notebuf[n] = '\0';
10927dd7cddfSDavid du Colombier noted(NCONT);
10937dd7cddfSDavid du Colombier }
10947dd7cddfSDavid du Colombier
10957dd7cddfSDavid du Colombier /*
10967dd7cddfSDavid du Colombier * mount in /dev a note file for the remote side to read.
10977dd7cddfSDavid du Colombier */
10987dd7cddfSDavid du Colombier void
lclnoteproc(int netfd)10997dd7cddfSDavid du Colombier lclnoteproc(int netfd)
11007dd7cddfSDavid du Colombier {
11019a747e4fSDavid du Colombier Waitmsg *w;
11027dd7cddfSDavid du Colombier Note *np;
11037dd7cddfSDavid du Colombier int pfd[2];
110442bd533dSDavid du Colombier int pid;
11057dd7cddfSDavid du Colombier
11067dd7cddfSDavid du Colombier if(pipe(pfd) < 0){
11079a747e4fSDavid du Colombier fprint(2, "cpu: can't start note proc: pipe: %r\n");
11087dd7cddfSDavid du Colombier return;
11097dd7cddfSDavid du Colombier }
11107dd7cddfSDavid du Colombier
11117dd7cddfSDavid du Colombier /* new proc mounts and returns to start exportfs */
111242bd533dSDavid du Colombier switch(pid = rfork(RFPROC|RFNAMEG|RFFDG|RFMEM)){
111342bd533dSDavid du Colombier default:
111442bd533dSDavid du Colombier exportpid = pid;
111542bd533dSDavid du Colombier break;
11167dd7cddfSDavid du Colombier case -1:
11179a747e4fSDavid du Colombier fprint(2, "cpu: can't start note proc: rfork: %r\n");
11187dd7cddfSDavid du Colombier return;
11197dd7cddfSDavid du Colombier case 0:
11207dd7cddfSDavid du Colombier close(pfd[0]);
11219a747e4fSDavid du Colombier if(mount(pfd[1], -1, "/dev", MBEFORE, "") < 0)
11229a747e4fSDavid du Colombier fprint(2, "cpu: can't mount note proc: %r\n");
11237dd7cddfSDavid du Colombier close(pfd[1]);
11247dd7cddfSDavid du Colombier return;
11257dd7cddfSDavid du Colombier }
11267dd7cddfSDavid du Colombier
11277dd7cddfSDavid du Colombier close(netfd);
11287dd7cddfSDavid du Colombier close(pfd[1]);
11297dd7cddfSDavid du Colombier
11307dd7cddfSDavid du Colombier /* new proc listens for note file system rpc's */
11317dd7cddfSDavid du Colombier switch(rfork(RFPROC|RFNAMEG|RFMEM)){
11327dd7cddfSDavid du Colombier case -1:
11339a747e4fSDavid du Colombier fprint(2, "cpu: can't start note proc: rfork1: %r\n");
11347dd7cddfSDavid du Colombier _exits(0);
11357dd7cddfSDavid du Colombier case 0:
11367dd7cddfSDavid du Colombier notefs(pfd[0]);
11377dd7cddfSDavid du Colombier _exits(0);
11387dd7cddfSDavid du Colombier }
11397dd7cddfSDavid du Colombier
11407dd7cddfSDavid du Colombier /* original proc waits for notes */
11417dd7cddfSDavid du Colombier notify(catcher);
11429a747e4fSDavid du Colombier w = nil;
11437dd7cddfSDavid du Colombier for(;;) {
11447dd7cddfSDavid du Colombier *notebuf = 0;
11459a747e4fSDavid du Colombier free(w);
11469a747e4fSDavid du Colombier w = wait();
11479a747e4fSDavid du Colombier if(w == nil) {
11487dd7cddfSDavid du Colombier if(*notebuf == 0)
11497dd7cddfSDavid du Colombier break;
11507dd7cddfSDavid du Colombier np = mallocz(sizeof(Note), 1);
11517dd7cddfSDavid du Colombier if(np != nil){
11527dd7cddfSDavid du Colombier strcpy(np->msg, notebuf);
11537dd7cddfSDavid du Colombier lock(&nfs);
11547dd7cddfSDavid du Colombier if(nfs.nfirst == nil)
11557dd7cddfSDavid du Colombier nfs.nfirst = np;
11567dd7cddfSDavid du Colombier else
11577dd7cddfSDavid du Colombier nfs.nlast->next = np;
11587dd7cddfSDavid du Colombier nfs.nlast = np;
11597dd7cddfSDavid du Colombier unlock(&nfs);
11607dd7cddfSDavid du Colombier kick(pfd[0]);
11617dd7cddfSDavid du Colombier }
11627dd7cddfSDavid du Colombier unlock(&nfs);
116342bd533dSDavid du Colombier } else if(w->pid == exportpid)
11647dd7cddfSDavid du Colombier break;
11657dd7cddfSDavid du Colombier }
11667dd7cddfSDavid du Colombier
11679a747e4fSDavid du Colombier if(w == nil)
11689a747e4fSDavid du Colombier exits(nil);
11692db064f5SDavid du Colombier exits(0);
11702db064f5SDavid du Colombier /* exits(w->msg); */
11717dd7cddfSDavid du Colombier }
1172