13e12c5d1SDavid du Colombier /* 23e12c5d1SDavid du Colombier * cpu.c - Make a connection to a cpu server 33e12c5d1SDavid du Colombier * 4*219b2ee8SDavid du Colombier * Invoked by listen as 'cpu -R | -N service net netdir' 5*219b2ee8SDavid 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> 123e12c5d1SDavid du Colombier 133e12c5d1SDavid du Colombier void remoteside(void); 143e12c5d1SDavid du Colombier void fatal(int, char*, ...); 153e12c5d1SDavid du Colombier void noteproc(char*); 163e12c5d1SDavid du Colombier void catcher(void*, char*); 173e12c5d1SDavid du Colombier void remotenote(void); 183e12c5d1SDavid du Colombier void usage(void); 193e12c5d1SDavid du Colombier void writestr(int, char*, char*, int); 20*219b2ee8SDavid du Colombier int readstr(int, char*, int); 213e12c5d1SDavid du Colombier char *rexcall(int*, char*, char*); 223e12c5d1SDavid du Colombier 233e12c5d1SDavid du Colombier int notechan; 243e12c5d1SDavid du Colombier char system[32]; 253e12c5d1SDavid du Colombier int cflag; 263e12c5d1SDavid du Colombier int hflag; 27*219b2ee8SDavid du Colombier int dbg; 28*219b2ee8SDavid du Colombier char notebuf[ERRLEN]; 293e12c5d1SDavid du Colombier 303e12c5d1SDavid du Colombier char *srvname = "cpu"; 313e12c5d1SDavid du Colombier char *notesrv = "cpunote"; 323e12c5d1SDavid du Colombier char *exportfs = "/bin/exportfs"; 333e12c5d1SDavid du Colombier 343e12c5d1SDavid du Colombier void 35*219b2ee8SDavid du Colombier usage(void) 36*219b2ee8SDavid du Colombier { 37*219b2ee8SDavid du Colombier fprint(2, "usage: cpu [-h system] [-c cmd args ...]\n"); 38*219b2ee8SDavid du Colombier exits("usage"); 39*219b2ee8SDavid du Colombier } 40*219b2ee8SDavid du Colombier 41*219b2ee8SDavid du Colombier void 423e12c5d1SDavid du Colombier main(int argc, char **argv) 433e12c5d1SDavid du Colombier { 443e12c5d1SDavid du Colombier char dat[128], buf[128], cmd[128], *p, *err; 453e12c5d1SDavid du Colombier int data; 463e12c5d1SDavid du Colombier 473e12c5d1SDavid du Colombier ARGBEGIN{ 48*219b2ee8SDavid du Colombier case 'd': 49*219b2ee8SDavid du Colombier dbg++; 50*219b2ee8SDavid du Colombier break; 513e12c5d1SDavid du Colombier case 'R': /* From listen */ 523e12c5d1SDavid du Colombier remoteside(); 533e12c5d1SDavid du Colombier break; 543e12c5d1SDavid du Colombier case 'N': 553e12c5d1SDavid du Colombier remotenote(); 563e12c5d1SDavid du Colombier break; 573e12c5d1SDavid du Colombier case 'h': 583e12c5d1SDavid du Colombier hflag++; 593e12c5d1SDavid du Colombier p = ARGF(); 603e12c5d1SDavid du Colombier if(p==0) 613e12c5d1SDavid du Colombier usage(); 623e12c5d1SDavid du Colombier strcpy(system, p); 633e12c5d1SDavid du Colombier break; 643e12c5d1SDavid du Colombier case 'c': 653e12c5d1SDavid du Colombier cflag++; 663e12c5d1SDavid du Colombier cmd[0] = '!'; 673e12c5d1SDavid du Colombier cmd[1] = '\0'; 683e12c5d1SDavid du Colombier while(p = ARGF()) { 693e12c5d1SDavid du Colombier strcat(cmd, " "); 703e12c5d1SDavid du Colombier strcat(cmd, p); 713e12c5d1SDavid du Colombier } 723e12c5d1SDavid du Colombier break; 733e12c5d1SDavid du Colombier }ARGEND; 743e12c5d1SDavid du Colombier 753e12c5d1SDavid du Colombier if(argv); 763e12c5d1SDavid du Colombier if(argc != 0) 773e12c5d1SDavid du Colombier usage(); 783e12c5d1SDavid du Colombier 793e12c5d1SDavid du Colombier if(hflag == 0) { 803e12c5d1SDavid du Colombier p = getenv("cpu"); 813e12c5d1SDavid du Colombier if(p == 0) 823e12c5d1SDavid du Colombier fatal(0, "set $cpu"); 833e12c5d1SDavid du Colombier strcpy(system, p); 843e12c5d1SDavid du Colombier } 853e12c5d1SDavid du Colombier 863e12c5d1SDavid du Colombier if(err = rexcall(&data, system, srvname)) 873e12c5d1SDavid du Colombier fatal(1, "%s: %s", err, system); 883e12c5d1SDavid du Colombier 893e12c5d1SDavid du Colombier /* Tell the remote side the command to execute and where our working directory is */ 903e12c5d1SDavid du Colombier if(cflag) 913e12c5d1SDavid du Colombier writestr(data, cmd, "command", 0); 923e12c5d1SDavid du Colombier if(getwd(dat, sizeof(dat)) == 0) 933e12c5d1SDavid du Colombier writestr(data, "NO", "dir", 0); 943e12c5d1SDavid du Colombier else 953e12c5d1SDavid du Colombier writestr(data, dat, "dir", 0); 963e12c5d1SDavid du Colombier 97*219b2ee8SDavid du Colombier if(readstr(data, buf, sizeof(buf)) < 0) 98*219b2ee8SDavid du Colombier fatal(1, "bad pid"); 993e12c5d1SDavid du Colombier noteproc(buf); 1003e12c5d1SDavid du Colombier 1013e12c5d1SDavid du Colombier /* Wait for the other end to execute and start our file service 1023e12c5d1SDavid du Colombier * of /mnt/term */ 103*219b2ee8SDavid du Colombier if(readstr(data, buf, sizeof(buf)) < 0) 104*219b2ee8SDavid du Colombier fatal(1, "waiting for FS"); 1053e12c5d1SDavid du Colombier if(strncmp("FS", buf, 2) != 0) { 1063e12c5d1SDavid du Colombier print("remote cpu: %s", buf); 1073e12c5d1SDavid du Colombier exits(buf); 1083e12c5d1SDavid du Colombier } 1093e12c5d1SDavid du Colombier 1103e12c5d1SDavid du Colombier /* Begin serving the gnot namespace */ 1113e12c5d1SDavid du Colombier close(0); 1123e12c5d1SDavid du Colombier dup(data, 0); 1133e12c5d1SDavid du Colombier close(data); 114*219b2ee8SDavid du Colombier if(dbg) 115*219b2ee8SDavid du Colombier execl(exportfs, exportfs, "-d", 0); 116*219b2ee8SDavid du Colombier else 1173e12c5d1SDavid du Colombier execl(exportfs, exportfs, 0); 1183e12c5d1SDavid du Colombier fatal(1, "starting exportfs"); 1193e12c5d1SDavid du Colombier } 1203e12c5d1SDavid du Colombier 1213e12c5d1SDavid du Colombier void 1223e12c5d1SDavid du Colombier fatal(int syserr, char *fmt, ...) 1233e12c5d1SDavid du Colombier { 1243e12c5d1SDavid du Colombier char buf[ERRLEN]; 1253e12c5d1SDavid du Colombier 1263e12c5d1SDavid du Colombier doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)); 1273e12c5d1SDavid du Colombier if(syserr) 1283e12c5d1SDavid du Colombier fprint(2, "cpu: %s: %r\n", buf); 1293e12c5d1SDavid du Colombier else 1303e12c5d1SDavid du Colombier fprint(2, "cpu: %s\n", buf); 1313e12c5d1SDavid du Colombier exits(buf); 1323e12c5d1SDavid du Colombier } 1333e12c5d1SDavid du Colombier 134*219b2ee8SDavid du Colombier 1353e12c5d1SDavid du Colombier /* Invoked with stdin, stdout and stderr connected to the network connection */ 1363e12c5d1SDavid du Colombier void 1373e12c5d1SDavid du Colombier remoteside(void) 1383e12c5d1SDavid du Colombier { 139*219b2ee8SDavid du Colombier char user[NAMELEN], home[128], buf[128], xdir[128], cmd[128]; 1403e12c5d1SDavid du Colombier int i, n, fd, badchdir, gotcmd; 1413e12c5d1SDavid du Colombier 142*219b2ee8SDavid du Colombier if(srvauth(0, user) < 0) 143*219b2ee8SDavid du Colombier fatal(1, "srvauth"); 144*219b2ee8SDavid du Colombier if(newns(user, 0) < 0) 145*219b2ee8SDavid du Colombier fatal(1, "newns"); 1463e12c5d1SDavid du Colombier 1473e12c5d1SDavid du Colombier /* Set environment values for the user */ 1483e12c5d1SDavid du Colombier putenv("user", user); 1493e12c5d1SDavid du Colombier sprint(home, "/usr/%s", user); 1503e12c5d1SDavid du Colombier putenv("home", home); 1513e12c5d1SDavid du Colombier 1523e12c5d1SDavid du Colombier /* Now collect invoking cpus current directory or possibly a command */ 1533e12c5d1SDavid du Colombier gotcmd = 0; 154*219b2ee8SDavid du Colombier if(readstr(0, xdir, sizeof(xdir)) < 0) 155*219b2ee8SDavid du Colombier fatal(1, "dir/cmd"); 1563e12c5d1SDavid du Colombier if(xdir[0] == '!') { 1573e12c5d1SDavid du Colombier strcpy(cmd, &xdir[1]); 1583e12c5d1SDavid du Colombier gotcmd = 1; 159*219b2ee8SDavid du Colombier if(readstr(0, xdir, sizeof(xdir)) < 0) 160*219b2ee8SDavid du Colombier fatal(1, "dir"); 1613e12c5d1SDavid du Colombier } 1623e12c5d1SDavid du Colombier 1633e12c5d1SDavid du Colombier /* Establish the new process at the current working directory of the 1643e12c5d1SDavid du Colombier * gnot */ 1653e12c5d1SDavid du Colombier badchdir = 0; 1663e12c5d1SDavid du Colombier if(strcmp(xdir, "NO") == 0) 1673e12c5d1SDavid du Colombier chdir(home); 1683e12c5d1SDavid du Colombier else if(chdir(xdir) < 0) { 1693e12c5d1SDavid du Colombier badchdir = 1; 1703e12c5d1SDavid du Colombier chdir(home); 1713e12c5d1SDavid du Colombier } 1723e12c5d1SDavid du Colombier 1733e12c5d1SDavid du Colombier sprint(buf, "%d", getpid()); 1743e12c5d1SDavid du Colombier writestr(1, buf, "pid", 0); 1753e12c5d1SDavid du Colombier 1763e12c5d1SDavid du Colombier /* Start the gnot serving its namespace */ 1773e12c5d1SDavid du Colombier writestr(1, "FS", "FS", 0); 1783e12c5d1SDavid du Colombier writestr(1, "/", "exportfs dir", 0); 1793e12c5d1SDavid du Colombier 1803e12c5d1SDavid du Colombier n = read(1, buf, sizeof(buf)); 1813e12c5d1SDavid du Colombier if(n != 2 || buf[0] != 'O' || buf[1] != 'K') 1823e12c5d1SDavid du Colombier exits("remote tree"); 1833e12c5d1SDavid du Colombier 1843e12c5d1SDavid du Colombier fd = dup(1, -1); 185*219b2ee8SDavid du Colombier if(amount(fd, "/mnt/term", MREPL, "") < 0) 1863e12c5d1SDavid du Colombier exits("mount failed"); 1873e12c5d1SDavid du Colombier close(fd); 1883e12c5d1SDavid du Colombier 1893e12c5d1SDavid du Colombier for(i = 0; i < 3; i++) 1903e12c5d1SDavid du Colombier close(i); 1913e12c5d1SDavid du Colombier 192*219b2ee8SDavid du Colombier if(open("/mnt/term/dev/cons", OREAD) != 0){ 1933e12c5d1SDavid du Colombier exits("open stdin"); 194*219b2ee8SDavid du Colombier } 195*219b2ee8SDavid du Colombier if(open("/mnt/term/dev/cons", OWRITE) != 1){ 1963e12c5d1SDavid du Colombier exits("open stdout"); 197*219b2ee8SDavid du Colombier } 1983e12c5d1SDavid du Colombier dup(1, 2); 1993e12c5d1SDavid du Colombier 2003e12c5d1SDavid du Colombier if(badchdir) 2013e12c5d1SDavid du Colombier print("cpu: failed to chdir to '%s'\n", xdir); 2023e12c5d1SDavid du Colombier 2033e12c5d1SDavid du Colombier if(gotcmd) 2043e12c5d1SDavid du Colombier execl("/bin/rc", "rc", "-lc", cmd, 0); 2053e12c5d1SDavid du Colombier else 2063e12c5d1SDavid du Colombier execl("/bin/rc", "rc", "-li", 0); 2073e12c5d1SDavid du Colombier fatal(1, "exec shell"); 2083e12c5d1SDavid du Colombier } 2093e12c5d1SDavid du Colombier 2103e12c5d1SDavid du Colombier void 2113e12c5d1SDavid du Colombier noteproc(char *pid) 2123e12c5d1SDavid du Colombier { 2133e12c5d1SDavid du Colombier char cmd[NAMELEN], syserr[ERRLEN], *err; 2143e12c5d1SDavid du Colombier int notepid, n; 2153e12c5d1SDavid du Colombier Waitmsg w; 2163e12c5d1SDavid du Colombier 2173e12c5d1SDavid du Colombier notepid = fork(); 2183e12c5d1SDavid du Colombier if(notepid < 0) 2193e12c5d1SDavid du Colombier fatal(1, "forking noteproc"); 2203e12c5d1SDavid du Colombier if(notepid == 0) 2213e12c5d1SDavid du Colombier return; 2223e12c5d1SDavid du Colombier 2233e12c5d1SDavid du Colombier if(err = rexcall(¬echan, system, notesrv)) 2243e12c5d1SDavid du Colombier fprint(2, "cpu: can't dial for notify: %s: %r\n", err); 2253e12c5d1SDavid du Colombier else{ 2263e12c5d1SDavid du Colombier sprint(cmd, "%s", pid); 2273e12c5d1SDavid du Colombier writestr(notechan, cmd, "notepid", 0); 2283e12c5d1SDavid du Colombier } 2293e12c5d1SDavid du Colombier 230*219b2ee8SDavid du Colombier notify(catcher); 231*219b2ee8SDavid du Colombier 2323e12c5d1SDavid du Colombier for(;;) { 2333e12c5d1SDavid du Colombier n = wait(&w); 2343e12c5d1SDavid du Colombier if(n < 0) { 235*219b2ee8SDavid du Colombier writestr(notechan, notebuf, "catcher", 1); 2363e12c5d1SDavid du Colombier errstr(syserr); 2373e12c5d1SDavid du Colombier if(strcmp(syserr, "interrupted") != 0){ 2383e12c5d1SDavid du Colombier fprint(2, "cpu: wait: %s\n", syserr); 2393e12c5d1SDavid du Colombier exits("waiterr"); 2403e12c5d1SDavid du Colombier } 2413e12c5d1SDavid du Colombier } 2423e12c5d1SDavid du Colombier if(n == notepid) 2433e12c5d1SDavid du Colombier break; 2443e12c5d1SDavid du Colombier } 2453e12c5d1SDavid du Colombier exits(w.msg); 2463e12c5d1SDavid du Colombier } 2473e12c5d1SDavid du Colombier 2483e12c5d1SDavid du Colombier void 2493e12c5d1SDavid du Colombier catcher(void *a, char *text) 2503e12c5d1SDavid du Colombier { 2513e12c5d1SDavid du Colombier if(a); 252*219b2ee8SDavid du Colombier strcpy(notebuf, text); 2533e12c5d1SDavid du Colombier noted(NCONT); 2543e12c5d1SDavid du Colombier } 2553e12c5d1SDavid du Colombier 2563e12c5d1SDavid du Colombier void 2573e12c5d1SDavid du Colombier remotenote(void) 2583e12c5d1SDavid du Colombier { 259*219b2ee8SDavid du Colombier int pid, e; 260*219b2ee8SDavid du Colombier char buf[128]; 2613e12c5d1SDavid du Colombier 262*219b2ee8SDavid du Colombier if(srvauth(0, buf) < 0) 263*219b2ee8SDavid du Colombier exits("srvauth"); 264*219b2ee8SDavid du Colombier if(readstr(0, buf, sizeof(buf)) < 0) 265*219b2ee8SDavid du Colombier fatal(1, "read pid"); 266*219b2ee8SDavid du Colombier pid = atoi(buf); 267*219b2ee8SDavid du Colombier e = 0; 268*219b2ee8SDavid du Colombier while(e == 0) { 269*219b2ee8SDavid du Colombier if(readstr(0, buf, sizeof(buf)) < 0) { 270*219b2ee8SDavid du Colombier strcpy(buf, "hangup"); 271*219b2ee8SDavid du Colombier e = 1; 2723e12c5d1SDavid du Colombier } 273*219b2ee8SDavid du Colombier if(postnote(PNGROUP, pid, buf) < 0) 274*219b2ee8SDavid du Colombier e = 1; 2753e12c5d1SDavid du Colombier } 276*219b2ee8SDavid du Colombier exits("remotenote"); 2773e12c5d1SDavid du Colombier } 2783e12c5d1SDavid du Colombier 2793e12c5d1SDavid du Colombier char* 2803e12c5d1SDavid du Colombier rexcall(int *fd, char *host, char *service) 2813e12c5d1SDavid du Colombier { 2823e12c5d1SDavid du Colombier char *na; 2833e12c5d1SDavid du Colombier 2843e12c5d1SDavid du Colombier na = netmkaddr(host, 0, service); 2853e12c5d1SDavid du Colombier if((*fd = dial(na, 0, 0, 0)) < 0) 2863e12c5d1SDavid du Colombier return "can't dial"; 287*219b2ee8SDavid du Colombier if(auth(*fd) < 0) 288*219b2ee8SDavid du Colombier return "can't authenticate"; 2893e12c5d1SDavid du Colombier return 0; 2903e12c5d1SDavid du Colombier } 2913e12c5d1SDavid du Colombier 2923e12c5d1SDavid du Colombier void 2933e12c5d1SDavid du Colombier writestr(int fd, char *str, char *thing, int ignore) 2943e12c5d1SDavid du Colombier { 2953e12c5d1SDavid du Colombier int l, n; 2963e12c5d1SDavid du Colombier 2973e12c5d1SDavid du Colombier l = strlen(str); 2983e12c5d1SDavid du Colombier n = write(fd, str, l+1); 2993e12c5d1SDavid du Colombier if(!ignore && n < 0) 3003e12c5d1SDavid du Colombier fatal(1, "writing network: %s", thing); 3013e12c5d1SDavid du Colombier } 3023e12c5d1SDavid du Colombier 303*219b2ee8SDavid du Colombier int 304*219b2ee8SDavid du Colombier readstr(int fd, char *str, int len) 3053e12c5d1SDavid du Colombier { 3063e12c5d1SDavid du Colombier int n; 3073e12c5d1SDavid du Colombier 3083e12c5d1SDavid du Colombier while(len) { 3093e12c5d1SDavid du Colombier n = read(fd, str, 1); 310*219b2ee8SDavid du Colombier if(n < 0) 311*219b2ee8SDavid du Colombier return -1; 3123e12c5d1SDavid du Colombier if(*str == '\0') 313*219b2ee8SDavid du Colombier return 0; 3143e12c5d1SDavid du Colombier str++; 3153e12c5d1SDavid du Colombier len--; 3163e12c5d1SDavid du Colombier } 317*219b2ee8SDavid du Colombier return -1; 3183e12c5d1SDavid du Colombier } 319