1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
31 * - cleanup of process status things
32 * - cleanup of process spawning
33 * - cleanup of resource transfer
37 // The procfs may only be used without LFS in 32bits.
38 # ifdef _FILE_OFFSET_BITS
39 # undef _FILE_OFFSET_BITS
45 #include <machine/param.h>
50 # include <sys/procfs.h>
52 #include <osl/diagnose.h>
53 #include <osl/mutex.h>
55 #ifndef _OSL_CONDITN_H_
56 #include <osl/conditn.h>
58 #include <osl/thread.h>
60 #include <osl/signal.h>
61 #include <rtl/alloc.h>
73 #if defined(MACOSX) || defined(IORESOURCE_TRANSFER_BSD)
74 #define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(int))
77 /* implemented in file.c */
78 extern oslFileError
FileURLToPath( char *, size_t, rtl_uString
* );
79 extern oslFileHandle
osl_createFileHandleFromFD( int fd
);
81 /******************************************************************************
83 * Data Type Definition
85 ******************************************************************************/
90 sal_Char m_Name
[PATH_MAX
+ 1];
94 const sal_Char
* m_pszArgs
[MAX_ARGS
+ 1];
95 oslProcessOption m_options
;
96 const sal_Char
* m_pszDir
;
97 sal_Char
* m_pszEnv
[MAX_ENVS
+ 1];
101 oslCondition m_started
;
102 oslProcessImpl
* m_pProcImpl
;
103 oslFileHandle
*m_pInputWrite
;
104 oslFileHandle
*m_pOutputRead
;
105 oslFileHandle
*m_pErrorRead
;
108 typedef struct _oslPipeImpl
{
110 sal_Char m_Name
[PATH_MAX
+ 1];
114 /******************************************************************************
116 * Function Declarations
118 *****************************************************************************/
120 oslProcessError SAL_CALL
osl_psz_executeProcess(sal_Char
*pszImageName
,
121 sal_Char
*pszArguments
[],
122 oslProcessOption Options
,
123 oslSecurity Security
,
124 sal_Char
*pszDirectory
,
125 sal_Char
*pszEnvironments
[],
126 oslProcess
*pProcess
,
127 oslFileHandle
*pInputWrite
,
128 oslFileHandle
*pOutputRead
,
129 oslFileHandle
*pErrorRead
);
132 oslProcessError SAL_CALL
osl_searchPath_impl(
133 const sal_Char
* pszName
,
134 const sal_Char
* pszPath
,
140 sal_Bool
osl_getFullPath(const sal_Char
* pszFilename
, sal_Char
* pszPath
, sal_uInt32 MaxLen
);
142 static oslProcessImpl
* ChildList
;
143 static oslMutex ChildListMutex
;
145 /******************************************************************************
147 Old and buggy implementation of osl_searchPath used only by
148 osl_psz_executeProcess.
149 A new implemenation is in file_path_helper.cxx
150 *****************************************************************************/
152 oslProcessError SAL_CALL
osl_searchPath_impl(const sal_Char
* pszName
, const sal_Char
* pszPath
,
153 sal_Char Separator
, sal_Char
*pszBuffer
, sal_uInt32 Max
)
155 sal_Char path
[PATH_MAX
+ 1];
160 OSL_ASSERT(pszName
!= NULL
);
164 return osl_Process_E_NotFound
;
170 if (Separator
== '\0')
174 if ( (pchr
= getenv(pszPath
)) != 0 )
178 while (*pchr
!= '\0')
182 while ((*pchr
!= '\0') && (*pchr
!= Separator
))
185 if ((pstr
> path
) && ((*(pstr
- 1) != '/')))
190 strcat(path
, pszName
);
192 if (access(path
, 0) == 0)
194 char szRealPathBuf
[PATH_MAX
] = "";
196 if( NULL
== realpath(path
, szRealPathBuf
) || (strlen(szRealPathBuf
) >= (sal_uInt32
)Max
))
197 return osl_Process_E_Unknown
;
199 strcpy(pszBuffer
, path
);
201 return osl_Process_E_None
;
204 if (*pchr
== Separator
)
209 return osl_Process_E_NotFound
;
212 /******************************************************************************
214 * New io resource transfer functions
216 *****************************************************************************/
219 /**********************************************
221 *********************************************/
223 static sal_Bool
sendFdPipe(int PipeFD
, int SocketFD
)
225 sal_Bool bRet
= sal_False
;
229 char buf
[2]; /* send_fd()/recv_fd() 2-byte protocol */
233 #if defined(IOCHANNEL_TRANSFER_BSD)
235 OSL_TRACE("IOCHANNEL_TRANSFER_BSD send");
236 /* OSL_TRACE("sending fd %i\n",SocketFD); */
238 iov
[0].iov_base
= buf
;
239 iov
[0].iov_len
= sizeof(buf
);
245 msg
.msg_accrights
= (caddr_t
) &SocketFD
; /* addr of descriptor */
246 msg
.msg_accrightslen
= sizeof(int); /* pass 1 descriptor */
247 buf
[1] = 0; /* zero status means OK */
248 buf
[0] = 0; /* null byte flag to recv_fd() */
252 struct cmsghdr
* cmptr
= (struct cmsghdr
*)malloc(CONTROLLEN
);
254 OSL_TRACE("!!!!!! IOCHANNEL_TRANSFER_BSD_RENO send");
255 /* OSL_TRACE("sending fd %i\n",SocketFD); */
257 iov
[0].iov_base
= buf
;
258 iov
[0].iov_len
= sizeof(buf
);
263 msg
.msg_control
= (caddr_t
) cmptr
;
264 msg
.msg_controllen
= CONTROLLEN
;
266 cmptr
->cmsg_level
= SOL_SOCKET
;
267 cmptr
->cmsg_type
= SCM_RIGHTS
;
268 cmptr
->cmsg_len
= CONTROLLEN
;
269 memcpy(CMSG_DATA(cmptr
), &SocketFD
, sizeof(int));
273 if ( ( nSend
= sendmsg(PipeFD
, &msg
, 0) ) > 0 )
276 OSL_TRACE("sendFdPipe : send '%i' bytes\n",nSend
);
281 OSL_TRACE("sendFdPipe : sending failed (%s)",strerror(errno
));
284 nSend
=read(PipeFD
,&RetCode
,sizeof(RetCode
));
286 if ( nSend
> 0 && RetCode
== 1 )
288 OSL_TRACE("sendFdPipe : resource was received\n");
292 OSL_TRACE("sendFdPipe : resource wasn't received\n");
295 #if defined(IOCHANNEL_TRANSFER_BSD_RENO)
302 /**********************************************
304 *********************************************/
306 static oslSocket
receiveFdPipe(int PipeFD
)
308 oslSocket pSocket
= 0;
309 struct msghdr msghdr
;
317 #if defined(IOCHANNEL_TRANSFER_BSD)
319 OSL_TRACE("IOCHANNEL_TRANSFER_BSD receive\n");
321 iov
[0].iov_base
= buffer
;
322 iov
[0].iov_len
= sizeof(buffer
);
323 msghdr
.msg_name
= NULL
;
324 msghdr
.msg_namelen
= 0;
325 msghdr
.msg_iov
= iov
;
326 msghdr
.msg_iovlen
= 1;
327 msghdr
.msg_accrights
= (caddr_t
) &newfd
; /* addr of descriptor */
328 msghdr
.msg_accrightslen
= sizeof(int); /* receive 1 descriptor */
331 struct cmsghdr
* cmptr
= (struct cmsghdr
*)malloc(CONTROLLEN
);
333 OSL_TRACE(" !!!! IOCHANNEL_TRANSFER_BSD_RENO receive");
335 iov
[0].iov_base
= buffer
;
336 iov
[0].iov_len
= sizeof(buffer
);
337 msghdr
.msg_name
= NULL
;
338 msghdr
.msg_namelen
= 0;
339 msghdr
.msg_iov
= iov
;
340 msghdr
.msg_iovlen
= 1;
342 msghdr
.msg_control
= (caddr_t
) cmptr
;
343 msghdr
.msg_controllen
= CONTROLLEN
;
348 #if defined(IOCHANNEL_TRANSFER_BSD)
350 if ( ( nRead
= recvmsg(PipeFD
, &msghdr
, 0) ) > 0 )
352 OSL_TRACE("receiveFdPipe : received '%i' bytes\n",nRead
);
356 if ( ( ( nRead
= recvmsg(PipeFD
, &msghdr
, 0) ) > 0 ) &&
357 ( msghdr
.msg_controllen
== CONTROLLEN
) )
359 OSL_TRACE("receiveFdPipe : received '%i' bytes\n",nRead
);
360 memcpy(&newfd
, CMSG_DATA(cmptr
), sizeof(int));
365 OSL_TRACE("receiveFdPipe : receiving failed (%s)",strerror(errno
));
370 pSocket
= __osl_createSocketImpl(newfd
);
372 OSL_TRACE("received fd %i\n",newfd
);
375 OSL_TRACE("receiveFdPipe : writing back %i",nRetCode
);
376 nRead
=write(PipeFD
,&nRetCode
,sizeof(nRetCode
));
378 #if defined(IOCHANNEL_TRANSFER_BSD_RENO)
385 /**********************************************
387 *********************************************/
389 sal_Bool
osl_sendResourcePipe(oslPipe pPipe
, oslSocket pSocket
)
391 sal_Bool bRet
= sal_False
;
393 if ( pSocket
== 0 || pPipe
== 0 )
398 bRet
= sendFdPipe(pPipe
->m_Socket
,pSocket
->m_Socket
);
403 /**********************************************
404 osl_receiveResourcePipe
405 *********************************************/
407 oslSocket
osl_receiveResourcePipe(oslPipe pPipe
)
416 pSocket
= receiveFdPipe(pPipe
->m_Socket
);
418 return (oslSocket
) pSocket
;
423 /******************************************************************************
425 * Functions for starting a process
427 *****************************************************************************/
429 static void ChildStatusProc(void *pData
)
436 int stdOutput
[2] = { -1, -1 }, stdInput
[2] = { -1, -1 }, stdError
[2] = { -1, -1 };
438 pdata
= (ProcessData
*)pData
;
440 /* make a copy of our data, because forking will only copy
441 our local stack of the thread, so the process data will not be accessible
442 in our child process */
443 memcpy(&data
, pData
, sizeof(data
));
445 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, channel
) == -1)
448 fcntl(channel
[0], F_SETFD
, FD_CLOEXEC
);
449 fcntl(channel
[1], F_SETFD
, FD_CLOEXEC
);
451 /* Create redirected IO pipes */
452 if ( status
== 0 && data
.m_pInputWrite
)
453 if (pipe( stdInput
) == -1)
456 if ( status
== 0 && data
.m_pOutputRead
)
457 if (pipe( stdOutput
) == -1)
460 if ( status
== 0 && data
.m_pErrorRead
)
461 if (pipe( stdError
) == -1)
464 if ( (status
== 0) && ((pid
= fork()) == 0) )
470 if (channel
[0] != -1) close(channel
[0]);
472 if ((data
.m_uid
!= (uid_t
)-1) && ((data
.m_uid
!= getuid()) || (data
.m_gid
!= getgid())))
474 OSL_ASSERT(geteuid() == 0); /* must be root */
476 if (! INIT_GROUPS(data
.m_name
, data
.m_gid
) || (setuid(data
.m_uid
) != 0))
477 OSL_TRACE("Failed to change uid and guid, errno=%d (%s)\n", errno
, strerror(errno
));
478 #if defined(LINUX) || defined (FREEBSD)
486 chstatus
= chdir(data
.m_pszDir
);
488 if (chstatus
== 0 && ((data
.m_uid
== (uid_t
)-1) || ((data
.m_uid
== getuid()) && (data
.m_gid
== getgid()))))
491 for (i
= 0; data
.m_pszEnv
[i
] != NULL
; i
++)
493 if (strchr(data
.m_pszEnv
[i
], '=') == NULL
)
495 unsetenv(data
.m_pszEnv
[i
]); /*TODO: check error return*/
499 putenv(data
.m_pszEnv
[i
]); /*TODO: check error return*/
503 OSL_TRACE("ChildStatusProc : starting '%s'",data
.m_pszArgs
[0]);
505 /* Connect std IO to pipe ends */
507 /* Write end of stdInput not used in child process */
508 if (stdInput
[1] != -1) close( stdInput
[1] );
510 /* Read end of stdOutput not used in child process */
511 if (stdOutput
[0] != -1) close( stdOutput
[0] );
513 /* Read end of stdError not used in child process */
514 if (stdError
[0] != -1) close( stdError
[0] );
516 /* Redirect pipe ends to std IO */
518 if ( stdInput
[0] != STDIN_FILENO
)
520 dup2( stdInput
[0], STDIN_FILENO
);
521 if (stdInput
[0] != -1) close( stdInput
[0] );
524 if ( stdOutput
[1] != STDOUT_FILENO
)
526 dup2( stdOutput
[1], STDOUT_FILENO
);
527 if (stdOutput
[1] != -1) close( stdOutput
[1] );
530 if ( stdError
[1] != STDERR_FILENO
)
532 dup2( stdError
[1], STDERR_FILENO
);
533 if (stdError
[1] != -1) close( stdError
[1] );
536 pid
=execv(data
.m_pszArgs
[0], (sal_Char
**)data
.m_pszArgs
);
540 OSL_TRACE("Failed to exec, errno=%d (%s)\n", errno
, strerror(errno
));
542 OSL_TRACE("ChildStatusProc : starting '%s' failed",data
.m_pszArgs
[0]);
544 /* if we reach here, something went wrong */
545 nWrote
= write(channel
[1], &errno
, sizeof(errno
));
546 if (nWrote
!= sizeof(errno
))
547 OSL_TRACE("sendFdPipe : sending failed (%s)",strerror(errno
));
549 if (channel
[1] != -1) close(channel
[1]);
556 if (channel
[1] != -1) close(channel
[1]);
558 /* Close unused pipe ends */
559 if (stdInput
[0] != -1) close( stdInput
[0] );
560 if (stdOutput
[1] != -1) close( stdOutput
[1] );
561 if (stdError
[1] != -1) close( stdError
[1] );
565 while (((i
= read(channel
[0], &status
, sizeof(status
))) < 0))
572 if (channel
[0] != -1) close(channel
[0]);
574 if ((pid
> 0) && (i
== 0))
577 osl_acquireMutex(ChildListMutex
);
579 pdata
->m_pProcImpl
->m_pid
= pid
;
580 pdata
->m_pProcImpl
->m_pnext
= ChildList
;
581 ChildList
= pdata
->m_pProcImpl
;
583 /* Store used pipe ends in data structure */
585 if ( pdata
->m_pInputWrite
)
586 *(pdata
->m_pInputWrite
) = osl_createFileHandleFromFD( stdInput
[1] );
588 if ( pdata
->m_pOutputRead
)
589 *(pdata
->m_pOutputRead
) = osl_createFileHandleFromFD( stdOutput
[0] );
591 if ( pdata
->m_pErrorRead
)
592 *(pdata
->m_pErrorRead
) = osl_createFileHandleFromFD( stdError
[0] );
594 osl_releaseMutex(ChildListMutex
);
596 osl_setCondition(pdata
->m_started
);
600 child_pid
= waitpid(pid
, &status
, 0);
601 } while ( 0 > child_pid
&& EINTR
== errno
);
605 OSL_TRACE("Failed to wait for child process, errno=%d (%s)\n", errno
, strerror(errno
));
608 We got an other error than EINTR. Anyway we have to wake up the
609 waiting thread under any circumstances */
617 oslProcessImpl
* pChild
;
619 osl_acquireMutex(ChildListMutex
);
623 /* check if it is one of our child processes */
624 while (pChild
!= NULL
)
626 if (pChild
->m_pid
== child_pid
)
628 if (WIFEXITED(status
))
629 pChild
->m_status
= WEXITSTATUS(status
);
631 pChild
->m_status
= -1;
633 osl_setCondition(pChild
->m_terminated
);
636 pChild
= pChild
->m_pnext
;
639 osl_releaseMutex(ChildListMutex
);
644 OSL_TRACE("ChildStatusProc : starting '%s' failed",data
.m_pszArgs
[0]);
645 OSL_TRACE("Failed to launch child process, child reports errno=%d (%s)\n", status
, strerror(status
));
647 /* Close pipe ends */
648 if ( pdata
->m_pInputWrite
)
649 *pdata
->m_pInputWrite
= NULL
;
651 if ( pdata
->m_pOutputRead
)
652 *pdata
->m_pOutputRead
= NULL
;
654 if ( pdata
->m_pErrorRead
)
655 *pdata
->m_pErrorRead
= NULL
;
657 if (stdInput
[1] != -1) close( stdInput
[1] );
658 if (stdOutput
[0] != -1) close( stdOutput
[0] );
659 if (stdError
[0] != -1) close( stdError
[0] );
661 //if pid > 0 then a process was created, even if it later failed
662 //e.g. bash searching for a command to execute, and we still
663 //need to clean it up to avoid "defunct" processes
669 child_pid
= waitpid(pid
, &status
, 0);
670 } while ( 0 > child_pid
&& EINTR
== errno
);
673 /* notify (and unblock) parent thread */
674 osl_setCondition(pdata
->m_started
);
679 /**********************************************
680 osl_executeProcess_WithRedirectedIO
681 *********************************************/
683 oslProcessError SAL_CALL
osl_executeProcess_WithRedirectedIO(
684 rtl_uString
*ustrImageName
,
685 rtl_uString
*ustrArguments
[],
686 sal_uInt32 nArguments
,
687 oslProcessOption Options
,
688 oslSecurity Security
,
689 rtl_uString
*ustrWorkDir
,
690 rtl_uString
*ustrEnvironment
[],
691 sal_uInt32 nEnvironmentVars
,
692 oslProcess
*pProcess
,
693 oslFileHandle
*pInputWrite
,
694 oslFileHandle
*pOutputRead
,
695 oslFileHandle
*pErrorRead
699 oslProcessError Error
;
700 sal_Char
* pszWorkDir
=0;
701 sal_Char
** pArguments
=0;
702 sal_Char
** pEnvironment
=0;
705 char szImagePath
[PATH_MAX
] = "";
706 char szWorkDir
[PATH_MAX
] = "";
708 if ( ustrImageName
&& ustrImageName
->length
)
710 FileURLToPath( szImagePath
, PATH_MAX
, ustrImageName
);
713 if ( ustrWorkDir
!= 0 && ustrWorkDir
->length
)
715 FileURLToPath( szWorkDir
, PATH_MAX
, ustrWorkDir
);
716 pszWorkDir
= szWorkDir
;
719 if ( pArguments
== 0 && nArguments
> 0 )
721 pArguments
= (sal_Char
**) malloc( ( nArguments
+ 2 ) * sizeof(sal_Char
*) );
725 for ( idx
= 0 ; idx
< nArguments
; ++idx
)
727 rtl_String
* strArg
=0;
730 rtl_uString2String( &strArg
,
731 rtl_uString_getStr(ustrArguments
[idx
]),
732 rtl_uString_getLength(ustrArguments
[idx
]),
733 osl_getThreadTextEncoding(),
734 OUSTRING_TO_OSTRING_CVTFLAGS
);
736 pArguments
[idx
]=strdup(rtl_string_getStr(strArg
));
737 rtl_string_release(strArg
);
741 for ( idx
= 0 ; idx
< nEnvironmentVars
; ++idx
)
743 rtl_String
* strEnv
=0;
745 if ( pEnvironment
== 0 )
747 pEnvironment
= (sal_Char
**) malloc( ( nEnvironmentVars
+ 2 ) * sizeof(sal_Char
*) );
750 rtl_uString2String( &strEnv
,
751 rtl_uString_getStr(ustrEnvironment
[idx
]),
752 rtl_uString_getLength(ustrEnvironment
[idx
]),
753 osl_getThreadTextEncoding(),
754 OUSTRING_TO_OSTRING_CVTFLAGS
);
756 pEnvironment
[idx
]=strdup(rtl_string_getStr(strEnv
));
757 rtl_string_release(strEnv
);
758 pEnvironment
[idx
+1]=0;
762 Error
= osl_psz_executeProcess(szImagePath
,
774 if ( pArguments
!= 0 )
776 for ( idx
= 0 ; idx
< nArguments
; ++idx
)
778 if ( pArguments
[idx
] != 0 )
780 free(pArguments
[idx
]);
786 if ( pEnvironment
!= 0 )
788 for ( idx
= 0 ; idx
< nEnvironmentVars
; ++idx
)
790 if ( pEnvironment
[idx
] != 0 )
792 free(pEnvironment
[idx
]);
801 /**********************************************
803 *********************************************/
805 oslProcessError SAL_CALL
osl_executeProcess(
806 rtl_uString
*ustrImageName
,
807 rtl_uString
*ustrArguments
[],
808 sal_uInt32 nArguments
,
809 oslProcessOption Options
,
810 oslSecurity Security
,
811 rtl_uString
*ustrWorkDir
,
812 rtl_uString
*ustrEnvironment
[],
813 sal_uInt32 nEnvironmentVars
,
817 return osl_executeProcess_WithRedirectedIO(
833 /**********************************************
834 osl_psz_executeProcess
835 *********************************************/
837 oslProcessError SAL_CALL
osl_psz_executeProcess(sal_Char
*pszImageName
,
838 sal_Char
*pszArguments
[],
839 oslProcessOption Options
,
840 oslSecurity Security
,
841 sal_Char
*pszDirectory
,
842 sal_Char
*pszEnvironments
[],
843 oslProcess
*pProcess
,
844 oslFileHandle
*pInputWrite
,
845 oslFileHandle
*pOutputRead
,
846 oslFileHandle
*pErrorRead
850 sal_Char path
[PATH_MAX
+ 1];
856 memset(&Data
,0,sizeof(ProcessData
));
857 Data
.m_pInputWrite
= pInputWrite
;
858 Data
.m_pOutputRead
= pOutputRead
;
859 Data
.m_pErrorRead
= pErrorRead
;
861 if (pszImageName
== NULL
)
862 pszImageName
= pszArguments
[0];
864 OSL_ASSERT(pszImageName
!= NULL
);
866 if ( pszImageName
== 0 )
868 return osl_Process_E_NotFound
;
871 if ((Options
& osl_Process_SEARCHPATH
) &&
872 (osl_searchPath_impl(pszImageName
, NULL
, '\0', path
, sizeof(path
)) == osl_Process_E_None
))
875 Data
.m_pszArgs
[0] = strdup(pszImageName
);
876 Data
.m_pszArgs
[1] = 0;
878 if ( pszArguments
!= 0 )
880 for (i
= 0; ((i
+ 2) < MAX_ARGS
) && (pszArguments
[i
] != NULL
); i
++)
881 Data
.m_pszArgs
[i
+1] = strdup(pszArguments
[i
]);
882 Data
.m_pszArgs
[i
+2] = NULL
;
885 Data
.m_options
= Options
;
886 Data
.m_pszDir
= (pszDirectory
!= NULL
) ? strdup(pszDirectory
) : NULL
;
888 if (pszEnvironments
!= NULL
)
890 for (i
= 0; ((i
+ 1) < MAX_ENVS
) && (pszEnvironments
[i
] != NULL
); i
++)
891 Data
.m_pszEnv
[i
] = strdup(pszEnvironments
[i
]);
892 Data
.m_pszEnv
[i
+1] = NULL
;
895 Data
.m_pszEnv
[0] = NULL
;
897 if (Security
!= NULL
)
899 Data
.m_uid
= ((oslSecurityImpl
*)Security
)->m_pPasswd
.pw_uid
;
900 Data
.m_gid
= ((oslSecurityImpl
*)Security
)->m_pPasswd
.pw_gid
;
901 Data
.m_name
= ((oslSecurityImpl
*)Security
)->m_pPasswd
.pw_name
;
904 Data
.m_uid
= (uid_t
)-1;
906 Data
.m_pProcImpl
= (oslProcessImpl
*) malloc(sizeof(oslProcessImpl
));
907 Data
.m_pProcImpl
->m_pid
= 0;
908 Data
.m_pProcImpl
->m_terminated
= osl_createCondition();
909 Data
.m_pProcImpl
->m_pnext
= NULL
;
911 if (ChildListMutex
== NULL
)
912 ChildListMutex
= osl_createMutex();
914 Data
.m_started
= osl_createCondition();
916 hThread
= osl_createThread(ChildStatusProc
, &Data
);
918 osl_waitCondition(Data
.m_started
, NULL
);
919 osl_destroyCondition(Data
.m_started
);
921 for (i
= 0; Data
.m_pszArgs
[i
] != NULL
; i
++)
922 free((void *)Data
.m_pszArgs
[i
]);
924 for (i
= 0; Data
.m_pszEnv
[i
] != NULL
; i
++)
925 free((void *)Data
.m_pszEnv
[i
]);
927 if ( Data
.m_pszDir
!= 0 )
929 free((void *)Data
.m_pszDir
);
932 osl_destroyThread(hThread
);
934 if (Data
.m_pProcImpl
->m_pid
!= 0)
936 *pProcess
= Data
.m_pProcImpl
;
938 if (Options
& osl_Process_WAIT
)
939 osl_joinProcess(*pProcess
);
941 return osl_Process_E_None
;
944 osl_destroyCondition(Data
.m_pProcImpl
->m_terminated
);
945 free(Data
.m_pProcImpl
);
947 return osl_Process_E_Unknown
;
951 /******************************************************************************
953 * Functions for processes
955 *****************************************************************************/
958 /**********************************************
960 *********************************************/
962 oslProcessError SAL_CALL
osl_terminateProcess(oslProcess Process
)
965 return osl_Process_E_Unknown
;
967 if (kill(((oslProcessImpl
*)Process
)->m_pid
, SIGKILL
) != 0)
972 return osl_Process_E_NoPermission
;
975 return osl_Process_E_NotFound
;
978 return osl_Process_E_Unknown
;
982 return osl_Process_E_None
;
985 /**********************************************
987 *********************************************/
989 oslProcess SAL_CALL
osl_getProcess(oslProcessIdentifier Ident
)
991 oslProcessImpl
*pProcImpl
;
993 if (kill(Ident
, 0) != -1)
995 oslProcessImpl
* pChild
;
997 if (ChildListMutex
== NULL
)
998 ChildListMutex
= osl_createMutex();
1000 osl_acquireMutex(ChildListMutex
);
1004 /* check if it is one of our child processes */
1005 while (pChild
!= NULL
)
1007 if (Ident
== (sal_uInt32
) pChild
->m_pid
)
1010 pChild
= pChild
->m_pnext
;
1013 pProcImpl
= (oslProcessImpl
*) malloc(sizeof(oslProcessImpl
));
1014 pProcImpl
->m_pid
= Ident
;
1015 pProcImpl
->m_terminated
= osl_createCondition();
1019 /* process is a child so insert into list */
1020 pProcImpl
->m_pnext
= pChild
->m_pnext
;
1021 pChild
->m_pnext
= pProcImpl
;
1023 pProcImpl
->m_status
= pChild
->m_status
;
1025 if (osl_checkCondition(pChild
->m_terminated
))
1026 osl_setCondition(pProcImpl
->m_terminated
);
1029 pProcImpl
->m_pnext
= NULL
;
1031 osl_releaseMutex(ChildListMutex
);
1039 /**********************************************
1040 osl_freeProcessHandle
1041 *********************************************/
1043 void SAL_CALL
osl_freeProcessHandle(oslProcess Process
)
1045 if (Process
!= NULL
)
1047 oslProcessImpl
*pChild
, *pPrev
= NULL
;
1049 OSL_ASSERT(ChildListMutex
!= NULL
);
1051 if ( ChildListMutex
== 0 )
1056 osl_acquireMutex(ChildListMutex
);
1060 /* remove process from child list */
1061 while (pChild
!= NULL
)
1063 if (pChild
== (oslProcessImpl
*)Process
)
1066 pPrev
->m_pnext
= pChild
->m_pnext
;
1068 ChildList
= pChild
->m_pnext
;
1074 pChild
= pChild
->m_pnext
;
1077 osl_releaseMutex(ChildListMutex
);
1079 osl_destroyCondition(((oslProcessImpl
*)Process
)->m_terminated
);
1089 pid_t pid
; /* pid */
1090 char command
[16]; /* 'argv[0]' */ /* mfe: it all right char comm[16] in kernel! */
1091 char state
; /* state (running, stopped, ...) */
1092 pid_t ppid
; /* parent pid */
1093 pid_t pgrp
; /* parent group */
1094 int session
; /* session ID */
1095 int tty
; /* no of tty */
1096 pid_t tpgid
; /* group of process owning the tty */
1097 unsigned long flags
; /* flags dunno */
1098 unsigned long minflt
; /* minor page faults */
1099 unsigned long cminflt
; /* minor page faults with children */
1100 unsigned long majflt
; /* major page faults */
1101 unsigned long cmajflt
; /* major page faults with children */
1102 unsigned long utime
; /* no of jiffies in user mode */
1103 unsigned long stime
; /* no of jiffies in kernel mode */
1104 unsigned long cutime
; /* no of jiffies in user mode with children */
1105 unsigned long cstime
; /* no of jiffies in kernel mode with children */
1106 unsigned long priority
; /* nice value + 15 (kernel scheduling prio)*/
1107 long nice
; /* nice value */
1108 long timeout
; /* no of jiffies of next process timeout */
1109 long itrealvalue
; /* no jiffies before next SIGALRM */
1110 unsigned long starttime
; /* process started this no of jiffies after boot */
1111 unsigned long vsize
; /* virtual memory size (in bytes) */
1112 long rss
; /* resident set size (in pages) */
1113 unsigned long rss_rlim
; /* rss limit (in bytes) */
1114 unsigned long startcode
; /* address above program text can run */
1115 unsigned long endcode
; /* address below program text can run */
1116 unsigned long startstack
; /* address of start of stack */
1117 unsigned long kstkesp
; /* current value of 'esp' (stack pointer) */
1118 unsigned long kstkeip
; /* current value of 'eip' (instruction pointer) */
1119 /* mfe: Linux > 2.1.7x have more signals (88) */
1121 char signal
[24]; /* pending signals */
1122 char blocked
[24]; /* blocked signals */
1123 char sigignore
[24]; /* ignored signals */
1124 char sigcatch
[24]; /* catched signals */
1126 /* long long signal;*/
1127 /* long long blocked;*/
1128 /* long long sigignore;*/
1129 /* long long sigcatch;*/
1131 unsigned long wchan
; /* 'channel' the process is waiting in */
1132 unsigned long nswap
; /* ? */
1133 unsigned long cnswap
; /* ? */
1136 int ruid
; /* real uid */
1137 int euid
; /* effective uid */
1138 int suid
; /* saved uid */
1139 int fuid
; /* file access uid */
1140 int rgid
; /* real gid */
1141 int egid
; /* effective gid */
1142 int sgid
; /* saved gid */
1143 int fgid
; /* file access gid */
1144 unsigned long vm_size
; /* like vsize but on kb */
1145 unsigned long vm_lock
; /* locked pages in kb */
1146 unsigned long vm_rss
; /* like rss but in kb */
1147 unsigned long vm_data
; /* data size */
1148 unsigned long vm_stack
; /* stack size */
1149 unsigned long vm_exe
; /* executable size */
1150 unsigned long vm_lib
; /* library size */
1153 /**********************************************
1155 *********************************************/
1157 sal_Bool
osl_getProcStat(pid_t pid
, struct osl_procStat
* procstat
)
1160 sal_Bool bRet
= sal_False
;
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 bRet
= read(fd
,prstatbuf
,511) == 511;
1172 /*printf("%s\n\n",prstatbuf);*/
1177 tmp
= strrchr(prstatbuf
, ')');
1179 memset(procstat
->command
, 0, sizeof(procstat
->command
));
1181 sscanf(prstatbuf
, "%d (%15c", &procstat
->pid
, procstat
->command
);
1185 "%lu %lu %lu %lu %lu"
1189 "%lu %lu %lu %lu %lu"
1193 &procstat
->ppid
, &procstat
->pgrp
, &procstat
->session
, &procstat
->tty
, &procstat
->tpgid
,
1194 &procstat
->flags
, &procstat
->minflt
, &procstat
->cminflt
, &procstat
->majflt
, &procstat
->cmajflt
,
1195 &procstat
->utime
, &procstat
->stime
, &procstat
->cutime
, &procstat
->cstime
,
1196 &procstat
->priority
, &procstat
->nice
, &procstat
->timeout
, &procstat
->itrealvalue
,
1197 &procstat
->starttime
, &procstat
->vsize
, &procstat
->rss
, &procstat
->rss_rlim
,
1198 &procstat
->startcode
, &procstat
->endcode
, &procstat
->startstack
, &procstat
->kstkesp
, &procstat
->kstkeip
,
1199 procstat
->signal
, procstat
->blocked
, procstat
->sigignore
, procstat
->sigcatch
,
1200 &procstat
->wchan
, &procstat
->nswap
, &procstat
->cnswap
1206 /**********************************************
1208 *********************************************/
1210 sal_Bool
osl_getProcStatus(pid_t pid
, struct osl_procStat
* procstat
)
1213 char name
[PATH_MAX
+ 1];
1214 snprintf(name
, sizeof(name
), "/proc/%u/status", pid
);
1216 sal_Bool bRet
= sal_False
;
1218 if ((fd
= open(name
,O_RDONLY
)) >=0 )
1221 char prstatusbuf
[512];
1222 memset(prstatusbuf
,0,512);
1223 bRet
= read(fd
,prstatusbuf
,511) == 511;
1227 /* printf("\n\n%s\n\n",prstatusbuf);*/
1232 tmp
= strstr(prstatusbuf
,"Uid:");
1235 sscanf(tmp
,"Uid:\t%d\t%d\t%d\t%d",
1236 &procstat
->ruid
, &procstat
->euid
, &procstat
->suid
, &procstat
->fuid
1241 tmp
= strstr(prstatusbuf
,"Gid:");
1244 sscanf(tmp
,"Gid:\t%d\t%d\t%d\t%d",
1245 &procstat
->rgid
, &procstat
->egid
, &procstat
->sgid
, &procstat
->fgid
1249 tmp
= strstr(prstatusbuf
,"VmSize:");
1260 &procstat
->vm_size
, &procstat
->vm_lock
, &procstat
->vm_rss
, &procstat
->vm_data
,
1261 &procstat
->vm_stack
, &procstat
->vm_exe
, &procstat
->vm_lib
1265 tmp
= strstr(prstatusbuf
,"SigPnd:");
1268 sscanf(tmp
, "SigPnd: %s SigBlk: %s SigIgn: %s %*s %s",
1269 procstat
->signal
, procstat
->blocked
, procstat
->sigignore
, procstat
->sigcatch
1278 /**********************************************
1280 *********************************************/
1282 oslProcessError SAL_CALL
osl_getProcessInfo(oslProcess Process
, oslProcessData Fields
, oslProcessInfo
* pInfo
)
1286 if (Process
== NULL
)
1289 pid
= ((oslProcessImpl
*)Process
)->m_pid
;
1291 if (! pInfo
|| (pInfo
->Size
!= sizeof(oslProcessInfo
)))
1292 return osl_Process_E_Unknown
;
1296 if (Fields
& osl_Process_IDENTIFIER
)
1299 pInfo
->Fields
|= osl_Process_IDENTIFIER
;
1302 if (Fields
& osl_Process_EXITCODE
)
1304 if ((Process
!= NULL
) &&
1305 osl_checkCondition(((oslProcessImpl
*)Process
)->m_terminated
))
1307 pInfo
->Code
= ((oslProcessImpl
*)Process
)->m_status
;
1308 pInfo
->Fields
|= osl_Process_EXITCODE
;
1312 if (Fields
& (osl_Process_HEAPUSAGE
| osl_Process_CPUTIMES
))
1315 #if defined(SOLARIS)
1318 sal_Char name
[PATH_MAX
+ 1];
1320 snprintf(name
, sizeof(name
), "/proc/%u", pid
);
1322 if ((fd
= open(name
, O_RDONLY
)) >= 0)
1324 prstatus_t prstatus
;
1326 if (ioctl(fd
, PIOCSTATUS
, &prstatus
) >= 0)
1328 if (Fields
& osl_Process_CPUTIMES
)
1330 pInfo
->UserTime
.Seconds
= prstatus
.pr_utime
.tv_sec
;
1331 pInfo
->UserTime
.Nanosec
= prstatus
.pr_utime
.tv_nsec
;
1332 pInfo
->SystemTime
.Seconds
= prstatus
.pr_stime
.tv_sec
;
1333 pInfo
->SystemTime
.Nanosec
= prstatus
.pr_stime
.tv_nsec
;
1335 pInfo
->Fields
|= osl_Process_CPUTIMES
;
1338 if (Fields
& osl_Process_HEAPUSAGE
)
1340 pInfo
->HeapUsage
= prstatus
.pr_brksize
;
1342 pInfo
->Fields
|= osl_Process_HEAPUSAGE
;
1347 return (pInfo
->Fields
== Fields
) ? osl_Process_E_None
: osl_Process_E_Unknown
;
1355 struct pst_status prstatus
;
1357 if (pstat_getproc(&prstatus
, sizeof(prstatus
), (size_t)0, pid
) == 1)
1359 if (Fields
& osl_Process_CPUTIMES
)
1361 pInfo
->UserTime
.Seconds
= prstatus
.pst_utime
;
1362 pInfo
->UserTime
.Nanosec
= 500000L;
1363 pInfo
->SystemTime
.Seconds
= prstatus
.pst_stime
;
1364 pInfo
->SystemTime
.Nanosec
= 500000L;
1366 pInfo
->Fields
|= osl_Process_CPUTIMES
;
1369 if (Fields
& osl_Process_HEAPUSAGE
)
1371 pInfo
->HeapUsage
= prstatus
.pst_vdsize
*PAGESIZE
;
1373 pInfo
->Fields
|= osl_Process_HEAPUSAGE
;
1376 return (pInfo
->Fields
== Fields
) ? osl_Process_E_None
: osl_Process_E_Unknown
;
1379 #elif defined(LINUX)
1381 if ( (Fields
& osl_Process_CPUTIMES
) || (Fields
& osl_Process_HEAPUSAGE
) )
1383 struct osl_procStat procstat
;
1384 memset(&procstat
,0,sizeof(procstat
));
1386 if ( (Fields
& osl_Process_CPUTIMES
) && osl_getProcStat(pid
, &procstat
) )
1390 * We calculate only time of the process proper.
1391 * Threads are processes, we do not consider their time here!
1392 * (For this, cutime and cstime should be used, it seems not
1393 * to work in 2.0.36)
1398 unsigned long userseconds
;
1399 unsigned long systemseconds
;
1401 clktck
= sysconf(_SC_CLK_TCK
);
1403 return osl_Process_E_Unknown
;
1405 hz
= (unsigned long) clktck
;
1407 userseconds
= procstat
.utime
/hz
;
1408 systemseconds
= procstat
.stime
/hz
;
1410 pInfo
->UserTime
.Seconds
= userseconds
;
1411 pInfo
->UserTime
.Nanosec
= procstat
.utime
- (userseconds
* hz
);
1412 pInfo
->SystemTime
.Seconds
= systemseconds
;
1413 pInfo
->SystemTime
.Nanosec
= procstat
.stime
- (systemseconds
* hz
);
1415 pInfo
->Fields
|= osl_Process_CPUTIMES
;
1418 if ( (Fields
& osl_Process_HEAPUSAGE
) && osl_getProcStatus(pid
, &procstat
) )
1422 * vm_data (found in status) shows the size of the data segment
1423 * it a rough approximation of the core heap size
1425 pInfo
->HeapUsage
= procstat
.vm_data
*1024;
1427 pInfo
->Fields
|= osl_Process_HEAPUSAGE
;
1431 return (pInfo
->Fields
== Fields
) ? osl_Process_E_None
: osl_Process_E_Unknown
;
1436 return (pInfo
->Fields
== Fields
) ? osl_Process_E_None
: osl_Process_E_Unknown
;
1440 /***********************************************
1441 helper function for osl_joinProcessWithTimeout
1442 **********************************************/
1444 static int is_timeout(const struct timeval
* tend
)
1446 struct timeval tcurrent
;
1447 gettimeofday(&tcurrent
, NULL
);
1448 return (tcurrent
.tv_sec
>= tend
->tv_sec
);
1451 /**********************************************
1452 kill(pid, 0) is usefull for checking if a
1453 process is still alive, but remember that
1454 kill even returns 0 if the process is already
1456 *********************************************/
1458 static int is_process_dead(pid_t pid
)
1460 return ((-1 == kill(pid
, 0)) && (ESRCH
== errno
));
1463 /**********************************************
1464 osl_joinProcessWithTimeout
1465 *********************************************/
1467 oslProcessError SAL_CALL
osl_joinProcessWithTimeout(oslProcess Process
, const TimeValue
* pTimeout
)
1469 oslProcessImpl
* pChild
= ChildList
;
1470 oslProcessError osl_error
= osl_Process_E_None
;
1472 OSL_PRECOND(Process
, "osl_joinProcess: Invalid parameter");
1473 OSL_ASSERT(ChildListMutex
);
1475 if (NULL
== Process
|| 0 == ChildListMutex
)
1476 return osl_Process_E_Unknown
;
1478 osl_acquireMutex(ChildListMutex
);
1480 /* check if process is a child of ours */
1481 while (pChild
!= NULL
)
1483 if (pChild
== (oslProcessImpl
*)Process
)
1486 pChild
= pChild
->m_pnext
;
1489 osl_releaseMutex(ChildListMutex
);
1493 oslConditionResult cond_res
= osl_waitCondition(pChild
->m_terminated
, pTimeout
);
1495 if (osl_cond_result_timeout
== cond_res
)
1496 osl_error
= osl_Process_E_TimedOut
;
1497 else if (osl_cond_result_ok
!= cond_res
)
1498 osl_error
= osl_Process_E_Unknown
;
1500 else /* alien process; StatusThread will not be able
1501 to set the condition terminated */
1503 pid_t pid
= ((oslProcessImpl
*)Process
)->m_pid
;
1508 struct timeval tend
;
1510 gettimeofday(&tend
, NULL
);
1512 tend
.tv_sec
+= pTimeout
->Seconds
;
1514 while (!is_process_dead(pid
) && ((timeout
= is_timeout(&tend
)) == 0))
1518 osl_error
= osl_Process_E_TimedOut
;
1522 while (!is_process_dead(pid
))
1529 /**********************************************
1531 *********************************************/
1533 oslProcessError SAL_CALL
osl_joinProcess(oslProcess Process
)
1535 return osl_joinProcessWithTimeout(Process
, NULL
);