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