diff options
Diffstat (limited to 'sal/osl/unx/process.c')
-rw-r--r-- | sal/osl/unx/process.c | 1528 |
1 files changed, 0 insertions, 1528 deletions
diff --git a/sal/osl/unx/process.c b/sal/osl/unx/process.c deleted file mode 100644 index 307cee5a5..000000000 --- a/sal/osl/unx/process.c +++ /dev/null @@ -1,1528 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - - -/* - * ToDo: - * - cleanup of process status things - * - cleanup of process spawning - * - cleanup of resource transfer - */ - -#if defined(SOLARIS) - // The procfs may only be used without LFS in 32bits. -# ifdef _FILE_OFFSET_BITS -# undef _FILE_OFFSET_BITS -# endif -#endif - - -#if defined(FREEBSD) || defined(NETBSD) || defined(DRAGONFLY) -#include <machine/param.h> -#endif - -#include "system.h" -#if defined(SOLARIS) -# include <sys/procfs.h> -#endif -#include <osl/diagnose.h> -#include <osl/mutex.h> - -#ifndef _OSL_CONDITN_H_ -#include <osl/conditn.h> -#endif -#include <osl/thread.h> -#include <osl/file.h> -#include <osl/signal.h> -#include <rtl/alloc.h> - -#include <grp.h> - -#include "procimpl.h" -#include "readwrite_helper.h" -#include "sockimpl.h" -#include "secimpl.h" - - -#define MAX_ARGS 255 -#define MAX_ENVS 255 - -#if defined(MACOSX) || defined(IOS) || defined(IORESOURCE_TRANSFER_BSD) || defined(AIX) -#define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(int)) -#endif - -/* implemented in file.c */ -extern oslFileError FileURLToPath( char *, size_t, rtl_uString* ); -extern oslFileHandle osl_createFileHandleFromFD( int fd ); - -/****************************************************************************** - * - * Data Type Definition - * - ******************************************************************************/ - -typedef struct { - int m_hPipe; - int m_hConn; - sal_Char m_Name[PATH_MAX + 1]; -} Pipe; - -typedef struct { - const sal_Char* m_pszArgs[MAX_ARGS + 1]; - oslProcessOption m_options; - const sal_Char* m_pszDir; - sal_Char* m_pszEnv[MAX_ENVS + 1]; - uid_t m_uid; - gid_t m_gid; - sal_Char* m_name; - oslCondition m_started; - oslProcessImpl* m_pProcImpl; - oslFileHandle *m_pInputWrite; - oslFileHandle *m_pOutputRead; - oslFileHandle *m_pErrorRead; -} ProcessData; - -typedef struct _oslPipeImpl { - int m_Socket; - sal_Char m_Name[PATH_MAX + 1]; -} oslPipeImpl; - - -/****************************************************************************** - * - * Function Declarations - * - *****************************************************************************/ - -oslProcessError SAL_CALL osl_psz_executeProcess(sal_Char *pszImageName, - sal_Char *pszArguments[], - oslProcessOption Options, - oslSecurity Security, - sal_Char *pszDirectory, - sal_Char *pszEnvironments[], - oslProcess *pProcess, - oslFileHandle *pInputWrite, - oslFileHandle *pOutputRead, - oslFileHandle *pErrorRead ); - - -oslProcessError SAL_CALL osl_searchPath_impl( - const sal_Char* pszName, - const sal_Char* pszPath, - sal_Char Separator, - sal_Char *pszBuffer, - sal_uInt32 Max); - - -sal_Bool osl_getFullPath(const sal_Char* pszFilename, sal_Char* pszPath, sal_uInt32 MaxLen); - -static oslProcessImpl* ChildList; -static oslMutex ChildListMutex; - -/****************************************************************************** - Deprecated - Old and buggy implementation of osl_searchPath used only by - osl_psz_executeProcess. - A new implemenation is in file_path_helper.cxx - *****************************************************************************/ - -oslProcessError SAL_CALL osl_searchPath_impl(const sal_Char* pszName, const sal_Char* pszPath, - sal_Char Separator, sal_Char *pszBuffer, sal_uInt32 Max) -{ - sal_Char path[PATH_MAX + 1]; - sal_Char *pchr; - - path[0] = '\0'; - - OSL_ASSERT(pszName != NULL); - - if ( pszName == 0 ) - { - return osl_Process_E_NotFound; - } - - if (pszPath == NULL) - pszPath = "PATH"; - - if (Separator == '\0') - Separator = ':'; - - - if ( (pchr = getenv(pszPath)) != 0 ) - { - sal_Char *pstr; - - while (*pchr != '\0') - { - pstr = path; - - while ((*pchr != '\0') && (*pchr != Separator)) - *pstr++ = *pchr++; - - if ((pstr > path) && ((*(pstr - 1) != '/'))) - *pstr++ = '/'; - - *pstr = '\0'; - - strcat(path, pszName); - - if (access(path, 0) == 0) - { - char szRealPathBuf[PATH_MAX] = ""; - - if( NULL == realpath(path, szRealPathBuf) || (strlen(szRealPathBuf) >= (sal_uInt32)Max)) - return osl_Process_E_Unknown; - - strcpy(pszBuffer, path); - - return osl_Process_E_None; - } - - if (*pchr == Separator) - pchr++; - } - } - - return osl_Process_E_NotFound; -} - -/****************************************************************************** - * - * New io resource transfer functions - * - *****************************************************************************/ - - -/********************************************** - sendFdPipe - *********************************************/ - -static sal_Bool sendFdPipe(int PipeFD, int SocketFD) -{ - sal_Bool bRet = sal_False; - - struct iovec iov[1]; - struct msghdr msg; - char buf[2]; /* send_fd()/recv_fd() 2-byte protocol */ - int nSend; - int RetCode=0; - -#if defined(IOCHANNEL_TRANSFER_BSD) - - OSL_TRACE("IOCHANNEL_TRANSFER_BSD send"); -/* OSL_TRACE("sending fd %i\n",SocketFD); */ - - iov[0].iov_base = buf; - iov[0].iov_len = sizeof(buf); - msg.msg_iov = iov; - msg.msg_iovlen = 1; - msg.msg_name = NULL; - msg.msg_namelen = 0; - - msg.msg_accrights = (caddr_t) &SocketFD; /* addr of descriptor */ - msg.msg_accrightslen = sizeof(int); /* pass 1 descriptor */ - buf[1] = 0; /* zero status means OK */ - buf[0] = 0; /* null byte flag to recv_fd() */ - -#else - - struct cmsghdr* cmptr = (struct cmsghdr*)malloc(CONTROLLEN); - - OSL_TRACE("!!!!!! IOCHANNEL_TRANSFER_BSD_RENO send"); -/* OSL_TRACE("sending fd %i\n",SocketFD); */ - - iov[0].iov_base = buf; - iov[0].iov_len = sizeof(buf); - msg.msg_iov = iov; - msg.msg_iovlen = 1; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_control = (caddr_t) cmptr; - msg.msg_controllen = CONTROLLEN; - - cmptr->cmsg_level = SOL_SOCKET; - cmptr->cmsg_type = SCM_RIGHTS; - cmptr->cmsg_len = CONTROLLEN; - memcpy(CMSG_DATA(cmptr), &SocketFD, sizeof(int)); - -#endif - - if ( ( nSend = sendmsg(PipeFD, &msg, 0) ) > 0 ) - { - bRet = sal_True; - OSL_TRACE("sendFdPipe : send '%i' bytes\n",nSend); - - } - else - { - OSL_TRACE("sendFdPipe : sending failed (%s)",strerror(errno)); - } - - bRet = safeRead(PipeFD, &RetCode, sizeof(RetCode)); - - if ( bRet && RetCode == 1 ) - { - OSL_TRACE("sendFdPipe : resource was received\n"); - } - else - { - OSL_TRACE("sendFdPipe : resource wasn't received (error %s)\n", strerror(errno)); - } - -#if defined(IOCHANNEL_TRANSFER_BSD_RENO) - free(cmptr); -#endif - - return bRet; -} - -/********************************************** - receiveFdPipe - *********************************************/ - -static oslSocket receiveFdPipe(int PipeFD) -{ - oslSocket pSocket = 0; - struct msghdr msghdr; - struct iovec iov[1]; - char buffer[2]; - sal_Int32 nRead; - int newfd=-1; - int nRetCode=0; -/* char *ptr; */ - -#if defined(IOCHANNEL_TRANSFER_BSD) - - OSL_TRACE("IOCHANNEL_TRANSFER_BSD receive\n"); - - iov[0].iov_base = buffer; - iov[0].iov_len = sizeof(buffer); - msghdr.msg_name = NULL; - msghdr.msg_namelen = 0; - msghdr.msg_iov = iov; - msghdr.msg_iovlen = 1; - msghdr.msg_accrights = (caddr_t) &newfd; /* addr of descriptor */ - msghdr.msg_accrightslen = sizeof(int); /* receive 1 descriptor */ - -#else - struct cmsghdr* cmptr = (struct cmsghdr*)malloc(CONTROLLEN); - - OSL_TRACE(" !!!! IOCHANNEL_TRANSFER_BSD_RENO receive"); - - iov[0].iov_base = buffer; - iov[0].iov_len = sizeof(buffer); - msghdr.msg_name = NULL; - msghdr.msg_namelen = 0; - msghdr.msg_iov = iov; - msghdr.msg_iovlen = 1; - - msghdr.msg_control = (caddr_t) cmptr; - msghdr.msg_controllen = CONTROLLEN; - -#endif - - -#if defined(IOCHANNEL_TRANSFER_BSD) - - if ( ( nRead = recvmsg(PipeFD, &msghdr, 0) ) > 0 ) - { - OSL_TRACE("receiveFdPipe : received '%i' bytes\n",nRead); - } -#else - - if ( ( ( nRead = recvmsg(PipeFD, &msghdr, 0) ) > 0 ) && - ( msghdr.msg_controllen == CONTROLLEN ) ) - { - OSL_TRACE("receiveFdPipe : received '%i' bytes\n",nRead); - memcpy(&newfd, CMSG_DATA(cmptr), sizeof(int)); - } -#endif - else - { - OSL_TRACE("receiveFdPipe : receiving failed (%s)",strerror(errno)); - } - - if ( newfd >= 0 ) - { - pSocket = __osl_createSocketImpl(newfd); - nRetCode=1; - OSL_TRACE("received fd %i\n",newfd); - } - - OSL_TRACE("receiveFdPipe : writing back %i",nRetCode); - if ( !safeWrite(PipeFD, &nRetCode, sizeof(nRetCode)) ) - OSL_TRACE("write failed (%s)", strerror(errno)); - - if ( nRead < 0 ) - { - OSL_TRACE("write failed (%s)", strerror(errno)); - } - else if ( nRead != sizeof(nRetCode) ) - { - // TODO: Handle this case. - OSL_TRACE("partial write: wrote %d out of %d)", nRead, sizeof(nRetCode)); - } - -#if defined(IOCHANNEL_TRANSFER_BSD_RENO) - free(cmptr); -#endif - - return pSocket; -} - -/********************************************** - osl_sendResourcePipe - *********************************************/ - -sal_Bool osl_sendResourcePipe(oslPipe pPipe, oslSocket pSocket) -{ - sal_Bool bRet = sal_False; - - if ( pSocket == 0 || pPipe == 0 ) - { - return sal_False; - } - - bRet = sendFdPipe(pPipe->m_Socket,pSocket->m_Socket); - - return bRet; -} - -/********************************************** - osl_receiveResourcePipe - *********************************************/ - -oslSocket osl_receiveResourcePipe(oslPipe pPipe) -{ - oslSocket pSocket=0; - - if ( pPipe == 0 ) - { - return 0; - } - - pSocket = receiveFdPipe(pPipe->m_Socket); - - return (oslSocket) pSocket; -} - - - -/****************************************************************************** - * - * Functions for starting a process - * - *****************************************************************************/ - -static void ChildStatusProc(void *pData) -{ - pid_t pid = -1; - int status = 0; - int channel[2]; - ProcessData data; - ProcessData *pdata; - int stdOutput[2] = { -1, -1 }, stdInput[2] = { -1, -1 }, stdError[2] = { -1, -1 }; - - pdata = (ProcessData *)pData; - - /* make a copy of our data, because forking will only copy - our local stack of the thread, so the process data will not be accessible - in our child process */ - memcpy(&data, pData, sizeof(data)); - -#ifdef NO_CHILD_PROCESSES -#define fork() (errno = EINVAL, -1) -#endif - if (socketpair(AF_UNIX, SOCK_STREAM, 0, channel) == -1) - status = errno; - - fcntl(channel[0], F_SETFD, FD_CLOEXEC); - fcntl(channel[1], F_SETFD, FD_CLOEXEC); - - /* Create redirected IO pipes */ - if ( status == 0 && data.m_pInputWrite ) - if (pipe( stdInput ) == -1) - status = errno; - - if ( status == 0 && data.m_pOutputRead ) - if (pipe( stdOutput ) == -1) - status = errno; - - if ( status == 0 && data.m_pErrorRead ) - if (pipe( stdError ) == -1) - status = errno; - - if ( (status == 0) && ((pid = fork()) == 0) ) - { - /* Child */ - int chstatus = 0; - - if (channel[0] != -1) close(channel[0]); - - if ((data.m_uid != (uid_t)-1) && ((data.m_uid != getuid()) || (data.m_gid != getgid()))) - { - OSL_ASSERT(geteuid() == 0); /* must be root */ - - if (! INIT_GROUPS(data.m_name, data.m_gid) || (setuid(data.m_uid) != 0)) - OSL_TRACE("Failed to change uid and guid, errno=%d (%s)\n", errno, strerror(errno)); -#if defined(LINUX) || defined (FREEBSD) || defined(NETBSD) || defined(OPENBSD) || defined(DRAGONFLY) - unsetenv("HOME"); -#else - putenv("HOME="); -#endif - } - - if (data.m_pszDir) - chstatus = chdir(data.m_pszDir); - - if (chstatus == 0 && ((data.m_uid == (uid_t)-1) || ((data.m_uid == getuid()) && (data.m_gid == getgid())))) - { - int i; - for (i = 0; data.m_pszEnv[i] != NULL; i++) - { - if (strchr(data.m_pszEnv[i], '=') == NULL) - { - unsetenv(data.m_pszEnv[i]); /*TODO: check error return*/ - } - else - { - putenv(data.m_pszEnv[i]); /*TODO: check error return*/ - } - } - - OSL_TRACE("ChildStatusProc : starting '%s'",data.m_pszArgs[0]); - - /* Connect std IO to pipe ends */ - - /* Write end of stdInput not used in child process */ - if (stdInput[1] != -1) close( stdInput[1] ); - - /* Read end of stdOutput not used in child process */ - if (stdOutput[0] != -1) close( stdOutput[0] ); - - /* Read end of stdError not used in child process */ - if (stdError[0] != -1) close( stdError[0] ); - - /* Redirect pipe ends to std IO */ - - if ( stdInput[0] != STDIN_FILENO ) - { - dup2( stdInput[0], STDIN_FILENO ); - if (stdInput[0] != -1) close( stdInput[0] ); - } - - if ( stdOutput[1] != STDOUT_FILENO ) - { - dup2( stdOutput[1], STDOUT_FILENO ); - if (stdOutput[1] != -1) close( stdOutput[1] ); - } - - if ( stdError[1] != STDERR_FILENO ) - { - dup2( stdError[1], STDERR_FILENO ); - if (stdError[1] != -1) close( stdError[1] ); - } - - // No need to check the return value of execv. If we return from - // it, an error has occurred. - execv(data.m_pszArgs[0], (sal_Char **)data.m_pszArgs); - } - - OSL_TRACE("Failed to exec, errno=%d (%s)\n", errno, strerror(errno)); - - OSL_TRACE("ChildStatusProc : starting '%s' failed",data.m_pszArgs[0]); - - /* if we reach here, something went wrong */ - if ( !safeWrite(channel[1], &errno, sizeof(errno)) ) - OSL_TRACE("sendFdPipe : sending failed (%s)",strerror(errno)); - - if ( channel[1] != -1 ) - close(channel[1]); - - _exit(255); - } - else - { /* Parent */ - int i = -1; - if (channel[1] != -1) close(channel[1]); - - /* Close unused pipe ends */ - if (stdInput[0] != -1) close( stdInput[0] ); - if (stdOutput[1] != -1) close( stdOutput[1] ); - if (stdError[1] != -1) close( stdError[1] ); - - if (pid > 0) - { - while (((i = read(channel[0], &status, sizeof(status))) < 0)) - { - if (errno != EINTR) - break; - } - } - - if (channel[0] != -1) close(channel[0]); - - if ((pid > 0) && (i == 0)) - { - pid_t child_pid; - osl_acquireMutex(ChildListMutex); - - pdata->m_pProcImpl->m_pid = pid; - pdata->m_pProcImpl->m_pnext = ChildList; - ChildList = pdata->m_pProcImpl; - - /* Store used pipe ends in data structure */ - - if ( pdata->m_pInputWrite ) - *(pdata->m_pInputWrite) = osl_createFileHandleFromFD( stdInput[1] ); - - if ( pdata->m_pOutputRead ) - *(pdata->m_pOutputRead) = osl_createFileHandleFromFD( stdOutput[0] ); - - if ( pdata->m_pErrorRead ) - *(pdata->m_pErrorRead) = osl_createFileHandleFromFD( stdError[0] ); - - osl_releaseMutex(ChildListMutex); - - osl_setCondition(pdata->m_started); - - do - { - child_pid = waitpid(pid, &status, 0); - } while ( 0 > child_pid && EINTR == errno ); - - if ( child_pid < 0) - { - OSL_TRACE("Failed to wait for child process, errno=%d (%s)\n", errno, strerror(errno)); - - /* - We got an other error than EINTR. Anyway we have to wake up the - waiting thread under any circumstances */ - - child_pid = pid; - } - - - if ( child_pid > 0 ) - { - oslProcessImpl* pChild; - - osl_acquireMutex(ChildListMutex); - - pChild = ChildList; - - /* check if it is one of our child processes */ - while (pChild != NULL) - { - if (pChild->m_pid == child_pid) - { - if (WIFEXITED(status)) - pChild->m_status = WEXITSTATUS(status); - else - pChild->m_status = -1; - - osl_setCondition(pChild->m_terminated); - } - - pChild = pChild->m_pnext; - } - - osl_releaseMutex(ChildListMutex); - } - } - else - { - OSL_TRACE("ChildStatusProc : starting '%s' failed",data.m_pszArgs[0]); - OSL_TRACE("Failed to launch child process, child reports errno=%d (%s)\n", status, strerror(status)); - - /* Close pipe ends */ - if ( pdata->m_pInputWrite ) - *pdata->m_pInputWrite = NULL; - - if ( pdata->m_pOutputRead ) - *pdata->m_pOutputRead = NULL; - - if ( pdata->m_pErrorRead ) - *pdata->m_pErrorRead = NULL; - - if (stdInput[1] != -1) close( stdInput[1] ); - if (stdOutput[0] != -1) close( stdOutput[0] ); - if (stdError[0] != -1) close( stdError[0] ); - - //if pid > 0 then a process was created, even if it later failed - //e.g. bash searching for a command to execute, and we still - //need to clean it up to avoid "defunct" processes - if (pid > 0) - { - pid_t child_pid; - do - { - child_pid = waitpid(pid, &status, 0); - } while ( 0 > child_pid && EINTR == errno ); - } - - /* notify (and unblock) parent thread */ - osl_setCondition(pdata->m_started); - } - } -} - -/********************************************** - osl_executeProcess_WithRedirectedIO - *********************************************/ - -oslProcessError SAL_CALL osl_executeProcess_WithRedirectedIO( - rtl_uString *ustrImageName, - rtl_uString *ustrArguments[], - sal_uInt32 nArguments, - oslProcessOption Options, - oslSecurity Security, - rtl_uString *ustrWorkDir, - rtl_uString *ustrEnvironment[], - sal_uInt32 nEnvironmentVars, - oslProcess *pProcess, - oslFileHandle *pInputWrite, - oslFileHandle *pOutputRead, - oslFileHandle *pErrorRead - ) -{ - - oslProcessError Error; - sal_Char* pszWorkDir=0; - sal_Char** pArguments=0; - sal_Char** pEnvironment=0; - unsigned int idx; - - char szImagePath[PATH_MAX] = ""; - char szWorkDir[PATH_MAX] = ""; - - if ( ustrImageName && ustrImageName->length ) - { - FileURLToPath( szImagePath, PATH_MAX, ustrImageName ); - } - - if ( ustrWorkDir != 0 && ustrWorkDir->length ) - { - FileURLToPath( szWorkDir, PATH_MAX, ustrWorkDir ); - pszWorkDir = szWorkDir; - } - - if ( pArguments == 0 && nArguments > 0 ) - { - pArguments = (sal_Char**) malloc( ( nArguments + 2 ) * sizeof(sal_Char*) ); - } - - - for ( idx = 0 ; idx < nArguments ; ++idx ) - { - rtl_String* strArg =0; - - - rtl_uString2String( &strArg, - rtl_uString_getStr(ustrArguments[idx]), - rtl_uString_getLength(ustrArguments[idx]), - osl_getThreadTextEncoding(), - OUSTRING_TO_OSTRING_CVTFLAGS ); - - pArguments[idx]=strdup(rtl_string_getStr(strArg)); - rtl_string_release(strArg); - pArguments[idx+1]=0; - } - - for ( idx = 0 ; idx < nEnvironmentVars ; ++idx ) - { - rtl_String* strEnv=0; - - if ( pEnvironment == 0 ) - { - pEnvironment = (sal_Char**) malloc( ( nEnvironmentVars + 2 ) * sizeof(sal_Char*) ); - } - - rtl_uString2String( &strEnv, - rtl_uString_getStr(ustrEnvironment[idx]), - rtl_uString_getLength(ustrEnvironment[idx]), - osl_getThreadTextEncoding(), - OUSTRING_TO_OSTRING_CVTFLAGS ); - - pEnvironment[idx]=strdup(rtl_string_getStr(strEnv)); - rtl_string_release(strEnv); - pEnvironment[idx+1]=0; - } - - - Error = osl_psz_executeProcess(szImagePath, - pArguments, - Options, - Security, - pszWorkDir, - pEnvironment, - pProcess, - pInputWrite, - pOutputRead, - pErrorRead - ); - - if ( pArguments != 0 ) - { - for ( idx = 0 ; idx < nArguments ; ++idx ) - { - if ( pArguments[idx] != 0 ) - { - free(pArguments[idx]); - } - } - free(pArguments); - } - - if ( pEnvironment != 0 ) - { - for ( idx = 0 ; idx < nEnvironmentVars ; ++idx ) - { - if ( pEnvironment[idx] != 0 ) - { - free(pEnvironment[idx]); - } - } - free(pEnvironment); - } - - return Error; -} - -/********************************************** - osl_executeProcess - *********************************************/ - -oslProcessError SAL_CALL osl_executeProcess( - rtl_uString *ustrImageName, - rtl_uString *ustrArguments[], - sal_uInt32 nArguments, - oslProcessOption Options, - oslSecurity Security, - rtl_uString *ustrWorkDir, - rtl_uString *ustrEnvironment[], - sal_uInt32 nEnvironmentVars, - oslProcess *pProcess - ) -{ - return osl_executeProcess_WithRedirectedIO( - ustrImageName, - ustrArguments, - nArguments, - Options, - Security, - ustrWorkDir, - ustrEnvironment, - nEnvironmentVars, - pProcess, - NULL, - NULL, - NULL - ); -} - -/********************************************** - osl_psz_executeProcess - *********************************************/ - -oslProcessError SAL_CALL osl_psz_executeProcess(sal_Char *pszImageName, - sal_Char *pszArguments[], - oslProcessOption Options, - oslSecurity Security, - sal_Char *pszDirectory, - sal_Char *pszEnvironments[], - oslProcess *pProcess, - oslFileHandle *pInputWrite, - oslFileHandle *pOutputRead, - oslFileHandle *pErrorRead - ) -{ - int i; - sal_Char path[PATH_MAX + 1]; - ProcessData Data; - oslThread hThread; - - path[0] = '\0'; - - memset(&Data,0,sizeof(ProcessData)); - Data.m_pInputWrite = pInputWrite; - Data.m_pOutputRead = pOutputRead; - Data.m_pErrorRead = pErrorRead; - - if (pszImageName == NULL) - pszImageName = pszArguments[0]; - - OSL_ASSERT(pszImageName != NULL); - - if ( pszImageName == 0 ) - { - return osl_Process_E_NotFound; - } - - if ((Options & osl_Process_SEARCHPATH) && - (osl_searchPath_impl(pszImageName, NULL, '\0', path, sizeof(path)) == osl_Process_E_None)) - pszImageName = path; - - Data.m_pszArgs[0] = strdup(pszImageName); - Data.m_pszArgs[1] = 0; - - if ( pszArguments != 0 ) - { - for (i = 0; ((i + 2) < MAX_ARGS) && (pszArguments[i] != NULL); i++) - Data.m_pszArgs[i+1] = strdup(pszArguments[i]); - Data.m_pszArgs[i+2] = NULL; - } - - Data.m_options = Options; - Data.m_pszDir = (pszDirectory != NULL) ? strdup(pszDirectory) : NULL; - - if (pszEnvironments != NULL) - { - for (i = 0; ((i + 1) < MAX_ENVS) && (pszEnvironments[i] != NULL); i++) - Data.m_pszEnv[i] = strdup(pszEnvironments[i]); - Data.m_pszEnv[i+1] = NULL; - } - else - Data.m_pszEnv[0] = NULL; - - if (Security != NULL) - { - Data.m_uid = ((oslSecurityImpl*)Security)->m_pPasswd.pw_uid; - Data.m_gid = ((oslSecurityImpl*)Security)->m_pPasswd.pw_gid; - Data.m_name = ((oslSecurityImpl*)Security)->m_pPasswd.pw_name; - } - else - Data.m_uid = (uid_t)-1; - - Data.m_pProcImpl = (oslProcessImpl*) malloc(sizeof(oslProcessImpl)); - Data.m_pProcImpl->m_pid = 0; - Data.m_pProcImpl->m_terminated = osl_createCondition(); - Data.m_pProcImpl->m_pnext = NULL; - - if (ChildListMutex == NULL) - ChildListMutex = osl_createMutex(); - - Data.m_started = osl_createCondition(); - - hThread = osl_createThread(ChildStatusProc, &Data); - - osl_waitCondition(Data.m_started, NULL); - osl_destroyCondition(Data.m_started); - - for (i = 0; Data.m_pszArgs[i] != NULL; i++) - free((void *)Data.m_pszArgs[i]); - - for (i = 0; Data.m_pszEnv[i] != NULL; i++) - free((void *)Data.m_pszEnv[i]); - - if ( Data.m_pszDir != 0 ) - { - free((void *)Data.m_pszDir); - } - - osl_destroyThread(hThread); - - if (Data.m_pProcImpl->m_pid != 0) - { - *pProcess = Data.m_pProcImpl; - - if (Options & osl_Process_WAIT) - osl_joinProcess(*pProcess); - - return osl_Process_E_None; - } - - osl_destroyCondition(Data.m_pProcImpl->m_terminated); - free(Data.m_pProcImpl); - - return osl_Process_E_Unknown; -} - - -/****************************************************************************** - * - * Functions for processes - * - *****************************************************************************/ - - -/********************************************** - osl_terminateProcess - *********************************************/ - -oslProcessError SAL_CALL osl_terminateProcess(oslProcess Process) -{ - if (Process == NULL) - return osl_Process_E_Unknown; - - if (kill(((oslProcessImpl*)Process)->m_pid, SIGKILL) != 0) - { - switch (errno) - { - case EPERM: - return osl_Process_E_NoPermission; - - case ESRCH: - return osl_Process_E_NotFound; - - default: - return osl_Process_E_Unknown; - } - } - - return osl_Process_E_None; -} - -/********************************************** - osl_getProcess - *********************************************/ - -oslProcess SAL_CALL osl_getProcess(oslProcessIdentifier Ident) -{ - oslProcessImpl *pProcImpl; - - if (kill(Ident, 0) != -1) - { - oslProcessImpl* pChild; - - if (ChildListMutex == NULL) - ChildListMutex = osl_createMutex(); - - osl_acquireMutex(ChildListMutex); - - pChild = ChildList; - - /* check if it is one of our child processes */ - while (pChild != NULL) - { - if (Ident == (sal_uInt32) pChild->m_pid) - break; - - pChild = pChild->m_pnext; - } - - pProcImpl = (oslProcessImpl*) malloc(sizeof(oslProcessImpl)); - pProcImpl->m_pid = Ident; - pProcImpl->m_terminated = osl_createCondition(); - - if (pChild != NULL) - { - /* process is a child so insert into list */ - pProcImpl->m_pnext = pChild->m_pnext; - pChild->m_pnext = pProcImpl; - - pProcImpl->m_status = pChild->m_status; - - if (osl_checkCondition(pChild->m_terminated)) - osl_setCondition(pProcImpl->m_terminated); - } - else - pProcImpl->m_pnext = NULL; - - osl_releaseMutex(ChildListMutex); - } - else - pProcImpl = NULL; - - return (pProcImpl); -} - -/********************************************** - osl_freeProcessHandle - *********************************************/ - -void SAL_CALL osl_freeProcessHandle(oslProcess Process) -{ - if (Process != NULL) - { - oslProcessImpl *pChild, *pPrev = NULL; - - OSL_ASSERT(ChildListMutex != NULL); - - if ( ChildListMutex == 0 ) - { - return; - } - - osl_acquireMutex(ChildListMutex); - - pChild = ChildList; - - /* remove process from child list */ - while (pChild != NULL) - { - if (pChild == (oslProcessImpl*)Process) - { - if (pPrev != NULL) - pPrev->m_pnext = pChild->m_pnext; - else - ChildList = pChild->m_pnext; - - break; - } - - pPrev = pChild; - pChild = pChild->m_pnext; - } - - osl_releaseMutex(ChildListMutex); - - osl_destroyCondition(((oslProcessImpl*)Process)->m_terminated); - - free(Process); - } -} - -#if defined(LINUX) -struct osl_procStat -{ - /* from 'stat' */ - pid_t pid; /* pid */ - char command[16]; /* 'argv[0]' */ /* mfe: it all right char comm[16] in kernel! */ - char state; /* state (running, stopped, ...) */ - pid_t ppid; /* parent pid */ - pid_t pgrp; /* parent group */ - int session; /* session ID */ - int tty; /* no of tty */ - pid_t tpgid; /* group of process owning the tty */ - unsigned long flags; /* flags dunno */ - unsigned long minflt; /* minor page faults */ - unsigned long cminflt; /* minor page faults with children */ - unsigned long majflt; /* major page faults */ - unsigned long cmajflt; /* major page faults with children */ - unsigned long utime; /* no of jiffies in user mode */ - unsigned long stime; /* no of jiffies in kernel mode */ - unsigned long cutime; /* no of jiffies in user mode with children */ - unsigned long cstime; /* no of jiffies in kernel mode with children */ - unsigned long priority; /* nice value + 15 (kernel scheduling prio)*/ - long nice; /* nice value */ - long timeout; /* no of jiffies of next process timeout */ - long itrealvalue; /* no jiffies before next SIGALRM */ - unsigned long starttime; /* process started this no of jiffies after boot */ - unsigned long vsize; /* virtual memory size (in bytes) */ - long rss; /* resident set size (in pages) */ - unsigned long rss_rlim; /* rss limit (in bytes) */ - unsigned long startcode; /* address above program text can run */ - unsigned long endcode; /* address below program text can run */ - unsigned long startstack; /* address of start of stack */ - unsigned long kstkesp; /* current value of 'esp' (stack pointer) */ - unsigned long kstkeip; /* current value of 'eip' (instruction pointer) */ - /* mfe: Linux > 2.1.7x have more signals (88) */ -/*#ifdef LINUX */ - char signal[24]; /* pending signals */ - char blocked[24]; /* blocked signals */ - char sigignore[24]; /* ignored signals */ - char sigcatch[24]; /* catched signals */ -/*#else*/ -/* long long signal;*/ -/* long long blocked;*/ -/* long long sigignore;*/ -/* long long sigcatch;*/ -/*#endif */ - unsigned long wchan; /* 'channel' the process is waiting in */ - unsigned long nswap; /* ? */ - unsigned long cnswap; /* ? */ - - /* from 'status' */ - int ruid; /* real uid */ - int euid; /* effective uid */ - int suid; /* saved uid */ - int fuid; /* file access uid */ - int rgid; /* real gid */ - int egid; /* effective gid */ - int sgid; /* saved gid */ - int fgid; /* file access gid */ - unsigned long vm_size; /* like vsize but on kb */ - unsigned long vm_lock; /* locked pages in kb */ - unsigned long vm_rss; /* like rss but in kb */ - unsigned long vm_data; /* data size */ - unsigned long vm_stack; /* stack size */ - unsigned long vm_exe; /* executable size */ - unsigned long vm_lib; /* library size */ -}; - -/********************************************** - osl_getProcStat - *********************************************/ - -sal_Bool osl_getProcStat(pid_t pid, struct osl_procStat* procstat) -{ - int fd = 0; - sal_Bool bRet = sal_False; - char name[PATH_MAX + 1]; - snprintf(name, sizeof(name), "/proc/%u/stat", pid); - - if ((fd = open(name,O_RDONLY)) >=0 ) - { - char* tmp=0; - char prstatbuf[512]; - memset(prstatbuf,0,512); - bRet = safeRead(fd, prstatbuf, 511); - - close(fd); - /*printf("%s\n\n",prstatbuf);*/ - - if (!bRet) - return sal_False; - - tmp = strrchr(prstatbuf, ')'); - *tmp = '\0'; - memset(procstat->command, 0, sizeof(procstat->command)); - - sscanf(prstatbuf, "%d (%15c", &procstat->pid, procstat->command); - sscanf(tmp + 2, - "%c" - "%i %i %i %i %i" - "%lu %lu %lu %lu %lu" - "%lu %lu %lu %lu" - "%lu %li %li %li" - "%lu %lu %li %lu" - "%lu %lu %lu %lu %lu" - "%s %s %s %s" - "%lu %lu %lu", - &procstat->state, - &procstat->ppid, &procstat->pgrp, &procstat->session, &procstat->tty, &procstat->tpgid, - &procstat->flags, &procstat->minflt, &procstat->cminflt, &procstat->majflt, &procstat->cmajflt, - &procstat->utime, &procstat->stime, &procstat->cutime, &procstat->cstime, - &procstat->priority, &procstat->nice, &procstat->timeout, &procstat->itrealvalue, - &procstat->starttime, &procstat->vsize, &procstat->rss, &procstat->rss_rlim, - &procstat->startcode, &procstat->endcode, &procstat->startstack, &procstat->kstkesp, &procstat->kstkeip, - procstat->signal, procstat->blocked, procstat->sigignore, procstat->sigcatch, - &procstat->wchan, &procstat->nswap, &procstat->cnswap - ); - } - return bRet; -} - -/********************************************** - osl_getProcStatus - *********************************************/ - -sal_Bool osl_getProcStatus(pid_t pid, struct osl_procStat* procstat) -{ - int fd = 0; - char name[PATH_MAX + 1]; - snprintf(name, sizeof(name), "/proc/%u/status", pid); - - sal_Bool bRet = sal_False; - - if ((fd = open(name,O_RDONLY)) >=0 ) - { - char* tmp=0; - char prstatusbuf[512]; - memset(prstatusbuf,0,512); - bRet = safeRead(fd, prstatusbuf, 511); - - close(fd); - - /* printf("\n\n%s\n\n",prstatusbuf);*/ - - if (!bRet) - return sal_False; - - tmp = strstr(prstatusbuf,"Uid:"); - if(tmp) - { - sscanf(tmp,"Uid:\t%d\t%d\t%d\t%d", - &procstat->ruid, &procstat->euid, &procstat->suid, &procstat->fuid - ); - } - - - tmp = strstr(prstatusbuf,"Gid:"); - if(tmp) - { - sscanf(tmp,"Gid:\t%d\t%d\t%d\t%d", - &procstat->rgid, &procstat->egid, &procstat->sgid, &procstat->fgid - ); - } - - tmp = strstr(prstatusbuf,"VmSize:"); - if(tmp) - { - sscanf(tmp, - "VmSize: %lu kB\n" - "VmLck: %lu kB\n" - "VmRSS: %lu kB\n" - "VmData: %lu kB\n" - "VmStk: %lu kB\n" - "VmExe: %lu kB\n" - "VmLib: %lu kB\n", - &procstat->vm_size, &procstat->vm_lock, &procstat->vm_rss, &procstat->vm_data, - &procstat->vm_stack, &procstat->vm_exe, &procstat->vm_lib - ); - } - - tmp = strstr(prstatusbuf,"SigPnd:"); - if(tmp) - { - sscanf(tmp, "SigPnd: %s SigBlk: %s SigIgn: %s %*s %s", - procstat->signal, procstat->blocked, procstat->sigignore, procstat->sigcatch - ); - } - } - return bRet; -} - -#endif - -/********************************************** - osl_getProcessInfo - *********************************************/ - -oslProcessError SAL_CALL osl_getProcessInfo(oslProcess Process, oslProcessData Fields, oslProcessInfo* pInfo) -{ - pid_t pid; - - if (Process == NULL) - pid = getpid(); - else - pid = ((oslProcessImpl*)Process)->m_pid; - - if (! pInfo || (pInfo->Size != sizeof(oslProcessInfo))) - return osl_Process_E_Unknown; - - pInfo->Fields = 0; - - if (Fields & osl_Process_IDENTIFIER) - { - pInfo->Ident = pid; - pInfo->Fields |= osl_Process_IDENTIFIER; - } - - if (Fields & osl_Process_EXITCODE) - { - if ((Process != NULL) && - osl_checkCondition(((oslProcessImpl*)Process)->m_terminated)) - { - pInfo->Code = ((oslProcessImpl*)Process)->m_status; - pInfo->Fields |= osl_Process_EXITCODE; - } - } - - if (Fields & (osl_Process_HEAPUSAGE | osl_Process_CPUTIMES)) - { - -#if defined(SOLARIS) - - int fd; - sal_Char name[PATH_MAX + 1]; - - snprintf(name, sizeof(name), "/proc/%u", pid); - - if ((fd = open(name, O_RDONLY)) >= 0) - { - prstatus_t prstatus; - - if (ioctl(fd, PIOCSTATUS, &prstatus) >= 0) - { - if (Fields & osl_Process_CPUTIMES) - { - pInfo->UserTime.Seconds = prstatus.pr_utime.tv_sec; - pInfo->UserTime.Nanosec = prstatus.pr_utime.tv_nsec; - pInfo->SystemTime.Seconds = prstatus.pr_stime.tv_sec; - pInfo->SystemTime.Nanosec = prstatus.pr_stime.tv_nsec; - - pInfo->Fields |= osl_Process_CPUTIMES; - } - - if (Fields & osl_Process_HEAPUSAGE) - { - pInfo->HeapUsage = prstatus.pr_brksize; - - pInfo->Fields |= osl_Process_HEAPUSAGE; - } - - close(fd); - - return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown; - } - else - close(fd); - } - -#elif defined(LINUX) - - if ( (Fields & osl_Process_CPUTIMES) || (Fields & osl_Process_HEAPUSAGE) ) - { - struct osl_procStat procstat; - memset(&procstat,0,sizeof(procstat)); - - if ( (Fields & osl_Process_CPUTIMES) && osl_getProcStat(pid, &procstat) ) - { - /* - * mfe: - * We calculate only time of the process proper. - * Threads are processes, we do not consider their time here! - * (For this, cutime and cstime should be used, it seems not - * to work in 2.0.36) - */ - - long clktck; - unsigned long hz; - unsigned long userseconds; - unsigned long systemseconds; - - clktck = sysconf(_SC_CLK_TCK); - if (clktck < 0) { - return osl_Process_E_Unknown; - } - hz = (unsigned long) clktck; - - userseconds = procstat.utime/hz; - systemseconds = procstat.stime/hz; - - pInfo->UserTime.Seconds = userseconds; - pInfo->UserTime.Nanosec = procstat.utime - (userseconds * hz); - pInfo->SystemTime.Seconds = systemseconds; - pInfo->SystemTime.Nanosec = procstat.stime - (systemseconds * hz); - - pInfo->Fields |= osl_Process_CPUTIMES; - } - - if ( (Fields & osl_Process_HEAPUSAGE) && osl_getProcStatus(pid, &procstat) ) - { - /* - * mfe: - * vm_data (found in status) shows the size of the data segment - * it a rough approximation of the core heap size - */ - pInfo->HeapUsage = procstat.vm_data*1024; - - pInfo->Fields |= osl_Process_HEAPUSAGE; - } - } - - return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown; -#endif - - } - - return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown; -} - - -/*********************************************** - helper function for osl_joinProcessWithTimeout - **********************************************/ - -static int is_timeout(const struct timeval* tend) -{ - struct timeval tcurrent; - gettimeofday(&tcurrent, NULL); - return (tcurrent.tv_sec >= tend->tv_sec); -} - -/********************************************** - kill(pid, 0) is usefull for checking if a - process is still alive, but remember that - kill even returns 0 if the process is already - a zombie. - *********************************************/ - -static int is_process_dead(pid_t pid) -{ - return ((-1 == kill(pid, 0)) && (ESRCH == errno)); -} - -/********************************************** - osl_joinProcessWithTimeout - *********************************************/ - -oslProcessError SAL_CALL osl_joinProcessWithTimeout(oslProcess Process, const TimeValue* pTimeout) -{ - oslProcessImpl* pChild = ChildList; - oslProcessError osl_error = osl_Process_E_None; - - OSL_PRECOND(Process, "osl_joinProcess: Invalid parameter"); - OSL_ASSERT(ChildListMutex); - - if (NULL == Process || 0 == ChildListMutex) - return osl_Process_E_Unknown; - - osl_acquireMutex(ChildListMutex); - - /* check if process is a child of ours */ - while (pChild != NULL) - { - if (pChild == (oslProcessImpl*)Process) - break; - - pChild = pChild->m_pnext; - } - - osl_releaseMutex(ChildListMutex); - - if (pChild != NULL) - { - oslConditionResult cond_res = osl_waitCondition(pChild->m_terminated, pTimeout); - - if (osl_cond_result_timeout == cond_res) - osl_error = osl_Process_E_TimedOut; - else if (osl_cond_result_ok != cond_res) - osl_error = osl_Process_E_Unknown; - } - else /* alien process; StatusThread will not be able - to set the condition terminated */ - { - pid_t pid = ((oslProcessImpl*)Process)->m_pid; - - if (pTimeout) - { - int timeout = 0; - struct timeval tend; - - gettimeofday(&tend, NULL); - - tend.tv_sec += pTimeout->Seconds; - - while (!is_process_dead(pid) && ((timeout = is_timeout(&tend)) == 0)) - sleep(1); - - if (timeout) - osl_error = osl_Process_E_TimedOut; - } - else /* infinite */ - { - while (!is_process_dead(pid)) - sleep(1); - } - } - return osl_error; -} - -/********************************************** - osl_joinProcess - *********************************************/ - -oslProcessError SAL_CALL osl_joinProcess(oslProcess Process) -{ - return osl_joinProcessWithTimeout(Process, NULL); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |