1 /* 2 * cpu.c - Make a connection to a cpu server 3 * 4 * Invoked by listen as 'cpu -R | -N service net netdir' 5 * by users as 'cpu [-h system] [-c cmd args ...]' 6 */ 7 8 #include <u.h> 9 #include <libc.h> 10 #include <bio.h> 11 #include <auth.h> 12 13 void remoteside(void); 14 void fatal(int, char*, ...); 15 void noteproc(char*); 16 void catcher(void*, char*); 17 void remotenote(void); 18 void usage(void); 19 void writestr(int, char*, char*, int); 20 int readstr(int, char*, int); 21 char *rexcall(int*, char*, char*); 22 23 int notechan; 24 char system[32]; 25 int cflag; 26 int hflag; 27 int dbg; 28 char notebuf[ERRLEN]; 29 30 char *srvname = "cpu"; 31 char *notesrv = "cpunote"; 32 char *exportfs = "/bin/exportfs"; 33 34 void 35 usage(void) 36 { 37 fprint(2, "usage: cpu [-h system] [-c cmd args ...]\n"); 38 exits("usage"); 39 } 40 41 void 42 main(int argc, char **argv) 43 { 44 char dat[128], buf[128], cmd[128], *p, *err; 45 int data; 46 47 ARGBEGIN{ 48 case 'd': 49 dbg++; 50 break; 51 case 'R': /* From listen */ 52 remoteside(); 53 break; 54 case 'N': 55 remotenote(); 56 break; 57 case 'h': 58 hflag++; 59 p = ARGF(); 60 if(p==0) 61 usage(); 62 strcpy(system, p); 63 break; 64 case 'c': 65 cflag++; 66 cmd[0] = '!'; 67 cmd[1] = '\0'; 68 while(p = ARGF()) { 69 strcat(cmd, " "); 70 strcat(cmd, p); 71 } 72 break; 73 }ARGEND; 74 75 if(argv); 76 if(argc != 0) 77 usage(); 78 79 if(hflag == 0) { 80 p = getenv("cpu"); 81 if(p == 0) 82 fatal(0, "set $cpu"); 83 strcpy(system, p); 84 } 85 86 if(err = rexcall(&data, system, srvname)) 87 fatal(1, "%s: %s", err, system); 88 89 /* Tell the remote side the command to execute and where our working directory is */ 90 if(cflag) 91 writestr(data, cmd, "command", 0); 92 if(getwd(dat, sizeof(dat)) == 0) 93 writestr(data, "NO", "dir", 0); 94 else 95 writestr(data, dat, "dir", 0); 96 97 if(readstr(data, buf, sizeof(buf)) < 0) 98 fatal(1, "bad pid"); 99 noteproc(buf); 100 101 /* Wait for the other end to execute and start our file service 102 * of /mnt/term */ 103 if(readstr(data, buf, sizeof(buf)) < 0) 104 fatal(1, "waiting for FS"); 105 if(strncmp("FS", buf, 2) != 0) { 106 print("remote cpu: %s", buf); 107 exits(buf); 108 } 109 110 /* Begin serving the gnot namespace */ 111 close(0); 112 dup(data, 0); 113 close(data); 114 if(dbg) 115 execl(exportfs, exportfs, "-d", 0); 116 else 117 execl(exportfs, exportfs, 0); 118 fatal(1, "starting exportfs"); 119 } 120 121 void 122 fatal(int syserr, char *fmt, ...) 123 { 124 char buf[ERRLEN]; 125 126 doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)); 127 if(syserr) 128 fprint(2, "cpu: %s: %r\n", buf); 129 else 130 fprint(2, "cpu: %s\n", buf); 131 exits(buf); 132 } 133 134 135 /* Invoked with stdin, stdout and stderr connected to the network connection */ 136 void 137 remoteside(void) 138 { 139 char user[NAMELEN], home[128], buf[128], xdir[128], cmd[128]; 140 int i, n, fd, badchdir, gotcmd; 141 142 if(srvauth(0, user) < 0) 143 fatal(1, "srvauth"); 144 if(newns(user, 0) < 0) 145 fatal(1, "newns"); 146 147 /* Set environment values for the user */ 148 putenv("user", user); 149 sprint(home, "/usr/%s", user); 150 putenv("home", home); 151 152 /* Now collect invoking cpus current directory or possibly a command */ 153 gotcmd = 0; 154 if(readstr(0, xdir, sizeof(xdir)) < 0) 155 fatal(1, "dir/cmd"); 156 if(xdir[0] == '!') { 157 strcpy(cmd, &xdir[1]); 158 gotcmd = 1; 159 if(readstr(0, xdir, sizeof(xdir)) < 0) 160 fatal(1, "dir"); 161 } 162 163 /* Establish the new process at the current working directory of the 164 * gnot */ 165 badchdir = 0; 166 if(strcmp(xdir, "NO") == 0) 167 chdir(home); 168 else if(chdir(xdir) < 0) { 169 badchdir = 1; 170 chdir(home); 171 } 172 173 sprint(buf, "%d", getpid()); 174 writestr(1, buf, "pid", 0); 175 176 /* Start the gnot serving its namespace */ 177 writestr(1, "FS", "FS", 0); 178 writestr(1, "/", "exportfs dir", 0); 179 180 n = read(1, buf, sizeof(buf)); 181 if(n != 2 || buf[0] != 'O' || buf[1] != 'K') 182 exits("remote tree"); 183 184 fd = dup(1, -1); 185 if(amount(fd, "/mnt/term", MREPL, "") < 0) 186 exits("mount failed"); 187 close(fd); 188 189 for(i = 0; i < 3; i++) 190 close(i); 191 192 if(open("/mnt/term/dev/cons", OREAD) != 0){ 193 exits("open stdin"); 194 } 195 if(open("/mnt/term/dev/cons", OWRITE) != 1){ 196 exits("open stdout"); 197 } 198 dup(1, 2); 199 200 if(badchdir) 201 print("cpu: failed to chdir to '%s'\n", xdir); 202 203 if(gotcmd) 204 execl("/bin/rc", "rc", "-lc", cmd, 0); 205 else 206 execl("/bin/rc", "rc", "-li", 0); 207 fatal(1, "exec shell"); 208 } 209 210 void 211 noteproc(char *pid) 212 { 213 char cmd[NAMELEN], syserr[ERRLEN], *err; 214 int notepid, n; 215 Waitmsg w; 216 217 notepid = fork(); 218 if(notepid < 0) 219 fatal(1, "forking noteproc"); 220 if(notepid == 0) 221 return; 222 223 if(err = rexcall(¬echan, system, notesrv)) 224 fprint(2, "cpu: can't dial for notify: %s: %r\n", err); 225 else{ 226 sprint(cmd, "%s", pid); 227 writestr(notechan, cmd, "notepid", 0); 228 } 229 230 notify(catcher); 231 232 for(;;) { 233 n = wait(&w); 234 if(n < 0) { 235 writestr(notechan, notebuf, "catcher", 1); 236 errstr(syserr); 237 if(strcmp(syserr, "interrupted") != 0){ 238 fprint(2, "cpu: wait: %s\n", syserr); 239 exits("waiterr"); 240 } 241 } 242 if(n == notepid) 243 break; 244 } 245 exits(w.msg); 246 } 247 248 void 249 catcher(void *a, char *text) 250 { 251 if(a); 252 strcpy(notebuf, text); 253 noted(NCONT); 254 } 255 256 void 257 remotenote(void) 258 { 259 int pid, e; 260 char buf[128]; 261 262 if(srvauth(0, buf) < 0) 263 exits("srvauth"); 264 if(readstr(0, buf, sizeof(buf)) < 0) 265 fatal(1, "read pid"); 266 pid = atoi(buf); 267 e = 0; 268 while(e == 0) { 269 if(readstr(0, buf, sizeof(buf)) < 0) { 270 strcpy(buf, "hangup"); 271 e = 1; 272 } 273 if(postnote(PNGROUP, pid, buf) < 0) 274 e = 1; 275 } 276 exits("remotenote"); 277 } 278 279 char* 280 rexcall(int *fd, char *host, char *service) 281 { 282 char *na; 283 284 na = netmkaddr(host, 0, service); 285 if((*fd = dial(na, 0, 0, 0)) < 0) 286 return "can't dial"; 287 if(auth(*fd) < 0) 288 return "can't authenticate"; 289 return 0; 290 } 291 292 void 293 writestr(int fd, char *str, char *thing, int ignore) 294 { 295 int l, n; 296 297 l = strlen(str); 298 n = write(fd, str, l+1); 299 if(!ignore && n < 0) 300 fatal(1, "writing network: %s", thing); 301 } 302 303 int 304 readstr(int fd, char *str, int len) 305 { 306 int n; 307 308 while(len) { 309 n = read(fd, str, 1); 310 if(n < 0) 311 return -1; 312 if(*str == '\0') 313 return 0; 314 str++; 315 len--; 316 } 317 return -1; 318 } 319