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