1 #define INFERNO_KEEPENVIRON 2 #include "mk.h" 3 #include <signal.h> 4 #include <sys/utime.h> 5 6 #define Arc My_Arc /* avoid name conflicts */ 7 #undef DELETE 8 9 #include <windows.h> 10 11 enum { 12 Nchild = 100, 13 }; 14 15 char *rootdir = ROOT; 16 char *shell = "Nt/386/bin/rcsh.exe"; /* Path relative to root */ 17 18 typedef struct Child Child; 19 20 struct Child { 21 int pid; 22 HANDLE handle; 23 }; 24 25 static Child child[Nchild]; 26 27 extern char **environ; 28 29 DWORD WINAPI writecmd(LPVOID a); 30 31 void 32 readenv(void) 33 { 34 char **p, *s; 35 Word *w; 36 37 for(p = environ; *p; p++){ 38 s = shname(*p); 39 if(*s == '=') { 40 *s = 0; 41 w = newword(s+1); 42 } else 43 w = newword(""); 44 if (symlook(*p, S_INTERNAL, 0)) 45 continue; 46 s = strdup(*p); 47 setvar(s, (void *)w); 48 symlook(s, S_EXPORTED, (void *)"")->value = ""; 49 } 50 } 51 52 char * 53 exportenv(Envy *e) 54 { 55 int i, n; 56 char *buf, *v; 57 58 buf = 0; 59 n = 0; 60 for(i = 0; e->name; e++, i++) { 61 /* word separator is shell-dependent */ 62 if(e->values) 63 v = wtos(e->values, IWS); 64 else 65 v = ""; 66 buf = Realloc(buf, n+strlen(e->name)+1+strlen(v)+1); 67 68 n += sprint(buf+n, "%s=%s", e->name, v); 69 n++; /* skip over null */ 70 if(e->values) 71 free(v); 72 } 73 /* final null */ 74 buf = Realloc(buf, n+1); 75 buf[n] = 0; 76 77 return buf; 78 } 79 80 int 81 waitfor(char *msg) 82 { 83 int pid, n, i, r, code; 84 HANDLE tab[Nchild]; 85 86 for(i=0,n=0; i<Nchild; i++) 87 if(child[i].handle != 0) 88 tab[n++] = child[i].handle; 89 90 if(n == 0) 91 return -1; 92 93 r = WaitForMultipleObjects(n, tab, 0, INFINITE); 94 95 r -= WAIT_OBJECT_0; 96 if(r<0 || r>=n) { 97 perror("wait failed"); 98 exits("wait failed"); 99 } 100 101 for(i=0; i<Nchild; i++) 102 if(child[i].handle == tab[r]) 103 break; 104 if(i == Nchild){ 105 snprint(msg, ERRMAX, "unknown child (%lux)", tab[r]); 106 return -1; 107 } 108 109 if(msg) { 110 *msg = 0; 111 if(GetExitCodeProcess(child[i].handle, &code) == FALSE) 112 snprint(msg, ERRMAX, "unknown exit code"); 113 else if(code != 0) 114 snprint(msg, ERRMAX, "exit(%d)", code); 115 } 116 117 CloseHandle(child[i].handle); 118 child[i].handle = 0; 119 pid = child[i].pid; 120 child[i].pid = 0; 121 122 return pid; 123 } 124 125 void 126 expunge(int pid, char *msg) 127 { 128 /* 129 if(strcmp(msg, "interrupt")) 130 kill(pid, SIGINT); 131 else 132 kill(pid, SIGHUP); 133 */ 134 } 135 136 HANDLE 137 duphandle(HANDLE h) 138 { 139 HANDLE r; 140 141 if(DuplicateHandle(GetCurrentProcess(), h, 142 GetCurrentProcess(), &r, DUPLICATE_SAME_ACCESS, 143 1, DUPLICATE_SAME_ACCESS) == FALSE) { 144 perror("dup handle"); 145 Exit(); 146 } 147 148 return r; 149 } 150 151 void 152 childadd(HANDLE h, int pid) 153 { 154 int i; 155 156 for(i=0; i<Nchild; i++) { 157 if(child[i].handle == 0) { 158 child[i].handle = h; 159 child[i].pid = pid; 160 return; 161 } 162 } 163 perror("child table full"); 164 Exit(); 165 } 166 167 static DWORD WINAPI 168 spinoff(HANDLE in, HANDLE out, char *args, char *cmd, Envy *e) 169 { 170 char args2[4096], path[MAX_PATH], *s, *eb; 171 STARTUPINFO si; 172 PROCESS_INFORMATION pi; 173 Symtab *sym; 174 175 176 /* set up the full path of the shell */ 177 sym = symlook("MKSH", S_VAR, 0); 178 if(sym){ 179 strncpy(path, ((Word*)(sym->value))->s, sizeof(path)); 180 path[MAX_PATH-1] = 0; 181 }else{ 182 sym = symlook("ROOT", S_VAR, 0); 183 if(sym) 184 rootdir = ((Word*)(sym->value))->s; 185 snprint(path, sizeof(path), "%s\\%s", rootdir, shell); 186 } 187 /* convert to backslash notation */ 188 for(s = strchr(path,'/'); s; s = strchr(s+1, '/')) 189 *s = '\\'; 190 191 s = args2; 192 s += snprint(args2, sizeof(args2)-1, "%s", path); 193 if(shflags) 194 s += snprint(s, args2+sizeof(args2)-s-1, " %s", shflags); 195 if(args) 196 s += snprint(s, args2+sizeof(args2)-s-1, " %s", args); 197 if(cmd) 198 s += snprint(s, args2+sizeof(args2)-s-1, " \"%s\"", cmd); 199 200 memset(&si, 0, sizeof(si)); 201 si.cb = sizeof(si); 202 si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES; 203 si.wShowWindow = SW_SHOW; 204 205 if (e) 206 eb = exportenv(e); 207 else 208 eb = 0; 209 si.hStdInput = duphandle(in); 210 si.hStdOutput = duphandle(out); 211 si.hStdError = duphandle(GetStdHandle(STD_ERROR_HANDLE)); 212 if(CreateProcess(path, args2, 0, 0, 1, 0, eb, 0, &si, &pi) == FALSE) { 213 perror("can't find shell"); 214 Exit(); 215 } 216 217 free(eb); 218 219 CloseHandle(si.hStdInput); 220 CloseHandle(si.hStdOutput); 221 CloseHandle(si.hStdError); 222 223 childadd(pi.hProcess, pi.dwProcessId); 224 return pi.dwProcessId; 225 } 226 227 int 228 execsh(char *args, char *cmd, Bufblock *buf, Envy *e) 229 { 230 int tot, n, tid, pid; 231 HANDLE outin, outout, inout, inin; 232 struct { char *cmd; HANDLE handle; } *arg; 233 234 if(buf == 0) 235 outout = GetStdHandle(STD_OUTPUT_HANDLE); 236 else 237 if(CreatePipe(&outin, &outout, 0, 0) == FALSE){ 238 perror("pipe"); 239 Exit(); 240 } 241 242 if(CreatePipe(&inin, &inout, 0, 0) == FALSE){ 243 perror("pipe"); 244 Exit(); 245 } 246 247 arg = malloc(sizeof(*arg)); 248 arg->cmd = strdup(cmd); 249 arg->handle = inout; 250 if(CreateThread(0, 0, writecmd, arg, 0, &tid) == FALSE) { 251 perror("spawn writecmd"); 252 Exit(); 253 } 254 255 pid = spinoff(inin, outout, args, 0, e); 256 CloseHandle(inin); 257 258 if(DEBUG(D_EXEC)) 259 fprint(1, "starting: %s\n", cmd); 260 261 if(buf){ 262 CloseHandle(outout); 263 tot = 0; 264 for(;;){ 265 if (buf->current >= buf->end) 266 growbuf(buf); 267 if(ReadFile(outin, buf->current, buf->end-buf->current, &n, 0) == FALSE) 268 break; 269 buf->current += n; 270 tot += n; 271 } 272 if (tot && buf->current[-1] == '\n') 273 buf->current--; 274 CloseHandle(outin); 275 } 276 277 return pid; 278 } 279 280 static DWORD WINAPI 281 writecmd(LPVOID a) 282 { 283 struct {char *cmd; HANDLE handle;} *arg; 284 char *cmd, *p; 285 int n; 286 287 arg = a; 288 cmd = arg->cmd; 289 p = cmd+strlen(cmd); 290 while(cmd < p){ 291 if(WriteFile(arg->handle, cmd, p-cmd, &n, 0) == FALSE) 292 break; 293 cmd += n; 294 } 295 296 free(arg->cmd); 297 CloseHandle(arg->handle); 298 free(arg); 299 ExitThread(0); 300 return 0; 301 } 302 303 int 304 pipecmd(char *cmd, Envy *e, int *fd) 305 { 306 int pid; 307 HANDLE pipein, pipeout; 308 309 if(fd){ 310 if(CreatePipe(&pipein, &pipeout, 0, 0) == FALSE){ 311 perror("pipe"); 312 Exit(); 313 } 314 } else 315 pipeout = GetStdHandle(STD_OUTPUT_HANDLE); 316 317 318 pid = spinoff(GetStdHandle(STD_INPUT_HANDLE), pipeout, "-c", cmd, e); 319 320 if(fd){ 321 CloseHandle(pipeout); 322 *fd = _open_osfhandle((long)pipein, 0); 323 } 324 return pid; 325 } 326 327 void 328 Exit(void) 329 { 330 while(waitfor(0) != -1) 331 ; 332 exits("error"); 333 } 334 335 void 336 catchnotes() 337 { 338 } 339 340 char* 341 maketmp(void) 342 { 343 static char temp[] = "mkargsXXXXXXXXXXX"; 344 345 mktemp(temp); 346 return temp; 347 } 348 349 Dir* 350 mkdirstat(char *name) 351 { 352 int c, n; 353 Dir *buf; 354 355 n = strlen(name)-1; 356 c = name[n]; 357 if(c == '/' || c == '\\') 358 name[n] = 0; 359 buf = dirstat(name); 360 name[n] = c; 361 return buf; 362 } 363 364 int 365 chgtime(char *name) 366 { 367 Dir *sbuf; 368 struct utimbuf u; 369 370 if((sbuf = mkdirstat(name)) != nil){ 371 u.actime = sbuf->atime; 372 u.modtime = time(0); 373 free(sbuf); 374 return utime(name, &u); 375 } 376 return close(create(name, OWRITE, 0666)); 377 } 378 379 void 380 rcopy(char **to, Resub *match, int n) 381 { 382 int c; 383 char *p; 384 385 *to = match->s.sp; /* stem0 matches complete target */ 386 for(to++, match++; --n > 0; to++, match++){ 387 if(match->s.sp && match->e.ep){ 388 p = match->e.ep; 389 c = *p; 390 *p = 0; 391 *to = strdup(match->s.sp); 392 *p = c; 393 } else 394 *to = 0; 395 } 396 } 397 398 ulong 399 mkmtime(char *name) 400 { 401 Dir *buf; 402 ulong t; 403 int n; 404 char *s; 405 406 n = strlen(name)-1; 407 if(n >= 0 && (name[n] == '/' || name[n] == '\\')){ 408 s = strdup(name); 409 s[n] = 0; 410 }else 411 s = name; 412 buf = dirstat(s); 413 if(buf == nil){ 414 if(s != name) 415 free(s); 416 return 0; 417 } 418 t = buf->mtime; 419 free(buf); 420 if(s != name) 421 free(s); 422 return t; 423 } 424 425 char *stab; 426 427 char * 428 membername(char *s, int fd, char *sz) 429 { 430 long t; 431 432 if(s[0] == '/' && s[1] == '\0'){ /* long file name string table */ 433 t = atol(sz); 434 if(t&01) t++; 435 stab = malloc(t); 436 read(fd, stab, t); 437 return nil; 438 } 439 else if(s[0] == '/' && stab != nil) /* index into string table */ 440 return stab+atol(s+1); 441 else 442 return s; 443 } 444