1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: process.c,v $
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 ************************************************************************/
34 * - cleanup of process status things
35 * - cleanup of process spawning
36 * - cleanup of resource transfer
40 // The procfs may only be used without LFS in 32bits.
41 # ifdef _FILE_OFFSET_BITS
42 # undef _FILE_OFFSET_BITS
48 #include <machine/param.h>
52 #if defined(SOLARIS) || defined(IRIX)
53 # include <sys/procfs.h>
55 #include <osl/diagnose.h>
56 #include <osl/mutex.h>
58 #ifndef _OSL_CONDITN_H_
59 #include <osl/conditn.h>
61 #include <osl/thread.h>
63 #include <osl/signal.h>
64 #include <rtl/alloc.h>
76 #if defined(MACOSX) || defined(IORESOURCE_TRANSFER_BSD)
77 #define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(int))
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 ******************************************************************************/
93 sal_Char m_Name
[PATH_MAX
+ 1];
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];
104 oslCondition m_started
;
105 oslProcessImpl
* m_pProcImpl
;
106 oslFileHandle
*m_pInputWrite
;
107 oslFileHandle
*m_pOutputRead
;
108 oslFileHandle
*m_pErrorRead
;
111 typedef struct _oslPipeImpl
{
113 sal_Char m_Name
[PATH_MAX
+ 1];
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
,
143 sal_Bool
osl_getFullPath(const sal_Char
* pszFilename
, sal_Char
* pszPath
, sal_uInt32 MaxLen
);
145 static oslProcessImpl
* ChildList
;
146 static oslMutex ChildListMutex
;
148 /******************************************************************************
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];
163 OSL_ASSERT(pszName
!= NULL
);
167 return osl_Process_E_NotFound
;
173 if (Separator
== '\0')
177 if ( (pchr
= getenv(pszPath
)) != 0 )
181 while (*pchr
!= '\0')
185 while ((*pchr
!= '\0') && (*pchr
!= Separator
))
188 if ((pstr
> path
) && ((*(pstr
- 1) != '/')))
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
)
212 return osl_Process_E_NotFound
;
215 /******************************************************************************
217 * New io resource transfer functions
219 *****************************************************************************/
222 /**********************************************
224 *********************************************/
226 static sal_Bool
sendFdPipe(int PipeFD
, int SocketFD
)
228 sal_Bool bRet
= sal_False
;
232 char buf
[2]; /* send_fd()/recv_fd() 2-byte protocol */
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
);
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() */
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
);
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
;
276 if ( ( nSend
= sendmsg(PipeFD
, &msg
, 0) ) > 0 )
279 OSL_TRACE("sendFdPipe : send '%i' bytes\n",nSend
);
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");
295 OSL_TRACE("sendFdPipe : resource wasn't received\n");
298 #if defined(IOCHANNEL_TRANSFER_BSD_RENO)
305 /**********************************************
307 *********************************************/
309 static oslSocket
receiveFdPipe(int PipeFD
)
311 oslSocket pSocket
= 0;
312 struct msghdr msghdr
;
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 */
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
;
351 #if defined(IOCHANNEL_TRANSFER_BSD)
353 if ( ( nRead
= recvmsg(PipeFD
, &msghdr
, 0) ) > 0 )
355 OSL_TRACE("receiveFdPipe : received '%i' bytes\n",nRead
);
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
);
368 OSL_TRACE("receiveFdPipe : receiving failed (%s)",strerror(errno
));
373 pSocket
= __osl_createSocketImpl(newfd
);
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)
388 /**********************************************
390 *********************************************/
392 sal_Bool
osl_sendResourcePipe(oslPipe pPipe
, oslSocket pSocket
)
394 sal_Bool bRet
= sal_False
;
396 if ( pSocket
== 0 || pPipe
== 0 )
401 bRet
= sendFdPipe(pPipe
->m_Socket
,pSocket
->m_Socket
);
406 /**********************************************
407 osl_receiveResourcePipe
408 *********************************************/
410 oslSocket
osl_receiveResourcePipe(oslPipe pPipe
)
419 pSocket
= receiveFdPipe(pPipe
->m_Socket
);
421 return (oslSocket
) pSocket
;
426 /******************************************************************************
428 * Functions for starting a process
430 *****************************************************************************/
432 static void ChildStatusProc(void *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
)
460 if ( data
.m_pOutputRead
)
463 if ( data
.m_pErrorRead
)
466 if ((pid
= fork()) == 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)
484 if ((data
.m_uid
== (uid_t
)-1) || ((data
.m_uid
== getuid()) && (data
.m_gid
== getgid())))
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();
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
));
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))
566 if ((pid
> 0) && (i
== 0))
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
);
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 */
609 oslProcessImpl
* pChild
;
611 osl_acquireMutex(ChildListMutex
);
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
);
623 pChild
->m_status
= -1;
625 osl_setCondition(pChild
->m_terminated
);
628 pChild
= pChild
->m_pnext
;
631 osl_releaseMutex(ChildListMutex
);
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
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;
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
);
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
,
766 if ( pArguments
!= 0 )
768 for ( idx
= 0 ; idx
< nArguments
; ++idx
)
770 if ( pArguments
[idx
] != 0 )
772 free(pArguments
[idx
]);
778 if ( pEnvironment
!= 0 )
780 for ( idx
= 0 ; idx
< nEnvironmentVars
; ++idx
)
782 if ( pEnvironment
[idx
] != 0 )
784 free(pEnvironment
[idx
]);
793 /**********************************************
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
,
809 return osl_executeProcess_WithRedirectedIO(
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
842 sal_Char path
[PATH_MAX
+ 1];
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
))
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
;
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
;
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 /**********************************************
952 *********************************************/
954 oslProcessError SAL_CALL
osl_terminateProcess(oslProcess Process
)
957 return osl_Process_E_Unknown
;
959 if (kill(((oslProcessImpl
*)Process
)->m_pid
, SIGKILL
) != 0)
964 return osl_Process_E_NoPermission
;
967 return osl_Process_E_NotFound
;
970 return osl_Process_E_Unknown
;
974 return osl_Process_E_None
;
977 /**********************************************
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
);
996 /* check if it is one of our child processes */
997 while (pChild
!= NULL
)
999 if (Ident
== (sal_uInt32
) pChild
->m_pid
)
1002 pChild
= pChild
->m_pnext
;
1005 pProcImpl
= (oslProcessImpl
*) malloc(sizeof(oslProcessImpl
));
1006 pProcImpl
->m_pid
= Ident
;
1007 pProcImpl
->m_terminated
= osl_createCondition();
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
);
1021 pProcImpl
->m_pnext
= NULL
;
1023 osl_releaseMutex(ChildListMutex
);
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 )
1048 osl_acquireMutex(ChildListMutex
);
1052 /* remove process from child list */
1053 while (pChild
!= NULL
)
1055 if (pChild
== (oslProcessImpl
*)Process
)
1058 pPrev
->m_pnext
= pChild
->m_pnext
;
1060 ChildList
= pChild
->m_pnext
;
1066 pChild
= pChild
->m_pnext
;
1069 osl_releaseMutex(ChildListMutex
);
1071 osl_destroyCondition(((oslProcessImpl
*)Process
)->m_terminated
);
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) */
1113 char signal
[24]; /* pending signals */
1114 char blocked
[24]; /* blocked signals */
1115 char sigignore
[24]; /* ignored signals */
1116 char sigcatch
[24]; /* catched signals */
1118 /* long long signal;*/
1119 /* long long blocked;*/
1120 /* long long sigignore;*/
1121 /* long long sigcatch;*/
1123 unsigned long wchan
; /* 'channel' the process is waiting in */
1124 unsigned long nswap
; /* ? */
1125 unsigned long cnswap
; /* ? */
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 */
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 /**********************************************
1156 *********************************************/
1158 void osl_getProcStat(pid_t pid
, struct osl_procStat
* procstat
)
1161 char name
[PATH_MAX
+ 1];
1162 snprintf(name
, sizeof(name
), "/proc/%u/stat", pid
);
1164 if ((fd
= open(name
,O_RDONLY
)) >=0 )
1167 char prstatbuf
[512];
1168 memset(prstatbuf
,0,512);
1169 read(fd
,prstatbuf
,511);
1172 /*printf("%s\n\n",prstatbuf);*/
1175 tmp
= strrchr(prstatbuf
, ')');
1177 memset(procstat
->command
, 0, sizeof(procstat
->command
));
1179 sscanf(prstatbuf
, "%d (%15c", &procstat
->pid
, procstat
->command
);
1183 "%lu %lu %lu %lu %lu"
1187 "%lu %lu %lu %lu %lu"
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 /**********************************************
1205 *********************************************/
1207 void osl_getProcStatm(pid_t pid
, struct osl_procStat
* procstat
)
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);
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
,
1231 /**********************************************
1233 *********************************************/
1235 void osl_getProcStatus(pid_t pid
, struct osl_procStat
* procstat
)
1238 char name
[PATH_MAX
+ 1];
1239 snprintf(name
, sizeof(name
), "/proc/%u/status", pid
);
1241 if ((fd
= open(name
,O_RDONLY
)) >=0 )
1244 char prstatusbuf
[512];
1245 memset(prstatusbuf
,0,512);
1246 read(fd
,prstatusbuf
,511);
1250 /* printf("\n\n%s\n\n",prstatusbuf);*/
1252 tmp
= strstr(prstatusbuf
,"Uid:");
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:");
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:");
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:");
1288 sscanf(tmp
, "SigPnd: %s SigBlk: %s SigIgn: %s %*s %s",
1289 procstat
->signal
, procstat
->blocked
, procstat
->sigignore
, procstat
->sigcatch
1297 /**********************************************
1299 *********************************************/
1301 oslProcessError SAL_CALL
osl_getProcessInfo(oslProcess Process
, oslProcessData Fields
, oslProcessInfo
* pInfo
)
1305 if (Process
== NULL
)
1308 pid
= ((oslProcessImpl
*)Process
)->m_pid
;
1310 if (! pInfo
|| (pInfo
->Size
!= sizeof(oslProcessInfo
)))
1311 return osl_Process_E_Unknown
;
1315 if (Fields
& osl_Process_IDENTIFIER
)
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)
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
;
1366 return (pInfo
->Fields
== Fields
) ? osl_Process_E_None
: osl_Process_E_Unknown
;
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
;
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
;
1434 return (pInfo
->Fields
== Fields
) ? osl_Process_E_None
: osl_Process_E_Unknown
;
1440 #elif defined(LINUX)
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
)
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)
1462 unsigned long userseconds
;
1463 unsigned long systemseconds
;
1465 clktck
= sysconf(_SC_CLK_TCK
);
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
)
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
;
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
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
)
1549 pChild
= pChild
->m_pnext
;
1552 osl_releaseMutex(ChildListMutex
);
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
;
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))
1581 osl_error
= osl_Process_E_TimedOut
;
1585 while (!is_process_dead(pid
))
1592 /**********************************************
1594 *********************************************/
1596 oslProcessError SAL_CALL
osl_joinProcess(oslProcess Process
)
1598 return osl_joinProcessWithTimeout(Process
, NULL
);