1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 25 /* 26 * ToDo: 27 * - cleanup of process status things 28 * - cleanup of process spawning 29 * - cleanup of resource transfer 30 */ 31 32 #if defined(SOLARIS) 33 // The procfs may only be used without LFS in 32bits. 34 # ifdef _FILE_OFFSET_BITS 35 # undef _FILE_OFFSET_BITS 36 # endif 37 #endif 38 39 40 #ifdef FREEBSD 41 #include <machine/param.h> 42 #endif 43 44 #include "system.h" 45 #if defined(SOLARIS) 46 # include <sys/procfs.h> 47 #endif 48 #include <osl/diagnose.h> 49 #include <osl/mutex.h> 50 51 #ifndef _OSL_CONDITN_H_ 52 #include <osl/conditn.h> 53 #endif 54 #include <osl/thread.h> 55 #include <osl/file.h> 56 #include <osl/signal.h> 57 #include <rtl/alloc.h> 58 59 #include <grp.h> 60 61 #include "procimpl.h" 62 #include "sockimpl.h" 63 #include "secimpl.h" 64 65 66 #define MAX_ARGS 255 67 #define MAX_ENVS 255 68 69 #if defined(MACOSX) || defined(IORESOURCE_TRANSFER_BSD) 70 #define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(int)) 71 #endif 72 73 /* implemented in file.c */ 74 extern oslFileError FileURLToPath( char *, size_t, rtl_uString* ); 75 extern oslFileHandle osl_createFileHandleFromFD( int fd ); 76 77 /****************************************************************************** 78 * 79 * Data Type Definition 80 * 81 ******************************************************************************/ 82 83 typedef struct { 84 int m_hPipe; 85 int m_hConn; 86 sal_Char m_Name[PATH_MAX + 1]; 87 } Pipe; 88 89 typedef struct { 90 const sal_Char* m_pszArgs[MAX_ARGS + 1]; 91 oslProcessOption m_options; 92 const sal_Char* m_pszDir; 93 sal_Char* m_pszEnv[MAX_ENVS + 1]; 94 uid_t m_uid; 95 gid_t m_gid; 96 sal_Char* m_name; 97 oslCondition m_started; 98 oslProcessImpl* m_pProcImpl; 99 oslFileHandle *m_pInputWrite; 100 oslFileHandle *m_pOutputRead; 101 oslFileHandle *m_pErrorRead; 102 } ProcessData; 103 104 typedef struct _oslPipeImpl { 105 int m_Socket; 106 sal_Char m_Name[PATH_MAX + 1]; 107 } oslPipeImpl; 108 109 110 /****************************************************************************** 111 * 112 * Function Declarations 113 * 114 *****************************************************************************/ 115 116 oslProcessError SAL_CALL osl_psz_executeProcess(sal_Char *pszImageName, 117 sal_Char *pszArguments[], 118 oslProcessOption Options, 119 oslSecurity Security, 120 sal_Char *pszDirectory, 121 sal_Char *pszEnvironments[], 122 oslProcess *pProcess, 123 oslFileHandle *pInputWrite, 124 oslFileHandle *pOutputRead, 125 oslFileHandle *pErrorRead ); 126 127 128 oslProcessError SAL_CALL osl_searchPath_impl( 129 const sal_Char* pszName, 130 const sal_Char* pszPath, 131 sal_Char Separator, 132 sal_Char *pszBuffer, 133 sal_uInt32 Max); 134 135 136 sal_Bool osl_getFullPath(const sal_Char* pszFilename, sal_Char* pszPath, sal_uInt32 MaxLen); 137 138 static oslProcessImpl* ChildList; 139 static oslMutex ChildListMutex; 140 141 /****************************************************************************** 142 Deprecated 143 Old and buggy implementation of osl_searchPath used only by 144 osl_psz_executeProcess. 145 A new implemenation is in file_path_helper.cxx 146 *****************************************************************************/ 147 148 oslProcessError SAL_CALL osl_searchPath_impl(const sal_Char* pszName, const sal_Char* pszPath, 149 sal_Char Separator, sal_Char *pszBuffer, sal_uInt32 Max) 150 { 151 sal_Char path[PATH_MAX + 1]; 152 sal_Char *pchr; 153 154 path[0] = '\0'; 155 156 OSL_ASSERT(pszName != NULL); 157 158 if ( pszName == 0 ) 159 { 160 return osl_Process_E_NotFound; 161 } 162 163 if (pszPath == NULL) 164 pszPath = "PATH"; 165 166 if (Separator == '\0') 167 Separator = ':'; 168 169 170 if ( (pchr = getenv(pszPath)) != 0 ) 171 { 172 sal_Char *pstr; 173 174 while (*pchr != '\0') 175 { 176 pstr = path; 177 178 while ((*pchr != '\0') && (*pchr != Separator)) 179 *pstr++ = *pchr++; 180 181 if ((pstr > path) && ((*(pstr - 1) != '/'))) 182 *pstr++ = '/'; 183 184 *pstr = '\0'; 185 186 strcat(path, pszName); 187 188 if (access(path, 0) == 0) 189 { 190 char szRealPathBuf[PATH_MAX] = ""; 191 192 if( NULL == realpath(path, szRealPathBuf) || (strlen(szRealPathBuf) >= (sal_uInt32)Max)) 193 return osl_Process_E_Unknown; 194 195 strcpy(pszBuffer, path); 196 197 return osl_Process_E_None; 198 } 199 200 if (*pchr == Separator) 201 pchr++; 202 } 203 } 204 205 return osl_Process_E_NotFound; 206 } 207 208 /****************************************************************************** 209 * 210 * New io resource transfer functions 211 * 212 *****************************************************************************/ 213 214 215 /********************************************** 216 sendFdPipe 217 *********************************************/ 218 219 static sal_Bool sendFdPipe(int PipeFD, int SocketFD) 220 { 221 sal_Bool bRet = sal_False; 222 223 struct iovec iov[1]; 224 struct msghdr msg; 225 char buf[2]; /* send_fd()/recv_fd() 2-byte protocol */ 226 int nSend; 227 int RetCode=0; 228 229 #if defined(IOCHANNEL_TRANSFER_BSD) 230 231 OSL_TRACE("IOCHANNEL_TRANSFER_BSD send"); 232 /* OSL_TRACE("sending fd %i\n",SocketFD); */ 233 234 iov[0].iov_base = buf; 235 iov[0].iov_len = sizeof(buf); 236 msg.msg_iov = iov; 237 msg.msg_iovlen = 1; 238 msg.msg_name = NULL; 239 msg.msg_namelen = 0; 240 241 msg.msg_accrights = (caddr_t) &SocketFD; /* addr of descriptor */ 242 msg.msg_accrightslen = sizeof(int); /* pass 1 descriptor */ 243 buf[1] = 0; /* zero status means OK */ 244 buf[0] = 0; /* null byte flag to recv_fd() */ 245 246 #else 247 248 struct cmsghdr* cmptr = (struct cmsghdr*)malloc(CONTROLLEN); 249 250 OSL_TRACE("!!!!!! IOCHANNEL_TRANSFER_BSD_RENO send"); 251 /* OSL_TRACE("sending fd %i\n",SocketFD); */ 252 253 iov[0].iov_base = buf; 254 iov[0].iov_len = sizeof(buf); 255 msg.msg_iov = iov; 256 msg.msg_iovlen = 1; 257 msg.msg_name = NULL; 258 msg.msg_namelen = 0; 259 msg.msg_control = (caddr_t) cmptr; 260 msg.msg_controllen = CONTROLLEN; 261 262 cmptr->cmsg_level = SOL_SOCKET; 263 cmptr->cmsg_type = SCM_RIGHTS; 264 cmptr->cmsg_len = CONTROLLEN; 265 memcpy(CMSG_DATA(cmptr), &SocketFD, sizeof(int)); 266 267 #endif 268 269 if ( ( nSend = sendmsg(PipeFD, &msg, 0) ) > 0 ) 270 { 271 bRet = sal_True; 272 OSL_TRACE("sendFdPipe : send '%i' bytes\n",nSend); 273 274 } 275 else 276 { 277 OSL_TRACE("sendFdPipe : sending failed (%s)",strerror(errno)); 278 } 279 280 nSend=read(PipeFD,&RetCode,sizeof(RetCode)); 281 282 if ( nSend > 0 && RetCode == 1 ) 283 { 284 OSL_TRACE("sendFdPipe : resource was received\n"); 285 } 286 else 287 { 288 OSL_TRACE("sendFdPipe : resource wasn't received\n"); 289 } 290 291 #if defined(IOCHANNEL_TRANSFER_BSD_RENO) 292 free(cmptr); 293 #endif 294 295 return bRet; 296 } 297 298 /********************************************** 299 receiveFdPipe 300 *********************************************/ 301 302 static oslSocket receiveFdPipe(int PipeFD) 303 { 304 oslSocket pSocket = 0; 305 struct msghdr msghdr; 306 struct iovec iov[1]; 307 char buffer[2]; 308 sal_Int32 nRead; 309 int newfd=-1; 310 int nRetCode=0; 311 /* char *ptr; */ 312 313 #if defined(IOCHANNEL_TRANSFER_BSD) 314 315 OSL_TRACE("IOCHANNEL_TRANSFER_BSD receive\n"); 316 317 iov[0].iov_base = buffer; 318 iov[0].iov_len = sizeof(buffer); 319 msghdr.msg_name = NULL; 320 msghdr.msg_namelen = 0; 321 msghdr.msg_iov = iov; 322 msghdr.msg_iovlen = 1; 323 msghdr.msg_accrights = (caddr_t) &newfd; /* addr of descriptor */ 324 msghdr.msg_accrightslen = sizeof(int); /* receive 1 descriptor */ 325 326 #else 327 struct cmsghdr* cmptr = (struct cmsghdr*)malloc(CONTROLLEN); 328 329 OSL_TRACE(" !!!! IOCHANNEL_TRANSFER_BSD_RENO receive"); 330 331 iov[0].iov_base = buffer; 332 iov[0].iov_len = sizeof(buffer); 333 msghdr.msg_name = NULL; 334 msghdr.msg_namelen = 0; 335 msghdr.msg_iov = iov; 336 msghdr.msg_iovlen = 1; 337 338 msghdr.msg_control = (caddr_t) cmptr; 339 msghdr.msg_controllen = CONTROLLEN; 340 341 #endif 342 343 344 #if defined(IOCHANNEL_TRANSFER_BSD) 345 346 if ( ( nRead = recvmsg(PipeFD, &msghdr, 0) ) > 0 ) 347 { 348 OSL_TRACE("receiveFdPipe : received '%i' bytes\n",nRead); 349 } 350 #else 351 352 if ( ( ( nRead = recvmsg(PipeFD, &msghdr, 0) ) > 0 ) && 353 ( msghdr.msg_controllen == CONTROLLEN ) ) 354 { 355 OSL_TRACE("receiveFdPipe : received '%i' bytes\n",nRead); 356 memcpy(&newfd, CMSG_DATA(cmptr), sizeof(int)); 357 } 358 #endif 359 else 360 { 361 OSL_TRACE("receiveFdPipe : receiving failed (%s)",strerror(errno)); 362 } 363 364 if ( newfd >= 0 ) 365 { 366 pSocket = __osl_createSocketImpl(newfd); 367 nRetCode=1; 368 OSL_TRACE("received fd %i\n",newfd); 369 } 370 371 OSL_TRACE("receiveFdPipe : writing back %i",nRetCode); 372 nRead=write(PipeFD,&nRetCode,sizeof(nRetCode)); 373 374 #if defined(IOCHANNEL_TRANSFER_BSD_RENO) 375 free(cmptr); 376 #endif 377 378 return pSocket; 379 } 380 381 /********************************************** 382 osl_sendResourcePipe 383 *********************************************/ 384 385 sal_Bool osl_sendResourcePipe(oslPipe pPipe, oslSocket pSocket) 386 { 387 sal_Bool bRet = sal_False; 388 389 if ( pSocket == 0 || pPipe == 0 ) 390 { 391 return sal_False; 392 } 393 394 bRet = sendFdPipe(pPipe->m_Socket,pSocket->m_Socket); 395 396 return bRet; 397 } 398 399 /********************************************** 400 osl_receiveResourcePipe 401 *********************************************/ 402 403 oslSocket osl_receiveResourcePipe(oslPipe pPipe) 404 { 405 oslSocket pSocket=0; 406 407 if ( pPipe == 0 ) 408 { 409 return 0; 410 } 411 412 pSocket = receiveFdPipe(pPipe->m_Socket); 413 414 return (oslSocket) pSocket; 415 } 416 417 418 419 /****************************************************************************** 420 * 421 * Functions for starting a process 422 * 423 *****************************************************************************/ 424 425 static void ChildStatusProc(void *pData) 426 { 427 pid_t pid = -1; 428 int status = 0; 429 int channel[2]; 430 ProcessData data; 431 ProcessData *pdata; 432 int stdOutput[2] = { -1, -1 }, stdInput[2] = { -1, -1 }, stdError[2] = { -1, -1 }; 433 434 pdata = (ProcessData *)pData; 435 436 /* make a copy of our data, because forking will only copy 437 our local stack of the thread, so the process data will not be accessible 438 in our child process */ 439 memcpy(&data, pData, sizeof(data)); 440 441 if (socketpair(AF_UNIX, SOCK_STREAM, 0, channel) == -1) 442 status = errno; 443 444 fcntl(channel[0], F_SETFD, FD_CLOEXEC); 445 fcntl(channel[1], F_SETFD, FD_CLOEXEC); 446 447 /* Create redirected IO pipes */ 448 if ( status == 0 && data.m_pInputWrite ) 449 if (pipe( stdInput ) == -1) 450 status = errno; 451 452 if ( status == 0 && data.m_pOutputRead ) 453 if (pipe( stdOutput ) == -1) 454 status = errno; 455 456 if ( status == 0 && data.m_pErrorRead ) 457 if (pipe( stdError ) == -1) 458 status = errno; 459 460 if ( (status == 0) && ((pid = fork()) == 0) ) 461 { 462 /* Child */ 463 int chstatus = 0; 464 sal_Int32 nWrote; 465 466 if (channel[0] != -1) close(channel[0]); 467 468 if ((data.m_uid != (uid_t)-1) && ((data.m_uid != getuid()) || (data.m_gid != getgid()))) 469 { 470 OSL_ASSERT(geteuid() == 0); /* must be root */ 471 472 if (! INIT_GROUPS(data.m_name, data.m_gid) || (setuid(data.m_uid) != 0)) 473 OSL_TRACE("Failed to change uid and guid, errno=%d (%s)\n", errno, strerror(errno)); 474 #if defined(LINUX) || defined (FREEBSD) 475 unsetenv("HOME"); 476 #else 477 putenv("HOME="); 478 #endif 479 } 480 481 if (data.m_pszDir) 482 chstatus = chdir(data.m_pszDir); 483 484 if (chstatus == 0 && ((data.m_uid == (uid_t)-1) || ((data.m_uid == getuid()) && (data.m_gid == getgid())))) 485 { 486 int i; 487 for (i = 0; data.m_pszEnv[i] != NULL; i++) 488 { 489 if (strchr(data.m_pszEnv[i], '=') == NULL) 490 { 491 unsetenv(data.m_pszEnv[i]); /*TODO: check error return*/ 492 } 493 else 494 { 495 putenv(data.m_pszEnv[i]); /*TODO: check error return*/ 496 } 497 } 498 499 OSL_TRACE("ChildStatusProc : starting '%s'",data.m_pszArgs[0]); 500 501 /* Connect std IO to pipe ends */ 502 503 /* Write end of stdInput not used in child process */ 504 if (stdInput[1] != -1) close( stdInput[1] ); 505 506 /* Read end of stdOutput not used in child process */ 507 if (stdOutput[0] != -1) close( stdOutput[0] ); 508 509 /* Read end of stdError not used in child process */ 510 if (stdError[0] != -1) close( stdError[0] ); 511 512 /* Redirect pipe ends to std IO */ 513 514 if ( stdInput[0] != STDIN_FILENO ) 515 { 516 dup2( stdInput[0], STDIN_FILENO ); 517 if (stdInput[0] != -1) close( stdInput[0] ); 518 } 519 520 if ( stdOutput[1] != STDOUT_FILENO ) 521 { 522 dup2( stdOutput[1], STDOUT_FILENO ); 523 if (stdOutput[1] != -1) close( stdOutput[1] ); 524 } 525 526 if ( stdError[1] != STDERR_FILENO ) 527 { 528 dup2( stdError[1], STDERR_FILENO ); 529 if (stdError[1] != -1) close( stdError[1] ); 530 } 531 532 pid=execv(data.m_pszArgs[0], (sal_Char **)data.m_pszArgs); 533 534 } 535 536 OSL_TRACE("Failed to exec, errno=%d (%s)\n", errno, strerror(errno)); 537 538 OSL_TRACE("ChildStatusProc : starting '%s' failed",data.m_pszArgs[0]); 539 540 /* if we reach here, something went wrong */ 541 nWrote = write(channel[1], &errno, sizeof(errno)); 542 if (nWrote != sizeof(errno)) 543 OSL_TRACE("sendFdPipe : sending failed (%s)",strerror(errno)); 544 545 if (channel[1] != -1) close(channel[1]); 546 547 _exit(255); 548 } 549 else 550 { /* Parent */ 551 int i = -1; 552 if (channel[1] != -1) close(channel[1]); 553 554 /* Close unused pipe ends */ 555 if (stdInput[0] != -1) close( stdInput[0] ); 556 if (stdOutput[1] != -1) close( stdOutput[1] ); 557 if (stdError[1] != -1) close( stdError[1] ); 558 559 if (pid > 0) 560 { 561 while (((i = read(channel[0], &status, sizeof(status))) < 0)) 562 { 563 if (errno != EINTR) 564 break; 565 } 566 } 567 568 if (channel[0] != -1) close(channel[0]); 569 570 if ((pid > 0) && (i == 0)) 571 { 572 pid_t child_pid; 573 osl_acquireMutex(ChildListMutex); 574 575 pdata->m_pProcImpl->m_pid = pid; 576 pdata->m_pProcImpl->m_pnext = ChildList; 577 ChildList = pdata->m_pProcImpl; 578 579 /* Store used pipe ends in data structure */ 580 581 if ( pdata->m_pInputWrite ) 582 *(pdata->m_pInputWrite) = osl_createFileHandleFromFD( stdInput[1] ); 583 584 if ( pdata->m_pOutputRead ) 585 *(pdata->m_pOutputRead) = osl_createFileHandleFromFD( stdOutput[0] ); 586 587 if ( pdata->m_pErrorRead ) 588 *(pdata->m_pErrorRead) = osl_createFileHandleFromFD( stdError[0] ); 589 590 osl_releaseMutex(ChildListMutex); 591 592 osl_setCondition(pdata->m_started); 593 594 do 595 { 596 child_pid = waitpid(pid, &status, 0); 597 } while ( 0 > child_pid && EINTR == errno ); 598 599 if ( child_pid < 0) 600 { 601 OSL_TRACE("Failed to wait for child process, errno=%d (%s)\n", errno, strerror(errno)); 602 603 /* 604 We got an other error than EINTR. Anyway we have to wake up the 605 waiting thread under any circumstances */ 606 607 child_pid = pid; 608 } 609 610 611 if ( child_pid > 0 ) 612 { 613 oslProcessImpl* pChild; 614 615 osl_acquireMutex(ChildListMutex); 616 617 pChild = ChildList; 618 619 /* check if it is one of our child processes */ 620 while (pChild != NULL) 621 { 622 if (pChild->m_pid == child_pid) 623 { 624 if (WIFEXITED(status)) 625 pChild->m_status = WEXITSTATUS(status); 626 else 627 pChild->m_status = -1; 628 629 osl_setCondition(pChild->m_terminated); 630 } 631 632 pChild = pChild->m_pnext; 633 } 634 635 osl_releaseMutex(ChildListMutex); 636 } 637 } 638 else 639 { 640 OSL_TRACE("ChildStatusProc : starting '%s' failed",data.m_pszArgs[0]); 641 OSL_TRACE("Failed to launch child process, child reports errno=%d (%s)\n", status, strerror(status)); 642 643 /* Close pipe ends */ 644 if ( pdata->m_pInputWrite ) 645 *pdata->m_pInputWrite = NULL; 646 647 if ( pdata->m_pOutputRead ) 648 *pdata->m_pOutputRead = NULL; 649 650 if ( pdata->m_pErrorRead ) 651 *pdata->m_pErrorRead = NULL; 652 653 if (stdInput[1] != -1) close( stdInput[1] ); 654 if (stdOutput[0] != -1) close( stdOutput[0] ); 655 if (stdError[0] != -1) close( stdError[0] ); 656 657 //if pid > 0 then a process was created, even if it later failed 658 //e.g. bash searching for a command to execute, and we still 659 //need to clean it up to avoid "defunct" processes 660 if (pid > 0) 661 { 662 pid_t child_pid; 663 do 664 { 665 child_pid = waitpid(pid, &status, 0); 666 } while ( 0 > child_pid && EINTR == errno ); 667 } 668 669 /* notify (and unblock) parent thread */ 670 osl_setCondition(pdata->m_started); 671 } 672 } 673 } 674 675 /********************************************** 676 osl_executeProcess_WithRedirectedIO 677 *********************************************/ 678 679 oslProcessError SAL_CALL osl_executeProcess_WithRedirectedIO( 680 rtl_uString *ustrImageName, 681 rtl_uString *ustrArguments[], 682 sal_uInt32 nArguments, 683 oslProcessOption Options, 684 oslSecurity Security, 685 rtl_uString *ustrWorkDir, 686 rtl_uString *ustrEnvironment[], 687 sal_uInt32 nEnvironmentVars, 688 oslProcess *pProcess, 689 oslFileHandle *pInputWrite, 690 oslFileHandle *pOutputRead, 691 oslFileHandle *pErrorRead 692 ) 693 { 694 695 oslProcessError Error; 696 sal_Char* pszWorkDir=0; 697 sal_Char** pArguments=0; 698 sal_Char** pEnvironment=0; 699 unsigned int idx; 700 701 char szImagePath[PATH_MAX] = ""; 702 char szWorkDir[PATH_MAX] = ""; 703 704 if ( ustrImageName && ustrImageName->length ) 705 { 706 FileURLToPath( szImagePath, PATH_MAX, ustrImageName ); 707 } 708 709 if ( ustrWorkDir != 0 && ustrWorkDir->length ) 710 { 711 FileURLToPath( szWorkDir, PATH_MAX, ustrWorkDir ); 712 pszWorkDir = szWorkDir; 713 } 714 715 if ( pArguments == 0 && nArguments > 0 ) 716 { 717 pArguments = (sal_Char**) malloc( ( nArguments + 2 ) * sizeof(sal_Char*) ); 718 } 719 720 721 for ( idx = 0 ; idx < nArguments ; ++idx ) 722 { 723 rtl_String* strArg =0; 724 725 726 rtl_uString2String( &strArg, 727 rtl_uString_getStr(ustrArguments[idx]), 728 rtl_uString_getLength(ustrArguments[idx]), 729 osl_getThreadTextEncoding(), 730 OUSTRING_TO_OSTRING_CVTFLAGS ); 731 732 pArguments[idx]=strdup(rtl_string_getStr(strArg)); 733 rtl_string_release(strArg); 734 pArguments[idx+1]=0; 735 } 736 737 for ( idx = 0 ; idx < nEnvironmentVars ; ++idx ) 738 { 739 rtl_String* strEnv=0; 740 741 if ( pEnvironment == 0 ) 742 { 743 pEnvironment = (sal_Char**) malloc( ( nEnvironmentVars + 2 ) * sizeof(sal_Char*) ); 744 } 745 746 rtl_uString2String( &strEnv, 747 rtl_uString_getStr(ustrEnvironment[idx]), 748 rtl_uString_getLength(ustrEnvironment[idx]), 749 osl_getThreadTextEncoding(), 750 OUSTRING_TO_OSTRING_CVTFLAGS ); 751 752 pEnvironment[idx]=strdup(rtl_string_getStr(strEnv)); 753 rtl_string_release(strEnv); 754 pEnvironment[idx+1]=0; 755 } 756 757 758 Error = osl_psz_executeProcess(szImagePath, 759 pArguments, 760 Options, 761 Security, 762 pszWorkDir, 763 pEnvironment, 764 pProcess, 765 pInputWrite, 766 pOutputRead, 767 pErrorRead 768 ); 769 770 if ( pArguments != 0 ) 771 { 772 for ( idx = 0 ; idx < nArguments ; ++idx ) 773 { 774 if ( pArguments[idx] != 0 ) 775 { 776 free(pArguments[idx]); 777 } 778 } 779 free(pArguments); 780 } 781 782 if ( pEnvironment != 0 ) 783 { 784 for ( idx = 0 ; idx < nEnvironmentVars ; ++idx ) 785 { 786 if ( pEnvironment[idx] != 0 ) 787 { 788 free(pEnvironment[idx]); 789 } 790 } 791 free(pEnvironment); 792 } 793 794 return Error; 795 } 796 797 /********************************************** 798 osl_executeProcess 799 *********************************************/ 800 801 oslProcessError SAL_CALL osl_executeProcess( 802 rtl_uString *ustrImageName, 803 rtl_uString *ustrArguments[], 804 sal_uInt32 nArguments, 805 oslProcessOption Options, 806 oslSecurity Security, 807 rtl_uString *ustrWorkDir, 808 rtl_uString *ustrEnvironment[], 809 sal_uInt32 nEnvironmentVars, 810 oslProcess *pProcess 811 ) 812 { 813 return osl_executeProcess_WithRedirectedIO( 814 ustrImageName, 815 ustrArguments, 816 nArguments, 817 Options, 818 Security, 819 ustrWorkDir, 820 ustrEnvironment, 821 nEnvironmentVars, 822 pProcess, 823 NULL, 824 NULL, 825 NULL 826 ); 827 } 828 829 /********************************************** 830 osl_psz_executeProcess 831 *********************************************/ 832 833 oslProcessError SAL_CALL osl_psz_executeProcess(sal_Char *pszImageName, 834 sal_Char *pszArguments[], 835 oslProcessOption Options, 836 oslSecurity Security, 837 sal_Char *pszDirectory, 838 sal_Char *pszEnvironments[], 839 oslProcess *pProcess, 840 oslFileHandle *pInputWrite, 841 oslFileHandle *pOutputRead, 842 oslFileHandle *pErrorRead 843 ) 844 { 845 int i; 846 sal_Char path[PATH_MAX + 1]; 847 ProcessData Data; 848 oslThread hThread; 849 850 path[0] = '\0'; 851 852 memset(&Data,0,sizeof(ProcessData)); 853 Data.m_pInputWrite = pInputWrite; 854 Data.m_pOutputRead = pOutputRead; 855 Data.m_pErrorRead = pErrorRead; 856 857 if (pszImageName == NULL) 858 pszImageName = pszArguments[0]; 859 860 OSL_ASSERT(pszImageName != NULL); 861 862 if ( pszImageName == 0 ) 863 { 864 return osl_Process_E_NotFound; 865 } 866 867 if ((Options & osl_Process_SEARCHPATH) && 868 (osl_searchPath_impl(pszImageName, NULL, '\0', path, sizeof(path)) == osl_Process_E_None)) 869 pszImageName = path; 870 871 Data.m_pszArgs[0] = strdup(pszImageName); 872 Data.m_pszArgs[1] = 0; 873 874 if ( pszArguments != 0 ) 875 { 876 for (i = 0; ((i + 2) < MAX_ARGS) && (pszArguments[i] != NULL); i++) 877 Data.m_pszArgs[i+1] = strdup(pszArguments[i]); 878 Data.m_pszArgs[i+2] = NULL; 879 } 880 881 Data.m_options = Options; 882 Data.m_pszDir = (pszDirectory != NULL) ? strdup(pszDirectory) : NULL; 883 884 if (pszEnvironments != NULL) 885 { 886 for (i = 0; ((i + 1) < MAX_ENVS) && (pszEnvironments[i] != NULL); i++) 887 Data.m_pszEnv[i] = strdup(pszEnvironments[i]); 888 Data.m_pszEnv[i+1] = NULL; 889 } 890 else 891 Data.m_pszEnv[0] = NULL; 892 893 if (Security != NULL) 894 { 895 Data.m_uid = ((oslSecurityImpl*)Security)->m_pPasswd.pw_uid; 896 Data.m_gid = ((oslSecurityImpl*)Security)->m_pPasswd.pw_gid; 897 Data.m_name = ((oslSecurityImpl*)Security)->m_pPasswd.pw_name; 898 } 899 else 900 Data.m_uid = (uid_t)-1; 901 902 Data.m_pProcImpl = (oslProcessImpl*) malloc(sizeof(oslProcessImpl)); 903 Data.m_pProcImpl->m_pid = 0; 904 Data.m_pProcImpl->m_terminated = osl_createCondition(); 905 Data.m_pProcImpl->m_pnext = NULL; 906 907 if (ChildListMutex == NULL) 908 ChildListMutex = osl_createMutex(); 909 910 Data.m_started = osl_createCondition(); 911 912 hThread = osl_createThread(ChildStatusProc, &Data); 913 914 osl_waitCondition(Data.m_started, NULL); 915 osl_destroyCondition(Data.m_started); 916 917 for (i = 0; Data.m_pszArgs[i] != NULL; i++) 918 free((void *)Data.m_pszArgs[i]); 919 920 for (i = 0; Data.m_pszEnv[i] != NULL; i++) 921 free((void *)Data.m_pszEnv[i]); 922 923 if ( Data.m_pszDir != 0 ) 924 { 925 free((void *)Data.m_pszDir); 926 } 927 928 osl_destroyThread(hThread); 929 930 if (Data.m_pProcImpl->m_pid != 0) 931 { 932 *pProcess = Data.m_pProcImpl; 933 934 if (Options & osl_Process_WAIT) 935 osl_joinProcess(*pProcess); 936 937 return osl_Process_E_None; 938 } 939 940 osl_destroyCondition(Data.m_pProcImpl->m_terminated); 941 free(Data.m_pProcImpl); 942 943 return osl_Process_E_Unknown; 944 } 945 946 947 /****************************************************************************** 948 * 949 * Functions for processes 950 * 951 *****************************************************************************/ 952 953 954 /********************************************** 955 osl_terminateProcess 956 *********************************************/ 957 958 oslProcessError SAL_CALL osl_terminateProcess(oslProcess Process) 959 { 960 if (Process == NULL) 961 return osl_Process_E_Unknown; 962 963 if (kill(((oslProcessImpl*)Process)->m_pid, SIGKILL) != 0) 964 { 965 switch (errno) 966 { 967 case EPERM: 968 return osl_Process_E_NoPermission; 969 970 case ESRCH: 971 return osl_Process_E_NotFound; 972 973 default: 974 return osl_Process_E_Unknown; 975 } 976 } 977 978 return osl_Process_E_None; 979 } 980 981 /********************************************** 982 osl_getProcess 983 *********************************************/ 984 985 oslProcess SAL_CALL osl_getProcess(oslProcessIdentifier Ident) 986 { 987 oslProcessImpl *pProcImpl; 988 989 if (kill(Ident, 0) != -1) 990 { 991 oslProcessImpl* pChild; 992 993 if (ChildListMutex == NULL) 994 ChildListMutex = osl_createMutex(); 995 996 osl_acquireMutex(ChildListMutex); 997 998 pChild = ChildList; 999 1000 /* check if it is one of our child processes */ 1001 while (pChild != NULL) 1002 { 1003 if (Ident == (sal_uInt32) pChild->m_pid) 1004 break; 1005 1006 pChild = pChild->m_pnext; 1007 } 1008 1009 pProcImpl = (oslProcessImpl*) malloc(sizeof(oslProcessImpl)); 1010 pProcImpl->m_pid = Ident; 1011 pProcImpl->m_terminated = osl_createCondition(); 1012 1013 if (pChild != NULL) 1014 { 1015 /* process is a child so insert into list */ 1016 pProcImpl->m_pnext = pChild->m_pnext; 1017 pChild->m_pnext = pProcImpl; 1018 1019 pProcImpl->m_status = pChild->m_status; 1020 1021 if (osl_checkCondition(pChild->m_terminated)) 1022 osl_setCondition(pProcImpl->m_terminated); 1023 } 1024 else 1025 pProcImpl->m_pnext = NULL; 1026 1027 osl_releaseMutex(ChildListMutex); 1028 } 1029 else 1030 pProcImpl = NULL; 1031 1032 return (pProcImpl); 1033 } 1034 1035 /********************************************** 1036 osl_freeProcessHandle 1037 *********************************************/ 1038 1039 void SAL_CALL osl_freeProcessHandle(oslProcess Process) 1040 { 1041 if (Process != NULL) 1042 { 1043 oslProcessImpl *pChild, *pPrev = NULL; 1044 1045 OSL_ASSERT(ChildListMutex != NULL); 1046 1047 if ( ChildListMutex == 0 ) 1048 { 1049 return; 1050 } 1051 1052 osl_acquireMutex(ChildListMutex); 1053 1054 pChild = ChildList; 1055 1056 /* remove process from child list */ 1057 while (pChild != NULL) 1058 { 1059 if (pChild == (oslProcessImpl*)Process) 1060 { 1061 if (pPrev != NULL) 1062 pPrev->m_pnext = pChild->m_pnext; 1063 else 1064 ChildList = pChild->m_pnext; 1065 1066 break; 1067 } 1068 1069 pPrev = pChild; 1070 pChild = pChild->m_pnext; 1071 } 1072 1073 osl_releaseMutex(ChildListMutex); 1074 1075 osl_destroyCondition(((oslProcessImpl*)Process)->m_terminated); 1076 1077 free(Process); 1078 } 1079 } 1080 1081 #if defined(LINUX) 1082 struct osl_procStat 1083 { 1084 /* from 'stat' */ 1085 pid_t pid; /* pid */ 1086 char command[16]; /* 'argv[0]' */ /* mfe: it all right char comm[16] in kernel! */ 1087 char state; /* state (running, stopped, ...) */ 1088 pid_t ppid; /* parent pid */ 1089 pid_t pgrp; /* parent group */ 1090 int session; /* session ID */ 1091 int tty; /* no of tty */ 1092 pid_t tpgid; /* group of process owning the tty */ 1093 unsigned long flags; /* flags dunno */ 1094 unsigned long minflt; /* minor page faults */ 1095 unsigned long cminflt; /* minor page faults with children */ 1096 unsigned long majflt; /* major page faults */ 1097 unsigned long cmajflt; /* major page faults with children */ 1098 unsigned long utime; /* no of jiffies in user mode */ 1099 unsigned long stime; /* no of jiffies in kernel mode */ 1100 unsigned long cutime; /* no of jiffies in user mode with children */ 1101 unsigned long cstime; /* no of jiffies in kernel mode with children */ 1102 unsigned long priority; /* nice value + 15 (kernel scheduling prio)*/ 1103 long nice; /* nice value */ 1104 long timeout; /* no of jiffies of next process timeout */ 1105 long itrealvalue; /* no jiffies before next SIGALRM */ 1106 unsigned long starttime; /* process started this no of jiffies after boot */ 1107 unsigned long vsize; /* virtual memory size (in bytes) */ 1108 long rss; /* resident set size (in pages) */ 1109 unsigned long rss_rlim; /* rss limit (in bytes) */ 1110 unsigned long startcode; /* address above program text can run */ 1111 unsigned long endcode; /* address below program text can run */ 1112 unsigned long startstack; /* address of start of stack */ 1113 unsigned long kstkesp; /* current value of 'esp' (stack pointer) */ 1114 unsigned long kstkeip; /* current value of 'eip' (instruction pointer) */ 1115 /* mfe: Linux > 2.1.7x have more signals (88) */ 1116 /*#ifdef LINUX */ 1117 char signal[24]; /* pending signals */ 1118 char blocked[24]; /* blocked signals */ 1119 char sigignore[24]; /* ignored signals */ 1120 char sigcatch[24]; /* catched signals */ 1121 /*#else*/ 1122 /* long long signal;*/ 1123 /* long long blocked;*/ 1124 /* long long sigignore;*/ 1125 /* long long sigcatch;*/ 1126 /*#endif */ 1127 unsigned long wchan; /* 'channel' the process is waiting in */ 1128 unsigned long nswap; /* ? */ 1129 unsigned long cnswap; /* ? */ 1130 1131 /* from 'status' */ 1132 int ruid; /* real uid */ 1133 int euid; /* effective uid */ 1134 int suid; /* saved uid */ 1135 int fuid; /* file access uid */ 1136 int rgid; /* real gid */ 1137 int egid; /* effective gid */ 1138 int sgid; /* saved gid */ 1139 int fgid; /* file access gid */ 1140 unsigned long vm_size; /* like vsize but on kb */ 1141 unsigned long vm_lock; /* locked pages in kb */ 1142 unsigned long vm_rss; /* like rss but in kb */ 1143 unsigned long vm_data; /* data size */ 1144 unsigned long vm_stack; /* stack size */ 1145 unsigned long vm_exe; /* executable size */ 1146 unsigned long vm_lib; /* library size */ 1147 }; 1148 1149 /********************************************** 1150 osl_getProcStat 1151 *********************************************/ 1152 1153 sal_Bool osl_getProcStat(pid_t pid, struct osl_procStat* procstat) 1154 { 1155 int fd = 0; 1156 sal_Bool bRet = sal_False; 1157 char name[PATH_MAX + 1]; 1158 snprintf(name, sizeof(name), "/proc/%u/stat", pid); 1159 1160 if ((fd = open(name,O_RDONLY)) >=0 ) 1161 { 1162 char* tmp=0; 1163 char prstatbuf[512]; 1164 memset(prstatbuf,0,512); 1165 bRet = read(fd,prstatbuf,511) == 511; 1166 1167 close(fd); 1168 /*printf("%s\n\n",prstatbuf);*/ 1169 1170 if (!bRet) 1171 return sal_False; 1172 1173 tmp = strrchr(prstatbuf, ')'); 1174 *tmp = '\0'; 1175 memset(procstat->command, 0, sizeof(procstat->command)); 1176 1177 sscanf(prstatbuf, "%d (%15c", &procstat->pid, procstat->command); 1178 sscanf(tmp + 2, 1179 "%c" 1180 "%i %i %i %i %i" 1181 "%lu %lu %lu %lu %lu" 1182 "%lu %lu %lu %lu" 1183 "%lu %li %li %li" 1184 "%lu %lu %li %lu" 1185 "%lu %lu %lu %lu %lu" 1186 "%s %s %s %s" 1187 "%lu %lu %lu", 1188 &procstat->state, 1189 &procstat->ppid, &procstat->pgrp, &procstat->session, &procstat->tty, &procstat->tpgid, 1190 &procstat->flags, &procstat->minflt, &procstat->cminflt, &procstat->majflt, &procstat->cmajflt, 1191 &procstat->utime, &procstat->stime, &procstat->cutime, &procstat->cstime, 1192 &procstat->priority, &procstat->nice, &procstat->timeout, &procstat->itrealvalue, 1193 &procstat->starttime, &procstat->vsize, &procstat->rss, &procstat->rss_rlim, 1194 &procstat->startcode, &procstat->endcode, &procstat->startstack, &procstat->kstkesp, &procstat->kstkeip, 1195 procstat->signal, procstat->blocked, procstat->sigignore, procstat->sigcatch, 1196 &procstat->wchan, &procstat->nswap, &procstat->cnswap 1197 ); 1198 } 1199 return bRet; 1200 } 1201 1202 /********************************************** 1203 osl_getProcStatus 1204 *********************************************/ 1205 1206 sal_Bool osl_getProcStatus(pid_t pid, struct osl_procStat* procstat) 1207 { 1208 int fd = 0; 1209 char name[PATH_MAX + 1]; 1210 snprintf(name, sizeof(name), "/proc/%u/status", pid); 1211 1212 sal_Bool bRet = sal_False; 1213 1214 if ((fd = open(name,O_RDONLY)) >=0 ) 1215 { 1216 char* tmp=0; 1217 char prstatusbuf[512]; 1218 memset(prstatusbuf,0,512); 1219 bRet = read(fd,prstatusbuf,511) == 511; 1220 1221 close(fd); 1222 1223 /* printf("\n\n%s\n\n",prstatusbuf);*/ 1224 1225 if (!bRet) 1226 return sal_False; 1227 1228 tmp = strstr(prstatusbuf,"Uid:"); 1229 if(tmp) 1230 { 1231 sscanf(tmp,"Uid:\t%d\t%d\t%d\t%d", 1232 &procstat->ruid, &procstat->euid, &procstat->suid, &procstat->fuid 1233 ); 1234 } 1235 1236 1237 tmp = strstr(prstatusbuf,"Gid:"); 1238 if(tmp) 1239 { 1240 sscanf(tmp,"Gid:\t%d\t%d\t%d\t%d", 1241 &procstat->rgid, &procstat->egid, &procstat->sgid, &procstat->fgid 1242 ); 1243 } 1244 1245 tmp = strstr(prstatusbuf,"VmSize:"); 1246 if(tmp) 1247 { 1248 sscanf(tmp, 1249 "VmSize: %lu kB\n" 1250 "VmLck: %lu kB\n" 1251 "VmRSS: %lu kB\n" 1252 "VmData: %lu kB\n" 1253 "VmStk: %lu kB\n" 1254 "VmExe: %lu kB\n" 1255 "VmLib: %lu kB\n", 1256 &procstat->vm_size, &procstat->vm_lock, &procstat->vm_rss, &procstat->vm_data, 1257 &procstat->vm_stack, &procstat->vm_exe, &procstat->vm_lib 1258 ); 1259 } 1260 1261 tmp = strstr(prstatusbuf,"SigPnd:"); 1262 if(tmp) 1263 { 1264 sscanf(tmp, "SigPnd: %s SigBlk: %s SigIgn: %s %*s %s", 1265 procstat->signal, procstat->blocked, procstat->sigignore, procstat->sigcatch 1266 ); 1267 } 1268 } 1269 return bRet; 1270 } 1271 1272 #endif 1273 1274 /********************************************** 1275 osl_getProcessInfo 1276 *********************************************/ 1277 1278 oslProcessError SAL_CALL osl_getProcessInfo(oslProcess Process, oslProcessData Fields, oslProcessInfo* pInfo) 1279 { 1280 pid_t pid; 1281 1282 if (Process == NULL) 1283 pid = getpid(); 1284 else 1285 pid = ((oslProcessImpl*)Process)->m_pid; 1286 1287 if (! pInfo || (pInfo->Size != sizeof(oslProcessInfo))) 1288 return osl_Process_E_Unknown; 1289 1290 pInfo->Fields = 0; 1291 1292 if (Fields & osl_Process_IDENTIFIER) 1293 { 1294 pInfo->Ident = pid; 1295 pInfo->Fields |= osl_Process_IDENTIFIER; 1296 } 1297 1298 if (Fields & osl_Process_EXITCODE) 1299 { 1300 if ((Process != NULL) && 1301 osl_checkCondition(((oslProcessImpl*)Process)->m_terminated)) 1302 { 1303 pInfo->Code = ((oslProcessImpl*)Process)->m_status; 1304 pInfo->Fields |= osl_Process_EXITCODE; 1305 } 1306 } 1307 1308 if (Fields & (osl_Process_HEAPUSAGE | osl_Process_CPUTIMES)) 1309 { 1310 1311 #if defined(SOLARIS) 1312 1313 int fd; 1314 sal_Char name[PATH_MAX + 1]; 1315 1316 snprintf(name, sizeof(name), "/proc/%u", pid); 1317 1318 if ((fd = open(name, O_RDONLY)) >= 0) 1319 { 1320 prstatus_t prstatus; 1321 1322 if (ioctl(fd, PIOCSTATUS, &prstatus) >= 0) 1323 { 1324 if (Fields & osl_Process_CPUTIMES) 1325 { 1326 pInfo->UserTime.Seconds = prstatus.pr_utime.tv_sec; 1327 pInfo->UserTime.Nanosec = prstatus.pr_utime.tv_nsec; 1328 pInfo->SystemTime.Seconds = prstatus.pr_stime.tv_sec; 1329 pInfo->SystemTime.Nanosec = prstatus.pr_stime.tv_nsec; 1330 1331 pInfo->Fields |= osl_Process_CPUTIMES; 1332 } 1333 1334 if (Fields & osl_Process_HEAPUSAGE) 1335 { 1336 pInfo->HeapUsage = prstatus.pr_brksize; 1337 1338 pInfo->Fields |= osl_Process_HEAPUSAGE; 1339 } 1340 1341 close(fd); 1342 1343 return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown; 1344 } 1345 else 1346 close(fd); 1347 } 1348 1349 #elif defined(HPUX) 1350 1351 struct pst_status prstatus; 1352 1353 if (pstat_getproc(&prstatus, sizeof(prstatus), (size_t)0, pid) == 1) 1354 { 1355 if (Fields & osl_Process_CPUTIMES) 1356 { 1357 pInfo->UserTime.Seconds = prstatus.pst_utime; 1358 pInfo->UserTime.Nanosec = 500000L; 1359 pInfo->SystemTime.Seconds = prstatus.pst_stime; 1360 pInfo->SystemTime.Nanosec = 500000L; 1361 1362 pInfo->Fields |= osl_Process_CPUTIMES; 1363 } 1364 1365 if (Fields & osl_Process_HEAPUSAGE) 1366 { 1367 pInfo->HeapUsage = prstatus.pst_vdsize*PAGESIZE; 1368 1369 pInfo->Fields |= osl_Process_HEAPUSAGE; 1370 } 1371 1372 return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown; 1373 } 1374 1375 #elif defined(LINUX) 1376 1377 if ( (Fields & osl_Process_CPUTIMES) || (Fields & osl_Process_HEAPUSAGE) ) 1378 { 1379 struct osl_procStat procstat; 1380 memset(&procstat,0,sizeof(procstat)); 1381 1382 if ( (Fields & osl_Process_CPUTIMES) && osl_getProcStat(pid, &procstat) ) 1383 { 1384 /* 1385 * mfe: 1386 * We calculate only time of the process proper. 1387 * Threads are processes, we do not consider their time here! 1388 * (For this, cutime and cstime should be used, it seems not 1389 * to work in 2.0.36) 1390 */ 1391 1392 long clktck; 1393 unsigned long hz; 1394 unsigned long userseconds; 1395 unsigned long systemseconds; 1396 1397 clktck = sysconf(_SC_CLK_TCK); 1398 if (clktck < 0) { 1399 return osl_Process_E_Unknown; 1400 } 1401 hz = (unsigned long) clktck; 1402 1403 userseconds = procstat.utime/hz; 1404 systemseconds = procstat.stime/hz; 1405 1406 pInfo->UserTime.Seconds = userseconds; 1407 pInfo->UserTime.Nanosec = procstat.utime - (userseconds * hz); 1408 pInfo->SystemTime.Seconds = systemseconds; 1409 pInfo->SystemTime.Nanosec = procstat.stime - (systemseconds * hz); 1410 1411 pInfo->Fields |= osl_Process_CPUTIMES; 1412 } 1413 1414 if ( (Fields & osl_Process_HEAPUSAGE) && osl_getProcStatus(pid, &procstat) ) 1415 { 1416 /* 1417 * mfe: 1418 * vm_data (found in status) shows the size of the data segment 1419 * it a rough approximation of the core heap size 1420 */ 1421 pInfo->HeapUsage = procstat.vm_data*1024; 1422 1423 pInfo->Fields |= osl_Process_HEAPUSAGE; 1424 } 1425 } 1426 1427 return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown; 1428 #endif 1429 1430 } 1431 1432 return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown; 1433 } 1434 1435 1436 /*********************************************** 1437 helper function for osl_joinProcessWithTimeout 1438 **********************************************/ 1439 1440 static int is_timeout(const struct timeval* tend) 1441 { 1442 struct timeval tcurrent; 1443 gettimeofday(&tcurrent, NULL); 1444 return (tcurrent.tv_sec >= tend->tv_sec); 1445 } 1446 1447 /********************************************** 1448 kill(pid, 0) is useful for checking if a 1449 process is still alive, but remember that 1450 kill even returns 0 if the process is already 1451 a zombie. 1452 *********************************************/ 1453 1454 static int is_process_dead(pid_t pid) 1455 { 1456 return ((-1 == kill(pid, 0)) && (ESRCH == errno)); 1457 } 1458 1459 /********************************************** 1460 osl_joinProcessWithTimeout 1461 *********************************************/ 1462 1463 oslProcessError SAL_CALL osl_joinProcessWithTimeout(oslProcess Process, const TimeValue* pTimeout) 1464 { 1465 oslProcessImpl* pChild = ChildList; 1466 oslProcessError osl_error = osl_Process_E_None; 1467 1468 OSL_PRECOND(Process, "osl_joinProcess: Invalid parameter"); 1469 OSL_ASSERT(ChildListMutex); 1470 1471 if (NULL == Process || 0 == ChildListMutex) 1472 return osl_Process_E_Unknown; 1473 1474 osl_acquireMutex(ChildListMutex); 1475 1476 /* check if process is a child of ours */ 1477 while (pChild != NULL) 1478 { 1479 if (pChild == (oslProcessImpl*)Process) 1480 break; 1481 1482 pChild = pChild->m_pnext; 1483 } 1484 1485 osl_releaseMutex(ChildListMutex); 1486 1487 if (pChild != NULL) 1488 { 1489 oslConditionResult cond_res = osl_waitCondition(pChild->m_terminated, pTimeout); 1490 1491 if (osl_cond_result_timeout == cond_res) 1492 osl_error = osl_Process_E_TimedOut; 1493 else if (osl_cond_result_ok != cond_res) 1494 osl_error = osl_Process_E_Unknown; 1495 } 1496 else /* alien process; StatusThread will not be able 1497 to set the condition terminated */ 1498 { 1499 pid_t pid = ((oslProcessImpl*)Process)->m_pid; 1500 1501 if (pTimeout) 1502 { 1503 int timeout = 0; 1504 struct timeval tend; 1505 1506 gettimeofday(&tend, NULL); 1507 1508 tend.tv_sec += pTimeout->Seconds; 1509 1510 while (!is_process_dead(pid) && ((timeout = is_timeout(&tend)) == 0)) 1511 sleep(1); 1512 1513 if (timeout) 1514 osl_error = osl_Process_E_TimedOut; 1515 } 1516 else /* infinite */ 1517 { 1518 while (!is_process_dead(pid)) 1519 sleep(1); 1520 } 1521 } 1522 return osl_error; 1523 } 1524 1525 /********************************************** 1526 osl_joinProcess 1527 *********************************************/ 1528 1529 oslProcessError SAL_CALL osl_joinProcess(oslProcess Process) 1530 { 1531 return osl_joinProcessWithTimeout(Process, NULL); 1532 } 1533