1 /* 2 * PROJECT: ReactOS CRT library 3 * LICENSE: GPL (?) - See COPYING in the top level directory 4 * FILE: lib/sdk/crt/process/process.c 5 * PURPOSE: Process management functions 6 * PROGRAMMERS: ??? 7 */ 8 9 #include <precomp.h> 10 #include <process.h> 11 #include <tchar.h> 12 #include <internal/wine/msvcrt.h> 13 14 #ifdef _UNICODE 15 #define sT "S" 16 #define find_execT find_execW 17 #define argvtosT argvtosW 18 #define do_spawnT do_spawnW 19 #define valisttosT valisttosW 20 #define extT extW 21 #define access_dirT access_dirW 22 #else 23 #define sT "s" 24 #define find_execT find_execA 25 #define argvtosT argvtosA 26 #define do_spawnT do_spawnA 27 #define valisttosT valisttosA 28 #define extT extA 29 #define access_dirT access_dirA 30 #endif 31 32 #define MK_STR(s) #s 33 34 int access_dirT(const _TCHAR *_path); 35 36 _TCHAR const* extT[] = 37 { 38 _T(""), 39 _T(".bat"), 40 _T(".cmd"), 41 _T(".com"), 42 _T(".exe") 43 }; 44 45 const _TCHAR* find_execT(const _TCHAR* path, _TCHAR* rpath) 46 { 47 _TCHAR *rp; 48 const _TCHAR *rd; 49 unsigned int i, found = 0; 50 51 TRACE(MK_STR(find_execT)"('%"sT"', %x)\n", path, rpath); 52 53 if (path == NULL) 54 { 55 return NULL; 56 } 57 if (_tcslen(path) > FILENAME_MAX - 1) 58 { 59 return path; 60 } 61 /* copy path in rpath */ 62 for (rd = path, rp = rpath; *rd; *rp++ = *rd++) 63 ; 64 *rp = 0; 65 /* try first with the name as is */ 66 for (i = 0; i < sizeof(extT) / sizeof(*extT); i++) 67 { 68 _tcscpy(rp, extT[i]); 69 70 TRACE("trying '%"sT"'\n", rpath); 71 72 if (_taccess(rpath, F_OK) == 0 && access_dirT(rpath) != 0) 73 { 74 found = 1; 75 break; 76 } 77 } 78 if (!found) 79 { 80 _TCHAR* env = _tgetenv(_T("PATH")); 81 if (env) 82 { 83 _TCHAR* ep = env; 84 while (*ep && !found) 85 { 86 if (*ep == ';') 87 ep++; 88 rp=rpath; 89 for (; *ep && (*ep != ';'); *rp++ = *ep++) 90 ; 91 if (rp > rpath) 92 { 93 rp--; 94 if (*rp != '/' && *rp != '\\') 95 { 96 *++rp = '\\'; 97 } 98 rp++; 99 } 100 for (rd=path; *rd; *rp++ = *rd++) 101 ; 102 for (i = 0; i < sizeof(extT) / sizeof(*extT); i++) 103 { 104 _tcscpy(rp, extT[i]); 105 106 TRACE("trying '%"sT"'\n", rpath); 107 108 if (_taccess(rpath, F_OK) == 0 && access_dirT(rpath) != 0) 109 { 110 found = 1; 111 break; 112 } 113 } 114 } 115 } 116 } 117 118 return found ? rpath : path; 119 } 120 121 static _TCHAR* 122 argvtosT(const _TCHAR* const* argv, _TCHAR delim) 123 { 124 int i; 125 size_t len; 126 _TCHAR *ptr, *str; 127 128 if (argv == NULL) 129 return NULL; 130 131 for (i = 0, len = 0; argv[i]; i++) 132 { 133 len += _tcslen(argv[i]) + 1; 134 } 135 136 str = ptr = (_TCHAR*) malloc((len + 1) * sizeof(_TCHAR)); 137 if (str == NULL) 138 return NULL; 139 140 for(i = 0; argv[i]; i++) 141 { 142 len = _tcslen(argv[i]); 143 memcpy(ptr, argv[i], len * sizeof(_TCHAR)); 144 ptr += len; 145 *ptr++ = delim; 146 } 147 *ptr = 0; 148 149 return str; 150 } 151 152 static _TCHAR* 153 valisttosT(const _TCHAR* arg0, va_list alist, _TCHAR delim) 154 { 155 va_list alist2; 156 _TCHAR *ptr, *str; 157 size_t len; 158 159 if (arg0 == NULL) 160 return NULL; 161 162 va_copy(alist2, alist); 163 ptr = (_TCHAR*)arg0; 164 len = 0; 165 do 166 { 167 len += _tcslen(ptr) + 1; 168 ptr = va_arg(alist, _TCHAR*); 169 } 170 while(ptr != NULL); 171 172 str = (_TCHAR*) malloc((len + 1) * sizeof(_TCHAR)); 173 if (str == NULL) 174 { 175 va_end(alist2); 176 return NULL; 177 } 178 179 ptr = str; 180 do 181 { 182 len = _tcslen(arg0); 183 memcpy(ptr, arg0, len * sizeof(_TCHAR)); 184 ptr += len; 185 *ptr++ = delim; 186 arg0 = va_arg(alist2, _TCHAR*); 187 } 188 while(arg0 != NULL); 189 *ptr = 0; 190 191 va_end(alist2); 192 return str; 193 } 194 195 static intptr_t 196 do_spawnT(int mode, const _TCHAR* cmdname, const _TCHAR* args, const _TCHAR* envp) 197 { 198 STARTUPINFO StartupInfo = {0}; 199 PROCESS_INFORMATION ProcessInformation; 200 // char* fmode; 201 // HANDLE* hFile; 202 // int i, last; 203 BOOL bResult; 204 DWORD dwExitCode; 205 DWORD dwError; 206 DWORD dwFlags = 0; 207 208 TRACE(MK_STR(do_spawnT)"(%i,'%"sT"','%"sT"','%"sT"')",mode,cmdname,args,envp); 209 210 211 if (mode != _P_NOWAIT && mode != _P_NOWAITO && mode != _P_WAIT && mode != _P_DETACH && mode != _P_OVERLAY) 212 { 213 _set_errno ( EINVAL ); 214 return( -1); 215 } 216 217 if (0 != _taccess(cmdname, F_OK)) 218 { 219 _set_errno ( ENOENT ); 220 return(-1); 221 } 222 if (0 == access_dirT(cmdname)) 223 { 224 _set_errno ( EISDIR ); 225 return(-1); 226 } 227 228 memset (&StartupInfo, 0, sizeof(StartupInfo)); 229 StartupInfo.cb = sizeof(StartupInfo); 230 231 #if 0 232 233 for (last = i = 0; i < FDINFO_FD_MAX; i++) 234 { 235 if ((void*)-1 != _get_osfhandle(i)) 236 { 237 last = i + 1; 238 } 239 } 240 241 if (last) 242 { 243 StartupInfo.cbReserved2 = sizeof(ULONG) + last * (sizeof(char) + sizeof(HANDLE)); 244 StartupInfo.lpReserved2 = malloc(StartupInfo.cbReserved2); 245 if (StartupInfo.lpReserved2 == NULL) 246 { 247 _set_errno ( ENOMEM ); 248 return -1; 249 } 250 251 *(DWORD*)StartupInfo.lpReserved2 = last; 252 fmode = (char*)(StartupInfo.lpReserved2 + sizeof(ULONG)); 253 hFile = (HANDLE*)(StartupInfo.lpReserved2 + sizeof(ULONG) + last * sizeof(char)); 254 for (i = 0; i < last; i++) 255 { 256 int _mode = __fileno_getmode(i); 257 HANDLE h = _get_osfhandle(i); 258 /* FIXME: The test of console handles (((ULONG)Handle) & 0x10000003) == 0x3) 259 * is possible wrong 260 */ 261 if ((((ULONG)h) & 0x10000003) == 0x3 || _mode & _O_NOINHERIT || (i < 3 && mode == _P_DETACH)) 262 { 263 *hFile = INVALID_HANDLE_VALUE; 264 *fmode = 0; 265 } 266 else 267 { 268 DWORD dwFlags; 269 BOOL bFlag; 270 bFlag = GetHandleInformation(h, &dwFlags); 271 if (bFlag && (dwFlags & HANDLE_FLAG_INHERIT)) 272 { 273 *hFile = h; 274 *fmode = (_O_ACCMODE & _mode) | (((_O_TEXT | _O_BINARY) & _mode) >> 8); 275 } 276 else 277 { 278 *hFile = INVALID_HANDLE_VALUE; 279 *fmode = 0; 280 } 281 } 282 fmode++; 283 hFile++; 284 } 285 } 286 #endif 287 288 create_io_inherit_block(&StartupInfo.cbReserved2, &StartupInfo.lpReserved2); 289 290 if (mode == _P_DETACH) 291 { 292 dwFlags |= DETACHED_PROCESS; 293 } 294 #ifdef _UNICODE 295 dwFlags |= CREATE_UNICODE_ENVIRONMENT; 296 #endif 297 298 bResult = CreateProcess((_TCHAR *)cmdname, 299 (_TCHAR *)args, 300 NULL, 301 NULL, 302 TRUE, 303 dwFlags, 304 (LPVOID)envp, 305 NULL, 306 &StartupInfo, 307 &ProcessInformation); 308 309 if (StartupInfo.lpReserved2) 310 { 311 free(StartupInfo.lpReserved2); 312 } 313 314 if (!bResult) 315 { 316 dwError = GetLastError(); 317 ERR("%x\n", dwError); 318 _dosmaperr(dwError); 319 return(-1); 320 } 321 CloseHandle(ProcessInformation.hThread); 322 switch(mode) 323 { 324 case _P_NOWAIT: 325 case _P_NOWAITO: 326 return((intptr_t)ProcessInformation.hProcess); 327 case _P_OVERLAY: 328 CloseHandle(ProcessInformation.hProcess); 329 _exit(0); 330 case _P_WAIT: 331 WaitForSingleObject(ProcessInformation.hProcess, INFINITE); 332 GetExitCodeProcess(ProcessInformation.hProcess, &dwExitCode); 333 CloseHandle(ProcessInformation.hProcess); 334 return( (int)dwExitCode); //CORRECT? 335 case _P_DETACH: 336 CloseHandle(ProcessInformation.hProcess); 337 return( 0); 338 } 339 return( (intptr_t)ProcessInformation.hProcess); 340 } 341 342 /* 343 * @implemented 344 */ 345 intptr_t _tspawnl(int mode, const _TCHAR *cmdname, const _TCHAR* arg0, ...) 346 { 347 va_list argp; 348 _TCHAR* args; 349 intptr_t ret = -1; 350 351 TRACE(MK_STR(_tspawnl)"('%"sT"')\n", cmdname); 352 353 va_start(argp, arg0); 354 args = valisttosT(arg0, argp, ' '); 355 356 if (args) 357 { 358 ret = do_spawnT(mode, cmdname, args, NULL); 359 free(args); 360 } 361 va_end(argp); 362 return ret; 363 } 364 365 /* 366 * @implemented 367 */ 368 intptr_t _tspawnv(int mode, const _TCHAR *cmdname, const _TCHAR* const* argv) 369 { 370 _TCHAR* args; 371 intptr_t ret = -1; 372 373 TRACE(MK_STR(_tspawnv)"('%"sT"')\n", cmdname); 374 375 args = argvtosT(argv, ' '); 376 377 if (args) 378 { 379 ret = do_spawnT(mode, cmdname, args, NULL); 380 free(args); 381 } 382 return ret; 383 } 384 385 /* 386 * @implemented 387 */ 388 intptr_t _tspawnle(int mode, const _TCHAR *cmdname, const _TCHAR* arg0, ... /*, NULL, const char* const* envp*/) 389 { 390 va_list argp; 391 _TCHAR* args; 392 _TCHAR* envs; 393 _TCHAR const * const* ptr; 394 intptr_t ret = -1; 395 396 TRACE(MK_STR(_tspawnle)"('%"sT"')\n", cmdname); 397 398 va_start(argp, arg0); 399 args = valisttosT(arg0, argp, ' '); 400 do 401 { 402 ptr = (_TCHAR const* const*)va_arg(argp, _TCHAR*); 403 } 404 while (ptr != NULL); 405 ptr = (_TCHAR const* const*)va_arg(argp, _TCHAR*); 406 envs = argvtosT(ptr, 0); 407 if (args) 408 { 409 ret = do_spawnT(mode, cmdname, args, envs); 410 free(args); 411 } 412 if (envs) 413 { 414 free(envs); 415 } 416 va_end(argp); 417 return ret; 418 419 } 420 421 /* 422 * @implemented 423 */ 424 intptr_t _tspawnve(int mode, const _TCHAR *cmdname, const _TCHAR* const* argv, const _TCHAR* const* envp) 425 { 426 _TCHAR *args; 427 _TCHAR *envs; 428 intptr_t ret = -1; 429 430 TRACE(MK_STR(_tspawnve)"('%"sT"')\n", cmdname); 431 432 args = argvtosT(argv, ' '); 433 envs = argvtosT(envp, 0); 434 435 if (args) 436 { 437 ret = do_spawnT(mode, cmdname, args, envs); 438 free(args); 439 } 440 if (envs) 441 { 442 free(envs); 443 } 444 return ret; 445 } 446 447 /* 448 * @implemented 449 */ 450 intptr_t _tspawnvp(int mode, const _TCHAR* cmdname, const _TCHAR* const* argv) 451 { 452 _TCHAR pathname[FILENAME_MAX]; 453 454 TRACE(MK_STR(_tspawnvp)"('%"sT"')\n", cmdname); 455 456 return _tspawnv(mode, find_execT(cmdname, pathname), argv); 457 } 458 459 /* 460 * @implemented 461 */ 462 intptr_t _tspawnlp(int mode, const _TCHAR* cmdname, const _TCHAR* arg0, .../*, NULL*/) 463 { 464 va_list argp; 465 _TCHAR* args; 466 intptr_t ret = -1; 467 _TCHAR pathname[FILENAME_MAX]; 468 469 TRACE(MK_STR(_tspawnlp)"('%"sT"')\n", cmdname); 470 471 va_start(argp, arg0); 472 args = valisttosT(arg0, argp, ' '); 473 if (args) 474 { 475 ret = do_spawnT(mode, find_execT(cmdname, pathname), args, NULL); 476 free(args); 477 } 478 va_end(argp); 479 return ret; 480 } 481 482 483 /* 484 * @implemented 485 */ 486 intptr_t _tspawnlpe(int mode, const _TCHAR* cmdname, const _TCHAR* arg0, .../*, NULL, const char* const* envp*/) 487 { 488 va_list argp; 489 _TCHAR* args; 490 _TCHAR* envs; 491 _TCHAR const* const * ptr; 492 intptr_t ret = -1; 493 _TCHAR pathname[FILENAME_MAX]; 494 495 TRACE(MK_STR(_tspawnlpe)"('%"sT"')\n", cmdname); 496 497 va_start(argp, arg0); 498 args = valisttosT(arg0, argp, ' '); 499 do 500 { 501 ptr = (_TCHAR const* const*)va_arg(argp, _TCHAR*); 502 } 503 while (ptr != NULL); 504 ptr = (_TCHAR const* const*)va_arg(argp, _TCHAR*); 505 envs = argvtosT(ptr, 0); 506 if (args) 507 { 508 ret = do_spawnT(mode, find_execT(cmdname, pathname), args, envs); 509 free(args); 510 } 511 if (envs) 512 { 513 free(envs); 514 } 515 va_end(argp); 516 return ret; 517 } 518 519 /* 520 * @implemented 521 */ 522 intptr_t _tspawnvpe(int mode, const _TCHAR* cmdname, const _TCHAR* const* argv, const _TCHAR* const* envp) 523 { 524 _TCHAR pathname[FILENAME_MAX]; 525 526 TRACE(MK_STR(_tspawnvpe)"('%"sT"')\n", cmdname); 527 528 return _tspawnve(mode, find_execT(cmdname, pathname), argv, envp); 529 } 530 531 /* 532 * @implemented 533 */ 534 intptr_t _texecl(const _TCHAR* cmdname, const _TCHAR* arg0, ...) 535 { 536 _TCHAR* args; 537 va_list argp; 538 intptr_t ret = -1; 539 540 TRACE(MK_STR(_texecl)"('%"sT"')\n", cmdname); 541 542 va_start(argp, arg0); 543 args = valisttosT(arg0, argp, ' '); 544 545 if (args) 546 { 547 ret = do_spawnT(_P_OVERLAY, cmdname, args, NULL); 548 free(args); 549 } 550 va_end(argp); 551 return ret; 552 } 553 554 /* 555 * @implemented 556 */ 557 intptr_t _texecv(const _TCHAR* cmdname, const _TCHAR* const* argv) 558 { 559 TRACE(MK_STR(_texecv)"('%"sT"')\n", cmdname); 560 return _tspawnv(_P_OVERLAY, cmdname, argv); 561 } 562 563 /* 564 * @implemented 565 */ 566 intptr_t _texecle(const _TCHAR* cmdname, const _TCHAR* arg0, ... /*, NULL, char* const* envp */) 567 { 568 va_list argp; 569 _TCHAR* args; 570 _TCHAR* envs; 571 _TCHAR const* const* ptr; 572 intptr_t ret = -1; 573 574 TRACE(MK_STR(_texecle)"('%"sT"')\n", cmdname); 575 576 va_start(argp, arg0); 577 args = valisttosT(arg0, argp, ' '); 578 do 579 { 580 ptr = (_TCHAR const* const*)va_arg(argp, _TCHAR*); 581 } 582 while (ptr != NULL); 583 ptr = (_TCHAR const* const*)va_arg(argp, _TCHAR*); 584 envs = argvtosT(ptr, 0); 585 if (args) 586 { 587 ret = do_spawnT(_P_OVERLAY, cmdname, args, envs); 588 free(args); 589 } 590 if (envs) 591 { 592 free(envs); 593 } 594 va_end(argp); 595 return ret; 596 } 597 598 /* 599 * @implemented 600 */ 601 intptr_t _texecve(const _TCHAR* cmdname, const _TCHAR* const* argv, const _TCHAR* const* envp) 602 { 603 TRACE(MK_STR(_texecve)"('%"sT"')\n", cmdname); 604 return _tspawnve(_P_OVERLAY, cmdname, argv, envp); 605 } 606 607 /* 608 * @implemented 609 */ 610 intptr_t _texeclp(const _TCHAR* cmdname, const _TCHAR* arg0, ...) 611 { 612 _TCHAR* args; 613 va_list argp; 614 intptr_t ret = -1; 615 _TCHAR pathname[FILENAME_MAX]; 616 617 TRACE(MK_STR(_texeclp)"('%"sT"')\n", cmdname); 618 619 va_start(argp, arg0); 620 args = valisttosT(arg0, argp, ' '); 621 622 if (args) 623 { 624 ret = do_spawnT(_P_OVERLAY, find_execT(cmdname, pathname), args, NULL); 625 free(args); 626 } 627 va_end(argp); 628 return ret; 629 } 630 631 /* 632 * @implemented 633 */ 634 intptr_t _texecvp(const _TCHAR* cmdname, const _TCHAR* const* argv) 635 { 636 TRACE(MK_STR(_texecvp)"('%"sT"')\n", cmdname); 637 return _tspawnvp(_P_OVERLAY, cmdname, argv); 638 } 639 640 /* 641 * @implemented 642 */ 643 intptr_t _texeclpe(const _TCHAR* cmdname, const _TCHAR* arg0, ... /*, NULL, char* const* envp */) 644 { 645 va_list argp; 646 _TCHAR* args; 647 _TCHAR* envs; 648 _TCHAR const* const* ptr; 649 intptr_t ret = -1; 650 _TCHAR pathname[FILENAME_MAX]; 651 652 TRACE(MK_STR(_texeclpe)"('%"sT"')\n", cmdname); 653 654 va_start(argp, arg0); 655 args = valisttosT(arg0, argp, ' '); 656 do 657 { 658 ptr = (_TCHAR const* const*)va_arg(argp, _TCHAR*); 659 } 660 while (ptr != NULL); 661 ptr = (_TCHAR const* const*)va_arg(argp, _TCHAR*); 662 envs = argvtosT(ptr, 0); 663 if (args) 664 { 665 ret = do_spawnT(_P_OVERLAY, find_execT(cmdname, pathname), args, envs); 666 free(args); 667 } 668 if (envs) 669 { 670 free(envs); 671 } 672 va_end(argp); 673 return ret; 674 } 675 676 /* 677 * @implemented 678 */ 679 intptr_t _texecvpe(const _TCHAR* cmdname, const _TCHAR* const* argv, const _TCHAR* const* envp) 680 { 681 TRACE(MK_STR(_texecvpe)"('%"sT"')\n", cmdname); 682 return _tspawnvpe(_P_OVERLAY, cmdname, argv, envp); 683 } 684 685 686