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