update dev300-m58
[ooovba.git] / sal / osl / unx / process.c
blob2eaea19eddc2639852aec3ae3533fdebcf86f385
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: process.c,v $
10 * $Revision: 1.44 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
33 * ToDo:
34 * - cleanup of process status things
35 * - cleanup of process spawning
36 * - cleanup of resource transfer
39 #if defined(SOLARIS)
40 // The procfs may only be used without LFS in 32bits.
41 # ifdef _FILE_OFFSET_BITS
42 # undef _FILE_OFFSET_BITS
43 # endif
44 #endif
47 #ifdef FREEBSD
48 #include <machine/param.h>
49 #endif
51 #include "system.h"
52 #if defined(SOLARIS) || defined(IRIX)
53 # include <sys/procfs.h>
54 #endif
55 #include <osl/diagnose.h>
56 #include <osl/mutex.h>
58 #ifndef _OSL_CONDITN_H_
59 #include <osl/conditn.h>
60 #endif
61 #include <osl/thread.h>
62 #include <osl/file.h>
63 #include <osl/signal.h>
64 #include <rtl/alloc.h>
66 #include <grp.h>
68 #include "procimpl.h"
69 #include "sockimpl.h"
70 #include "secimpl.h"
73 #define MAX_ARGS 255
74 #define MAX_ENVS 255
76 #if defined(MACOSX) || defined(IORESOURCE_TRANSFER_BSD)
77 #define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(int))
78 #endif
80 /* implemented in file.c */
81 extern oslFileError FileURLToPath( char *, size_t, rtl_uString* );
82 extern oslFileHandle osl_createFileHandleFromFD( int fd );
84 /******************************************************************************
86 * Data Type Definition
88 ******************************************************************************/
90 typedef struct {
91 int m_hPipe;
92 int m_hConn;
93 sal_Char m_Name[PATH_MAX + 1];
94 } Pipe;
96 typedef struct {
97 const sal_Char* m_pszArgs[MAX_ARGS + 1];
98 oslProcessOption m_options;
99 const sal_Char* m_pszDir;
100 sal_Char* m_pszEnv[MAX_ENVS + 1];
101 uid_t m_uid;
102 gid_t m_gid;
103 sal_Char* m_name;
104 oslCondition m_started;
105 oslProcessImpl* m_pProcImpl;
106 oslFileHandle *m_pInputWrite;
107 oslFileHandle *m_pOutputRead;
108 oslFileHandle *m_pErrorRead;
109 } ProcessData;
111 typedef struct _oslPipeImpl {
112 int m_Socket;
113 sal_Char m_Name[PATH_MAX + 1];
114 } oslPipeImpl;
117 /******************************************************************************
119 * Function Declarations
121 *****************************************************************************/
123 oslProcessError SAL_CALL osl_psz_executeProcess(sal_Char *pszImageName,
124 sal_Char *pszArguments[],
125 oslProcessOption Options,
126 oslSecurity Security,
127 sal_Char *pszDirectory,
128 sal_Char *pszEnvironments[],
129 oslProcess *pProcess,
130 oslFileHandle *pInputWrite,
131 oslFileHandle *pOutputRead,
132 oslFileHandle *pErrorRead );
135 oslProcessError SAL_CALL osl_searchPath_impl(
136 const sal_Char* pszName,
137 const sal_Char* pszPath,
138 sal_Char Separator,
139 sal_Char *pszBuffer,
140 sal_uInt32 Max);
143 sal_Bool osl_getFullPath(const sal_Char* pszFilename, sal_Char* pszPath, sal_uInt32 MaxLen);
145 static oslProcessImpl* ChildList;
146 static oslMutex ChildListMutex;
148 /******************************************************************************
149 Deprecated
150 Old and buggy implementation of osl_searchPath used only by
151 osl_psz_executeProcess.
152 A new implemenation is in file_path_helper.cxx
153 *****************************************************************************/
155 oslProcessError SAL_CALL osl_searchPath_impl(const sal_Char* pszName, const sal_Char* pszPath,
156 sal_Char Separator, sal_Char *pszBuffer, sal_uInt32 Max)
158 sal_Char path[PATH_MAX + 1];
159 sal_Char *pchr;
161 path[0] = '\0';
163 OSL_ASSERT(pszName != NULL);
165 if ( pszName == 0 )
167 return osl_Process_E_NotFound;
170 if (pszPath == NULL)
171 pszPath = "PATH";
173 if (Separator == '\0')
174 Separator = ':';
177 if ( (pchr = getenv(pszPath)) != 0 )
179 sal_Char *pstr;
181 while (*pchr != '\0')
183 pstr = path;
185 while ((*pchr != '\0') && (*pchr != Separator))
186 *pstr++ = *pchr++;
188 if ((pstr > path) && ((*(pstr - 1) != '/')))
189 *pstr++ = '/';
191 *pstr = '\0';
193 strcat(path, pszName);
195 if (access(path, 0) == 0)
197 char szRealPathBuf[PATH_MAX] = "";
199 if( NULL == realpath(path, szRealPathBuf) || (strlen(szRealPathBuf) >= (sal_uInt32)Max))
200 return osl_Process_E_Unknown;
202 strcpy(pszBuffer, path);
204 return osl_Process_E_None;
207 if (*pchr == Separator)
208 pchr++;
212 return osl_Process_E_NotFound;
215 /******************************************************************************
217 * New io resource transfer functions
219 *****************************************************************************/
222 /**********************************************
223 sendFdPipe
224 *********************************************/
226 static sal_Bool sendFdPipe(int PipeFD, int SocketFD)
228 sal_Bool bRet = sal_False;
230 struct iovec iov[1];
231 struct msghdr msg;
232 char buf[2]; /* send_fd()/recv_fd() 2-byte protocol */
233 int nSend;
234 int RetCode=0;
236 #if defined(IOCHANNEL_TRANSFER_BSD)
238 OSL_TRACE("IOCHANNEL_TRANSFER_BSD send");
239 /* OSL_TRACE("sending fd %i\n",SocketFD); */
241 iov[0].iov_base = buf;
242 iov[0].iov_len = sizeof(buf);
243 msg.msg_iov = iov;
244 msg.msg_iovlen = 1;
245 msg.msg_name = NULL;
246 msg.msg_namelen = 0;
248 msg.msg_accrights = (caddr_t) &SocketFD; /* addr of descriptor */
249 msg.msg_accrightslen = sizeof(int); /* pass 1 descriptor */
250 buf[1] = 0; /* zero status means OK */
251 buf[0] = 0; /* null byte flag to recv_fd() */
253 #else
255 struct cmsghdr* cmptr = (struct cmsghdr*)malloc(CONTROLLEN);
257 OSL_TRACE("!!!!!! IOCHANNEL_TRANSFER_BSD_RENO send");
258 /* OSL_TRACE("sending fd %i\n",SocketFD); */
260 iov[0].iov_base = buf;
261 iov[0].iov_len = sizeof(buf);
262 msg.msg_iov = iov;
263 msg.msg_iovlen = 1;
264 msg.msg_name = NULL;
265 msg.msg_namelen = 0;
266 msg.msg_control = (caddr_t) cmptr;
267 msg.msg_controllen = CONTROLLEN;
269 cmptr->cmsg_level = SOL_SOCKET;
270 cmptr->cmsg_type = SCM_RIGHTS;
271 cmptr->cmsg_len = CONTROLLEN;
272 *(int*)CMSG_DATA(cmptr) = SocketFD;
274 #endif
276 if ( ( nSend = sendmsg(PipeFD, &msg, 0) ) > 0 )
278 bRet = sal_True;
279 OSL_TRACE("sendFdPipe : send '%i' bytes\n",nSend);
282 else
284 OSL_TRACE("sendFdPipe : sending failed (%s)",strerror(errno));
287 nSend=read(PipeFD,&RetCode,sizeof(RetCode));
289 if ( nSend > 0 && RetCode == 1 )
291 OSL_TRACE("sendFdPipe : resource was received\n");
293 else
295 OSL_TRACE("sendFdPipe : resource wasn't received\n");
298 #if defined(IOCHANNEL_TRANSFER_BSD_RENO)
299 free(cmptr);
300 #endif
302 return bRet;
305 /**********************************************
306 receiveFdPipe
307 *********************************************/
309 static oslSocket receiveFdPipe(int PipeFD)
311 oslSocket pSocket = 0;
312 struct msghdr msghdr;
313 struct iovec iov[1];
314 char buffer[2];
315 sal_Int32 nRead;
316 int newfd=-1;
317 int nRetCode=0;
318 /* char *ptr; */
320 #if defined(IOCHANNEL_TRANSFER_BSD)
322 OSL_TRACE("IOCHANNEL_TRANSFER_BSD receive\n");
324 iov[0].iov_base = buffer;
325 iov[0].iov_len = sizeof(buffer);
326 msghdr.msg_name = NULL;
327 msghdr.msg_namelen = 0;
328 msghdr.msg_iov = iov;
329 msghdr.msg_iovlen = 1;
330 msghdr.msg_accrights = (caddr_t) &newfd; /* addr of descriptor */
331 msghdr.msg_accrightslen = sizeof(int); /* receive 1 descriptor */
333 #else
334 struct cmsghdr* cmptr = (struct cmsghdr*)malloc(CONTROLLEN);
336 OSL_TRACE(" !!!! IOCHANNEL_TRANSFER_BSD_RENO receive");
338 iov[0].iov_base = buffer;
339 iov[0].iov_len = sizeof(buffer);
340 msghdr.msg_name = NULL;
341 msghdr.msg_namelen = 0;
342 msghdr.msg_iov = iov;
343 msghdr.msg_iovlen = 1;
345 msghdr.msg_control = (caddr_t) cmptr;
346 msghdr.msg_controllen = CONTROLLEN;
348 #endif
351 #if defined(IOCHANNEL_TRANSFER_BSD)
353 if ( ( nRead = recvmsg(PipeFD, &msghdr, 0) ) > 0 )
355 OSL_TRACE("receiveFdPipe : received '%i' bytes\n",nRead);
357 #else
359 if ( ( ( nRead = recvmsg(PipeFD, &msghdr, 0) ) > 0 ) &&
360 ( msghdr.msg_controllen == CONTROLLEN ) )
362 OSL_TRACE("receiveFdPipe : received '%i' bytes\n",nRead);
363 newfd = *(int*)CMSG_DATA(cmptr);
365 #endif
366 else
368 OSL_TRACE("receiveFdPipe : receiving failed (%s)",strerror(errno));
371 if ( newfd >= 0 )
373 pSocket = __osl_createSocketImpl(newfd);
374 nRetCode=1;
375 OSL_TRACE("received fd %i\n",newfd);
378 OSL_TRACE("receiveFdPipe : writing back %i",nRetCode);
379 nRead=write(PipeFD,&nRetCode,sizeof(nRetCode));
381 #if defined(IOCHANNEL_TRANSFER_BSD_RENO)
382 free(cmptr);
383 #endif
385 return pSocket;
388 /**********************************************
389 osl_sendResourcePipe
390 *********************************************/
392 sal_Bool osl_sendResourcePipe(oslPipe pPipe, oslSocket pSocket)
394 sal_Bool bRet = sal_False;
396 if ( pSocket == 0 || pPipe == 0 )
398 return sal_False;
401 bRet = sendFdPipe(pPipe->m_Socket,pSocket->m_Socket);
403 return bRet;
406 /**********************************************
407 osl_receiveResourcePipe
408 *********************************************/
410 oslSocket osl_receiveResourcePipe(oslPipe pPipe)
412 oslSocket pSocket=0;
414 if ( pPipe == 0 )
416 return 0;
419 pSocket = receiveFdPipe(pPipe->m_Socket);
421 return (oslSocket) pSocket;
426 /******************************************************************************
428 * Functions for starting a process
430 *****************************************************************************/
432 static void ChildStatusProc(void *pData)
434 int i;
435 /* int first = 0;*/
436 pid_t pid;
437 /* int status;*/
438 int channel[2];
439 ProcessData data;
440 ProcessData *pdata;
441 int stdOutput[2] = { -1, -1 }, stdInput[2] = { -1, -1 }, stdError[2] = { -1, -1 };
443 pdata = (ProcessData *)pData;
445 /* make a copy of our data, because forking will only copy
446 our local stack of the thread, so the process data will not be accessible
447 in our child process */
448 memcpy(&data, pData, sizeof(data));
450 socketpair(AF_UNIX, SOCK_STREAM, 0, channel);
452 fcntl(channel[0], F_SETFD, FD_CLOEXEC);
453 fcntl(channel[1], F_SETFD, FD_CLOEXEC);
455 /* Create redirected IO pipes */
457 if ( data.m_pInputWrite )
458 pipe( stdInput );
460 if ( data.m_pOutputRead )
461 pipe( stdOutput );
463 if ( data.m_pErrorRead )
464 pipe( stdError );
466 if ((pid = fork()) == 0)
468 /* Child */
469 close(channel[0]);
471 if ((data.m_uid != (uid_t)-1) && ((data.m_uid != getuid()) || (data.m_gid != getgid())))
473 OSL_ASSERT(geteuid() == 0); /* must be root */
475 if (! INIT_GROUPS(data.m_name, data.m_gid) || (setuid(data.m_uid) != 0))
476 OSL_TRACE("Failed to change uid and guid, errno=%d (%s)\n", errno, strerror(errno));
477 #if defined(LINUX) || defined (FREEBSD)
478 unsetenv("HOME");
479 #else
480 putenv("HOME=");
481 #endif
484 if ((data.m_uid == (uid_t)-1) || ((data.m_uid == getuid()) && (data.m_gid == getgid())))
487 if (data.m_pszDir)
488 chdir(data.m_pszDir);
490 for (i = 0; data.m_pszEnv[i] != NULL; i++)
491 putenv(data.m_pszEnv[i]);
493 #if defined(LINUX) && !defined(NPTL)
494 /* mfe: linux likes to have just one thread when the exec family is called */
495 /* this np function has this purpose ... */
496 pthread_kill_other_threads_np();
497 #endif
498 OSL_TRACE("ChildStatusProc : starting '%s'",data.m_pszArgs[0]);
500 /* Connect std IO to pipe ends */
502 /* Write end of stdInput not used in child process */
503 close( stdInput[1] );
505 /* Read end of stdOutput not used in child process */
506 close( stdOutput[0] );
508 /* Read end of stdError not used in child process */
509 close( stdError[0] );
511 /* Redirect pipe ends to std IO */
513 if ( stdInput[0] != STDIN_FILENO )
515 dup2( stdInput[0], STDIN_FILENO );
516 close( stdInput[0] );
519 if ( stdOutput[1] != STDOUT_FILENO )
521 dup2( stdOutput[1], STDOUT_FILENO );
522 close( stdOutput[1] );
525 if ( stdError[1] != STDERR_FILENO )
527 dup2( stdError[1], STDERR_FILENO );
528 close( stdError[1] );
531 pid=execv(data.m_pszArgs[0], (sal_Char **)data.m_pszArgs);
535 OSL_TRACE("Failed to exec, errno=%d (%s)\n", errno, strerror(errno));
537 OSL_TRACE("ChildStatusProc : starting '%s' failed",data.m_pszArgs[0]);
539 /* if we reach here, something went wrong */
540 write(channel[1], &errno, sizeof(errno));
542 close(channel[1]);
544 _exit(255);
546 else
547 { /* Parent */
548 int status;
550 close(channel[1]);
552 /* Close unused pipe ends */
553 close( stdInput[0] );
554 close( stdOutput[1] );
555 close( stdError[1] );
557 while (((i = read(channel[0], &status, sizeof(status))) < 0))
559 if (errno != EINTR)
560 break;
563 close(channel[0]);
566 if ((pid > 0) && (i == 0))
568 pid_t child_pid;
569 osl_acquireMutex(ChildListMutex);
571 pdata->m_pProcImpl->m_pid = pid;
572 pdata->m_pProcImpl->m_pnext = ChildList;
573 ChildList = pdata->m_pProcImpl;
575 /* Store used pipe ends in data structure */
577 if ( pdata->m_pInputWrite )
578 *(pdata->m_pInputWrite) = osl_createFileHandleFromFD( stdInput[1] );
580 if ( pdata->m_pOutputRead )
581 *(pdata->m_pOutputRead) = osl_createFileHandleFromFD( stdOutput[0] );
583 if ( pdata->m_pErrorRead )
584 *(pdata->m_pErrorRead) = osl_createFileHandleFromFD( stdError[0] );
586 osl_releaseMutex(ChildListMutex);
588 osl_setCondition(pdata->m_started);
592 child_pid = waitpid(pid, &status, 0);
593 } while ( 0 > child_pid && EINTR == errno );
595 if ( child_pid < 0)
597 OSL_TRACE("Failed to wait for child process, errno=%d (%s)\n", errno, strerror(errno));
600 We got an other error than EINTR. Anyway we have to wake up the
601 waiting thread under any circumstances */
603 child_pid = pid;
607 if ( child_pid > 0 )
609 oslProcessImpl* pChild;
611 osl_acquireMutex(ChildListMutex);
613 pChild = ChildList;
615 /* check if it is one of our child processes */
616 while (pChild != NULL)
618 if (pChild->m_pid == child_pid)
620 if (WIFEXITED(status))
621 pChild->m_status = WEXITSTATUS(status);
622 else
623 pChild->m_status = -1;
625 osl_setCondition(pChild->m_terminated);
628 pChild = pChild->m_pnext;
631 osl_releaseMutex(ChildListMutex);
634 else
636 OSL_TRACE("ChildStatusProc : starting '%s' failed",data.m_pszArgs[0]);
637 OSL_TRACE("Failed to launch child process, child reports errno=%d (%s)\n", status, strerror(status));
639 /* Close pipe ends */
640 if ( pdata->m_pInputWrite )
641 *pdata->m_pInputWrite = NULL;
643 if ( pdata->m_pOutputRead )
644 *pdata->m_pOutputRead = NULL;
646 if ( pdata->m_pErrorRead )
647 *pdata->m_pErrorRead = NULL;
649 close( stdInput[1] );
650 close( stdOutput[0] );
651 close( stdError[0] );
653 //if pid > 0 then a process was created, even if it later failed
654 //e.g. bash searching for a command to execute, and we still
655 //need to clean it up to avoid "defunct" processes
656 if (pid > 0)
658 pid_t child_pid;
661 child_pid = waitpid(pid, &status, 0);
662 } while ( 0 > child_pid && EINTR == errno );
665 /* notify (and unblock) parent thread */
666 osl_setCondition(pdata->m_started);
671 /**********************************************
672 osl_executeProcess_WithRedirectedIO
673 *********************************************/
675 oslProcessError SAL_CALL osl_executeProcess_WithRedirectedIO(
676 rtl_uString *ustrImageName,
677 rtl_uString *ustrArguments[],
678 sal_uInt32 nArguments,
679 oslProcessOption Options,
680 oslSecurity Security,
681 rtl_uString *ustrWorkDir,
682 rtl_uString *ustrEnvironment[],
683 sal_uInt32 nEnvironmentVars,
684 oslProcess *pProcess,
685 oslFileHandle *pInputWrite,
686 oslFileHandle *pOutputRead,
687 oslFileHandle *pErrorRead
691 oslProcessError Error;
692 sal_Char* pszWorkDir=0;
693 sal_Char** pArguments=0;
694 sal_Char** pEnvironment=0;
695 unsigned int idx;
697 char szImagePath[PATH_MAX] = "";
698 char szWorkDir[PATH_MAX] = "";
700 if ( ustrImageName && ustrImageName->length )
702 FileURLToPath( szImagePath, PATH_MAX, ustrImageName );
705 if ( ustrWorkDir != 0 && ustrWorkDir->length )
707 FileURLToPath( szWorkDir, PATH_MAX, ustrWorkDir );
708 pszWorkDir = szWorkDir;
711 if ( pArguments == 0 && nArguments > 0 )
713 pArguments = (sal_Char**) malloc( ( nArguments + 2 ) * sizeof(sal_Char*) );
717 for ( idx = 0 ; idx < nArguments ; ++idx )
719 rtl_String* strArg =0;
722 rtl_uString2String( &strArg,
723 rtl_uString_getStr(ustrArguments[idx]),
724 rtl_uString_getLength(ustrArguments[idx]),
725 osl_getThreadTextEncoding(),
726 OUSTRING_TO_OSTRING_CVTFLAGS );
728 pArguments[idx]=strdup(rtl_string_getStr(strArg));
729 rtl_string_release(strArg);
730 pArguments[idx+1]=0;
733 for ( idx = 0 ; idx < nEnvironmentVars ; ++idx )
735 rtl_String* strEnv=0;
737 if ( pEnvironment == 0 )
739 pEnvironment = (sal_Char**) malloc( ( nEnvironmentVars + 2 ) * sizeof(sal_Char*) );
742 rtl_uString2String( &strEnv,
743 rtl_uString_getStr(ustrEnvironment[idx]),
744 rtl_uString_getLength(ustrEnvironment[idx]),
745 osl_getThreadTextEncoding(),
746 OUSTRING_TO_OSTRING_CVTFLAGS );
748 pEnvironment[idx]=strdup(rtl_string_getStr(strEnv));
749 rtl_string_release(strEnv);
750 pEnvironment[idx+1]=0;
754 Error = osl_psz_executeProcess(szImagePath,
755 pArguments,
756 Options,
757 Security,
758 pszWorkDir,
759 pEnvironment,
760 pProcess,
761 pInputWrite,
762 pOutputRead,
763 pErrorRead
766 if ( pArguments != 0 )
768 for ( idx = 0 ; idx < nArguments ; ++idx )
770 if ( pArguments[idx] != 0 )
772 free(pArguments[idx]);
775 free(pArguments);
778 if ( pEnvironment != 0 )
780 for ( idx = 0 ; idx < nEnvironmentVars ; ++idx )
782 if ( pEnvironment[idx] != 0 )
784 free(pEnvironment[idx]);
787 free(pEnvironment);
790 return Error;
793 /**********************************************
794 osl_executeProcess
795 *********************************************/
797 oslProcessError SAL_CALL osl_executeProcess(
798 rtl_uString *ustrImageName,
799 rtl_uString *ustrArguments[],
800 sal_uInt32 nArguments,
801 oslProcessOption Options,
802 oslSecurity Security,
803 rtl_uString *ustrWorkDir,
804 rtl_uString *ustrEnvironment[],
805 sal_uInt32 nEnvironmentVars,
806 oslProcess *pProcess
809 return osl_executeProcess_WithRedirectedIO(
810 ustrImageName,
811 ustrArguments,
812 nArguments,
813 Options,
814 Security,
815 ustrWorkDir,
816 ustrEnvironment,
817 nEnvironmentVars,
818 pProcess,
819 NULL,
820 NULL,
821 NULL
825 /**********************************************
826 osl_psz_executeProcess
827 *********************************************/
829 oslProcessError SAL_CALL osl_psz_executeProcess(sal_Char *pszImageName,
830 sal_Char *pszArguments[],
831 oslProcessOption Options,
832 oslSecurity Security,
833 sal_Char *pszDirectory,
834 sal_Char *pszEnvironments[],
835 oslProcess *pProcess,
836 oslFileHandle *pInputWrite,
837 oslFileHandle *pOutputRead,
838 oslFileHandle *pErrorRead
841 int i;
842 sal_Char path[PATH_MAX + 1];
843 ProcessData Data;
844 oslThread hThread;
846 path[0] = '\0';
848 memset(&Data,0,sizeof(ProcessData));
849 Data.m_pInputWrite = pInputWrite;
850 Data.m_pOutputRead = pOutputRead;
851 Data.m_pErrorRead = pErrorRead;
853 if (pszImageName == NULL)
854 pszImageName = pszArguments[0];
856 OSL_ASSERT(pszImageName != NULL);
858 if ( pszImageName == 0 )
860 return osl_Process_E_NotFound;
863 if ((Options & osl_Process_SEARCHPATH) &&
864 (osl_searchPath_impl(pszImageName, NULL, '\0', path, sizeof(path)) == osl_Process_E_None))
865 pszImageName = path;
867 Data.m_pszArgs[0] = strdup(pszImageName);
868 Data.m_pszArgs[1] = 0;
870 if ( pszArguments != 0 )
872 for (i = 0; ((i + 2) < MAX_ARGS) && (pszArguments[i] != NULL); i++)
873 Data.m_pszArgs[i+1] = strdup(pszArguments[i]);
874 Data.m_pszArgs[i+2] = NULL;
877 Data.m_options = Options;
878 Data.m_pszDir = (pszDirectory != NULL) ? strdup(pszDirectory) : NULL;
880 if (pszEnvironments != NULL)
882 for (i = 0; ((i + 1) < MAX_ENVS) && (pszEnvironments[i] != NULL); i++)
883 Data.m_pszEnv[i] = strdup(pszEnvironments[i]);
884 Data.m_pszEnv[i+1] = NULL;
886 else
887 Data.m_pszEnv[0] = NULL;
889 if (Security != NULL)
891 Data.m_uid = ((oslSecurityImpl*)Security)->m_pPasswd.pw_uid;
892 Data.m_gid = ((oslSecurityImpl*)Security)->m_pPasswd.pw_gid;
893 Data.m_name = ((oslSecurityImpl*)Security)->m_pPasswd.pw_name;
895 else
896 Data.m_uid = (uid_t)-1;
898 Data.m_pProcImpl = (oslProcessImpl*) malloc(sizeof(oslProcessImpl));
899 Data.m_pProcImpl->m_pid = 0;
900 Data.m_pProcImpl->m_terminated = osl_createCondition();
901 Data.m_pProcImpl->m_pnext = NULL;
903 if (ChildListMutex == NULL)
904 ChildListMutex = osl_createMutex();
906 Data.m_started = osl_createCondition();
908 hThread = osl_createThread(ChildStatusProc, &Data);
910 osl_waitCondition(Data.m_started, NULL);
911 osl_destroyCondition(Data.m_started);
913 for (i = 0; Data.m_pszArgs[i] != NULL; i++)
914 free((void *)Data.m_pszArgs[i]);
916 for (i = 0; Data.m_pszEnv[i] != NULL; i++)
917 free((void *)Data.m_pszEnv[i]);
919 if ( Data.m_pszDir != 0 )
921 free((void *)Data.m_pszDir);
924 osl_destroyThread(hThread);
926 if (Data.m_pProcImpl->m_pid != 0)
928 *pProcess = Data.m_pProcImpl;
930 if (Options & osl_Process_WAIT)
931 osl_joinProcess(*pProcess);
933 return osl_Process_E_None;
936 osl_destroyCondition(Data.m_pProcImpl->m_terminated);
937 free(Data.m_pProcImpl);
939 return osl_Process_E_Unknown;
943 /******************************************************************************
945 * Functions for processes
947 *****************************************************************************/
950 /**********************************************
951 osl_terminateProcess
952 *********************************************/
954 oslProcessError SAL_CALL osl_terminateProcess(oslProcess Process)
956 if (Process == NULL)
957 return osl_Process_E_Unknown;
959 if (kill(((oslProcessImpl*)Process)->m_pid, SIGKILL) != 0)
961 switch (errno)
963 case EPERM:
964 return osl_Process_E_NoPermission;
966 case ESRCH:
967 return osl_Process_E_NotFound;
969 default:
970 return osl_Process_E_Unknown;
974 return osl_Process_E_None;
977 /**********************************************
978 osl_getProcess
979 *********************************************/
981 oslProcess SAL_CALL osl_getProcess(oslProcessIdentifier Ident)
983 oslProcessImpl *pProcImpl;
985 if (kill(Ident, 0) != -1)
987 oslProcessImpl* pChild;
989 if (ChildListMutex == NULL)
990 ChildListMutex = osl_createMutex();
992 osl_acquireMutex(ChildListMutex);
994 pChild = ChildList;
996 /* check if it is one of our child processes */
997 while (pChild != NULL)
999 if (Ident == (sal_uInt32) pChild->m_pid)
1000 break;
1002 pChild = pChild->m_pnext;
1005 pProcImpl = (oslProcessImpl*) malloc(sizeof(oslProcessImpl));
1006 pProcImpl->m_pid = Ident;
1007 pProcImpl->m_terminated = osl_createCondition();
1009 if (pChild != NULL)
1011 /* process is a child so insert into list */
1012 pProcImpl->m_pnext = pChild->m_pnext;
1013 pChild->m_pnext = pProcImpl;
1015 pProcImpl->m_status = pChild->m_status;
1017 if (osl_checkCondition(pChild->m_terminated))
1018 osl_setCondition(pProcImpl->m_terminated);
1020 else
1021 pProcImpl->m_pnext = NULL;
1023 osl_releaseMutex(ChildListMutex);
1025 else
1026 pProcImpl = NULL;
1028 return (pProcImpl);
1031 /**********************************************
1032 osl_freeProcessHandle
1033 *********************************************/
1035 void SAL_CALL osl_freeProcessHandle(oslProcess Process)
1037 if (Process != NULL)
1039 oslProcessImpl *pChild, *pPrev = NULL;
1041 OSL_ASSERT(ChildListMutex != NULL);
1043 if ( ChildListMutex == 0 )
1045 return;
1048 osl_acquireMutex(ChildListMutex);
1050 pChild = ChildList;
1052 /* remove process from child list */
1053 while (pChild != NULL)
1055 if (pChild == (oslProcessImpl*)Process)
1057 if (pPrev != NULL)
1058 pPrev->m_pnext = pChild->m_pnext;
1059 else
1060 ChildList = pChild->m_pnext;
1062 break;
1065 pPrev = pChild;
1066 pChild = pChild->m_pnext;
1069 osl_releaseMutex(ChildListMutex);
1071 osl_destroyCondition(((oslProcessImpl*)Process)->m_terminated);
1073 free(Process);
1077 #if defined(LINUX)
1078 struct osl_procStat
1080 /* from 'stat' */
1081 pid_t pid; /* pid */
1082 char command[16]; /* 'argv[0]' */ /* mfe: it all right char comm[16] in kernel! */
1083 char state; /* state (running, stopped, ...) */
1084 pid_t ppid; /* parent pid */
1085 pid_t pgrp; /* parent group */
1086 int session; /* session ID */
1087 int tty; /* no of tty */
1088 pid_t tpgid; /* group of process owning the tty */
1089 unsigned long flags; /* flags dunno */
1090 unsigned long minflt; /* minor page faults */
1091 unsigned long cminflt; /* minor page faults with children */
1092 unsigned long majflt; /* major page faults */
1093 unsigned long cmajflt; /* major page faults with children */
1094 unsigned long utime; /* no of jiffies in user mode */
1095 unsigned long stime; /* no of jiffies in kernel mode */
1096 unsigned long cutime; /* no of jiffies in user mode with children */
1097 unsigned long cstime; /* no of jiffies in kernel mode with children */
1098 unsigned long priority; /* nice value + 15 (kernel scheduling prio)*/
1099 long nice; /* nice value */
1100 long timeout; /* no of jiffies of next process timeout */
1101 long itrealvalue; /* no jiffies before next SIGALRM */
1102 unsigned long starttime; /* process started this no of jiffies after boot */
1103 unsigned long vsize; /* virtual memory size (in bytes) */
1104 long rss; /* resident set size (in pages) */
1105 unsigned long rss_rlim; /* rss limit (in bytes) */
1106 unsigned long startcode; /* address above program text can run */
1107 unsigned long endcode; /* address below program text can run */
1108 unsigned long startstack; /* address of start of stack */
1109 unsigned long kstkesp; /* current value of 'esp' (stack pointer) */
1110 unsigned long kstkeip; /* current value of 'eip' (instruction pointer) */
1111 /* mfe: Linux > 2.1.7x have more signals (88) */
1112 /*#ifdef LINUX */
1113 char signal[24]; /* pending signals */
1114 char blocked[24]; /* blocked signals */
1115 char sigignore[24]; /* ignored signals */
1116 char sigcatch[24]; /* catched signals */
1117 /*#else*/
1118 /* long long signal;*/
1119 /* long long blocked;*/
1120 /* long long sigignore;*/
1121 /* long long sigcatch;*/
1122 /*#endif */
1123 unsigned long wchan; /* 'channel' the process is waiting in */
1124 unsigned long nswap; /* ? */
1125 unsigned long cnswap; /* ? */
1127 /* from 'statm' */
1128 long size; /* numbers of pages in memory */
1129 long resident; /* number of resident pages */
1130 long share; /* number of shared pages */
1131 long trs; /* text resident size */
1132 long lrs; /* library resident size */
1133 long drs; /* data resident size */
1134 long dt; /* ditry pages */
1136 /* from 'status' */
1137 int ruid; /* real uid */
1138 int euid; /* effective uid */
1139 int suid; /* saved uid */
1140 int fuid; /* file access uid */
1141 int rgid; /* real gid */
1142 int egid; /* effective gid */
1143 int sgid; /* saved gid */
1144 int fgid; /* file access gid */
1145 unsigned long vm_size; /* like vsize but on kb */
1146 unsigned long vm_lock; /* locked pages in kb */
1147 unsigned long vm_rss; /* like rss but in kb */
1148 unsigned long vm_data; /* data size */
1149 unsigned long vm_stack; /* stack size */
1150 unsigned long vm_exe; /* executable size */
1151 unsigned long vm_lib; /* library size */
1154 /**********************************************
1155 osl_getProcStat
1156 *********************************************/
1158 void osl_getProcStat(pid_t pid, struct osl_procStat* procstat)
1160 int fd = 0;
1161 char name[PATH_MAX + 1];
1162 snprintf(name, sizeof(name), "/proc/%u/stat", pid);
1164 if ((fd = open(name,O_RDONLY)) >=0 )
1166 char* tmp=0;
1167 char prstatbuf[512];
1168 memset(prstatbuf,0,512);
1169 read(fd,prstatbuf,511);
1171 close(fd);
1172 /*printf("%s\n\n",prstatbuf);*/
1175 tmp = strrchr(prstatbuf, ')');
1176 *tmp = '\0';
1177 memset(procstat->command, 0, sizeof(procstat->command));
1179 sscanf(prstatbuf, "%d (%15c", &procstat->pid, procstat->command);
1180 sscanf(tmp + 2,
1181 "%c"
1182 "%i %i %i %i %i"
1183 "%lu %lu %lu %lu %lu"
1184 "%lu %lu %lu %lu"
1185 "%lu %li %li %li"
1186 "%lu %lu %li %lu"
1187 "%lu %lu %lu %lu %lu"
1188 "%s %s %s %s"
1189 "%lu %lu %lu",
1190 &procstat->state,
1191 &procstat->ppid, &procstat->pgrp, &procstat->session, &procstat->tty, &procstat->tpgid,
1192 &procstat->flags, &procstat->minflt, &procstat->cminflt, &procstat->majflt, &procstat->cmajflt,
1193 &procstat->utime, &procstat->stime, &procstat->cutime, &procstat->cstime,
1194 &procstat->priority, &procstat->nice, &procstat->timeout, &procstat->itrealvalue,
1195 &procstat->starttime, &procstat->vsize, &procstat->rss, &procstat->rss_rlim,
1196 &procstat->startcode, &procstat->endcode, &procstat->startstack, &procstat->kstkesp, &procstat->kstkeip,
1197 procstat->signal, procstat->blocked, procstat->sigignore, procstat->sigcatch,
1198 &procstat->wchan, &procstat->nswap, &procstat->cnswap
1203 /**********************************************
1204 osl_getProcStatm
1205 *********************************************/
1207 void osl_getProcStatm(pid_t pid, struct osl_procStat* procstat)
1209 int fd = 0;
1210 char name[PATH_MAX + 1];
1211 snprintf(name, sizeof(name), "/proc/%u/statm", pid);
1213 if ((fd = open(name,O_RDONLY)) >=0 )
1215 char prstatmbuf[512];
1216 memset(prstatmbuf,0,512);
1217 read(fd,prstatmbuf,511);
1219 close(fd);
1221 /* printf("\n\n%s\n\n",prstatmbuf);*/
1223 sscanf(prstatmbuf,"%li %li %li %li %li %li %li",
1224 &procstat->size, &procstat->resident, &procstat->share,
1225 &procstat->trs, &procstat->lrs, &procstat->drs,
1226 &procstat->dt
1231 /**********************************************
1232 osl_getProcStatus
1233 *********************************************/
1235 void osl_getProcStatus(pid_t pid, struct osl_procStat* procstat)
1237 int fd = 0;
1238 char name[PATH_MAX + 1];
1239 snprintf(name, sizeof(name), "/proc/%u/status", pid);
1241 if ((fd = open(name,O_RDONLY)) >=0 )
1243 char* tmp=0;
1244 char prstatusbuf[512];
1245 memset(prstatusbuf,0,512);
1246 read(fd,prstatusbuf,511);
1248 close(fd);
1250 /* printf("\n\n%s\n\n",prstatusbuf);*/
1252 tmp = strstr(prstatusbuf,"Uid:");
1253 if(tmp)
1255 sscanf(tmp,"Uid:\t%d\t%d\t%d\t%d",
1256 &procstat->ruid, &procstat->euid, &procstat->suid, &procstat->fuid
1261 tmp = strstr(prstatusbuf,"Gid:");
1262 if(tmp)
1264 sscanf(tmp,"Gid:\t%d\t%d\t%d\t%d",
1265 &procstat->rgid, &procstat->egid, &procstat->sgid, &procstat->fgid
1269 tmp = strstr(prstatusbuf,"VmSize:");
1270 if(tmp)
1272 sscanf(tmp,
1273 "VmSize: %lu kB\n"
1274 "VmLck: %lu kB\n"
1275 "VmRSS: %lu kB\n"
1276 "VmData: %lu kB\n"
1277 "VmStk: %lu kB\n"
1278 "VmExe: %lu kB\n"
1279 "VmLib: %lu kB\n",
1280 &procstat->vm_size, &procstat->vm_lock, &procstat->vm_rss, &procstat->vm_data,
1281 &procstat->vm_stack, &procstat->vm_exe, &procstat->vm_lib
1285 tmp = strstr(prstatusbuf,"SigPnd:");
1286 if(tmp)
1288 sscanf(tmp, "SigPnd: %s SigBlk: %s SigIgn: %s %*s %s",
1289 procstat->signal, procstat->blocked, procstat->sigignore, procstat->sigcatch
1295 #endif
1297 /**********************************************
1298 osl_getProcessInfo
1299 *********************************************/
1301 oslProcessError SAL_CALL osl_getProcessInfo(oslProcess Process, oslProcessData Fields, oslProcessInfo* pInfo)
1303 pid_t pid;
1305 if (Process == NULL)
1306 pid = getpid();
1307 else
1308 pid = ((oslProcessImpl*)Process)->m_pid;
1310 if (! pInfo || (pInfo->Size != sizeof(oslProcessInfo)))
1311 return osl_Process_E_Unknown;
1313 pInfo->Fields = 0;
1315 if (Fields & osl_Process_IDENTIFIER)
1317 pInfo->Ident = pid;
1318 pInfo->Fields |= osl_Process_IDENTIFIER;
1321 if (Fields & osl_Process_EXITCODE)
1323 if ((Process != NULL) &&
1324 osl_checkCondition(((oslProcessImpl*)Process)->m_terminated))
1326 pInfo->Code = ((oslProcessImpl*)Process)->m_status;
1327 pInfo->Fields |= osl_Process_EXITCODE;
1331 if (Fields & (osl_Process_HEAPUSAGE | osl_Process_CPUTIMES))
1334 #if defined(SOLARIS)
1336 int fd;
1337 sal_Char name[PATH_MAX + 1];
1339 snprintf(name, sizeof(name), "/proc/%u", pid);
1341 if ((fd = open(name, O_RDONLY)) >= 0)
1343 prstatus_t prstatus;
1345 if (ioctl(fd, PIOCSTATUS, &prstatus) >= 0)
1347 if (Fields & osl_Process_CPUTIMES)
1349 pInfo->UserTime.Seconds = prstatus.pr_utime.tv_sec;
1350 pInfo->UserTime.Nanosec = prstatus.pr_utime.tv_nsec;
1351 pInfo->SystemTime.Seconds = prstatus.pr_stime.tv_sec;
1352 pInfo->SystemTime.Nanosec = prstatus.pr_stime.tv_nsec;
1354 pInfo->Fields |= osl_Process_CPUTIMES;
1357 if (Fields & osl_Process_HEAPUSAGE)
1359 pInfo->HeapUsage = prstatus.pr_brksize;
1361 pInfo->Fields |= osl_Process_HEAPUSAGE;
1364 close(fd);
1366 return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown;
1368 else
1369 close(fd);
1372 #elif defined(HPUX)
1374 struct pst_status prstatus;
1376 if (pstat_getproc(&prstatus, sizeof(prstatus), (size_t)0, pid) == 1)
1378 if (Fields & osl_Process_CPUTIMES)
1380 pInfo->UserTime.Seconds = prstatus.pst_utime;
1381 pInfo->UserTime.Nanosec = 500000L;
1382 pInfo->SystemTime.Seconds = prstatus.pst_stime;
1383 pInfo->SystemTime.Nanosec = 500000L;
1385 pInfo->Fields |= osl_Process_CPUTIMES;
1388 if (Fields & osl_Process_HEAPUSAGE)
1390 pInfo->HeapUsage = prstatus.pst_vdsize*PAGESIZE;
1392 pInfo->Fields |= osl_Process_HEAPUSAGE;
1395 return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown;
1398 #elif defined(IRIX)
1400 int fd;
1401 sal_Char name[PATH_MAX + 1];
1403 snprintf(name, sizeof(name), "/proc/%u", pid);
1405 if ((fd = open(name, O_RDONLY)) >= 0)
1407 prstatus_t prstatus;
1408 prpsinfo_t prpsinfo;
1410 if (ioctl(fd, PIOCSTATUS, &prstatus) >= 0 &&
1411 ioctl(fd, PIOCPSINFO, &prpsinfo) >= 0)
1413 if (Fields & osl_Process_CPUTIMES)
1415 pInfo->UserTime.Seconds = prstatus.pr_utime.tv_sec;
1416 pInfo->UserTime.Nanosec = prstatus.pr_utime.tv_nsec;
1417 pInfo->SystemTime.Seconds = prstatus.pr_stime.tv_sec;
1418 pInfo->SystemTime.Nanosec = prstatus.pr_stime.tv_nsec;
1420 pInfo->Fields |= osl_Process_CPUTIMES;
1423 if (Fields & osl_Process_HEAPUSAGE)
1425 int pagesize = getpagesize();
1427 pInfo->HeapUsage = prpsinfo.pr_size*pagesize;
1429 pInfo->Fields |= osl_Process_HEAPUSAGE;
1432 close(fd);
1434 return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown;
1436 else
1437 close(fd);
1440 #elif defined(LINUX)
1442 /* int fd = 0;*/
1443 struct osl_procStat procstat;
1444 memset(&procstat,0,sizeof(procstat));
1446 osl_getProcStat(pid, &procstat);
1447 osl_getProcStatm(pid, &procstat);
1448 osl_getProcStatus(pid, &procstat);
1450 if ( Fields & osl_Process_CPUTIMES)
1453 * mfe:
1454 * We calculate only time of the process proper.
1455 * Threads are processes, we do not consider their time here!
1456 * (For this, cutime and cstime should be used, it seems not
1457 * to work in 2.0.36)
1460 long clktck;
1461 unsigned long hz;
1462 unsigned long userseconds;
1463 unsigned long systemseconds;
1465 clktck = sysconf(_SC_CLK_TCK);
1466 if (clktck < 0) {
1467 return osl_Process_E_Unknown;
1469 hz = (unsigned long) clktck;
1471 userseconds = procstat.utime/hz;
1472 systemseconds = procstat.stime/hz;
1474 pInfo->UserTime.Seconds = userseconds;
1475 pInfo->UserTime.Nanosec = procstat.utime - (userseconds * hz);
1476 pInfo->SystemTime.Seconds = systemseconds;
1477 pInfo->SystemTime.Nanosec = procstat.stime - (systemseconds * hz);
1479 pInfo->Fields |= osl_Process_CPUTIMES;
1482 if (Fields & osl_Process_HEAPUSAGE)
1485 * mfe:
1486 * vm_data (found in status) shows the size of the data segment
1487 * it a rough approximation of the core heap size
1489 pInfo->HeapUsage = procstat.vm_data*1024;
1491 pInfo->Fields |= osl_Process_HEAPUSAGE;
1494 return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown;
1495 #endif
1499 return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown;
1503 /***********************************************
1504 helper function for osl_joinProcessWithTimeout
1505 **********************************************/
1507 static int is_timeout(const struct timeval* tend)
1509 struct timeval tcurrent;
1510 gettimeofday(&tcurrent, NULL);
1511 return (tcurrent.tv_sec >= tend->tv_sec);
1514 /**********************************************
1515 kill(pid, 0) is usefull for checking if a
1516 process is still alive, but remember that
1517 kill even returns 0 if the process is already
1518 a zombie.
1519 *********************************************/
1521 static int is_process_dead(pid_t pid)
1523 return ((-1 == kill(pid, 0)) && (ESRCH == errno));
1526 /**********************************************
1527 osl_joinProcessWithTimeout
1528 *********************************************/
1530 oslProcessError SAL_CALL osl_joinProcessWithTimeout(oslProcess Process, const TimeValue* pTimeout)
1532 oslProcessImpl* pChild = ChildList;
1533 oslProcessError osl_error = osl_Process_E_None;
1535 OSL_PRECOND(Process, "osl_joinProcess: Invalid parameter");
1536 OSL_ASSERT(ChildListMutex);
1538 if (NULL == Process || 0 == ChildListMutex)
1539 return osl_Process_E_Unknown;
1541 osl_acquireMutex(ChildListMutex);
1543 /* check if process is a child of ours */
1544 while (pChild != NULL)
1546 if (pChild == (oslProcessImpl*)Process)
1547 break;
1549 pChild = pChild->m_pnext;
1552 osl_releaseMutex(ChildListMutex);
1554 if (pChild != NULL)
1556 oslConditionResult cond_res = osl_waitCondition(pChild->m_terminated, pTimeout);
1558 if (osl_cond_result_timeout == cond_res)
1559 osl_error = osl_Process_E_TimedOut;
1560 else if (osl_cond_result_ok != cond_res)
1561 osl_error = osl_Process_E_Unknown;
1563 else /* alien process; StatusThread will not be able
1564 to set the condition terminated */
1566 pid_t pid = ((oslProcessImpl*)Process)->m_pid;
1568 if (pTimeout)
1570 int timeout = 0;
1571 struct timeval tend;
1573 gettimeofday(&tend, NULL);
1575 tend.tv_sec += pTimeout->Seconds;
1577 while (!is_process_dead(pid) && ((timeout = is_timeout(&tend)) == 0))
1578 sleep(1);
1580 if (timeout)
1581 osl_error = osl_Process_E_TimedOut;
1583 else /* infinite */
1585 while (!is_process_dead(pid))
1586 sleep(1);
1589 return osl_error;
1592 /**********************************************
1593 osl_joinProcess
1594 *********************************************/
1596 oslProcessError SAL_CALL osl_joinProcess(oslProcess Process)
1598 return osl_joinProcessWithTimeout(Process, NULL);