merged tag ooo/DEV300_m102
[LibreOffice.git] / sal / osl / unx / process.c
blob300a1446e81a63db97f98e8dcd7944611e9cedda
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 ************************************************************************/
30 * ToDo:
31 * - cleanup of process status things
32 * - cleanup of process spawning
33 * - cleanup of resource transfer
36 #if defined(SOLARIS)
37 // The procfs may only be used without LFS in 32bits.
38 # ifdef _FILE_OFFSET_BITS
39 # undef _FILE_OFFSET_BITS
40 # endif
41 #endif
44 #ifdef FREEBSD
45 #include <machine/param.h>
46 #endif
48 #include "system.h"
49 #if defined(SOLARIS)
50 # include <sys/procfs.h>
51 #endif
52 #include <osl/diagnose.h>
53 #include <osl/mutex.h>
55 #ifndef _OSL_CONDITN_H_
56 #include <osl/conditn.h>
57 #endif
58 #include <osl/thread.h>
59 #include <osl/file.h>
60 #include <osl/signal.h>
61 #include <rtl/alloc.h>
63 #include <grp.h>
65 #include "procimpl.h"
66 #include "sockimpl.h"
67 #include "secimpl.h"
70 #define MAX_ARGS 255
71 #define MAX_ENVS 255
73 #if defined(MACOSX) || defined(IORESOURCE_TRANSFER_BSD)
74 #define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(int))
75 #endif
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 ******************************************************************************/
87 typedef struct {
88 int m_hPipe;
89 int m_hConn;
90 sal_Char m_Name[PATH_MAX + 1];
91 } Pipe;
93 typedef struct {
94 const sal_Char* m_pszArgs[MAX_ARGS + 1];
95 oslProcessOption m_options;
96 const sal_Char* m_pszDir;
97 sal_Char* m_pszEnv[MAX_ENVS + 1];
98 uid_t m_uid;
99 gid_t m_gid;
100 sal_Char* m_name;
101 oslCondition m_started;
102 oslProcessImpl* m_pProcImpl;
103 oslFileHandle *m_pInputWrite;
104 oslFileHandle *m_pOutputRead;
105 oslFileHandle *m_pErrorRead;
106 } ProcessData;
108 typedef struct _oslPipeImpl {
109 int m_Socket;
110 sal_Char m_Name[PATH_MAX + 1];
111 } oslPipeImpl;
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,
135 sal_Char Separator,
136 sal_Char *pszBuffer,
137 sal_uInt32 Max);
140 sal_Bool osl_getFullPath(const sal_Char* pszFilename, sal_Char* pszPath, sal_uInt32 MaxLen);
142 static oslProcessImpl* ChildList;
143 static oslMutex ChildListMutex;
145 /******************************************************************************
146 Deprecated
147 Old and buggy implementation of osl_searchPath used only by
148 osl_psz_executeProcess.
149 A new implemenation is in file_path_helper.cxx
150 *****************************************************************************/
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];
156 sal_Char *pchr;
158 path[0] = '\0';
160 OSL_ASSERT(pszName != NULL);
162 if ( pszName == 0 )
164 return osl_Process_E_NotFound;
167 if (pszPath == NULL)
168 pszPath = "PATH";
170 if (Separator == '\0')
171 Separator = ':';
174 if ( (pchr = getenv(pszPath)) != 0 )
176 sal_Char *pstr;
178 while (*pchr != '\0')
180 pstr = path;
182 while ((*pchr != '\0') && (*pchr != Separator))
183 *pstr++ = *pchr++;
185 if ((pstr > path) && ((*(pstr - 1) != '/')))
186 *pstr++ = '/';
188 *pstr = '\0';
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)
205 pchr++;
209 return osl_Process_E_NotFound;
212 /******************************************************************************
214 * New io resource transfer functions
216 *****************************************************************************/
219 /**********************************************
220 sendFdPipe
221 *********************************************/
223 static sal_Bool sendFdPipe(int PipeFD, int SocketFD)
225 sal_Bool bRet = sal_False;
227 struct iovec iov[1];
228 struct msghdr msg;
229 char buf[2]; /* send_fd()/recv_fd() 2-byte protocol */
230 int nSend;
231 int RetCode=0;
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);
240 msg.msg_iov = iov;
241 msg.msg_iovlen = 1;
242 msg.msg_name = NULL;
243 msg.msg_namelen = 0;
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() */
250 #else
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);
259 msg.msg_iov = iov;
260 msg.msg_iovlen = 1;
261 msg.msg_name = NULL;
262 msg.msg_namelen = 0;
263 msg.msg_control = (caddr_t) cmptr;
264 msg.msg_controllen = CONTROLLEN;
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));
271 #endif
273 if ( ( nSend = sendmsg(PipeFD, &msg, 0) ) > 0 )
275 bRet = sal_True;
276 OSL_TRACE("sendFdPipe : send '%i' bytes\n",nSend);
279 else
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");
290 else
292 OSL_TRACE("sendFdPipe : resource wasn't received\n");
295 #if defined(IOCHANNEL_TRANSFER_BSD_RENO)
296 free(cmptr);
297 #endif
299 return bRet;
302 /**********************************************
303 receiveFdPipe
304 *********************************************/
306 static oslSocket receiveFdPipe(int PipeFD)
308 oslSocket pSocket = 0;
309 struct msghdr msghdr;
310 struct iovec iov[1];
311 char buffer[2];
312 sal_Int32 nRead;
313 int newfd=-1;
314 int nRetCode=0;
315 /* char *ptr; */
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 */
330 #else
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;
345 #endif
348 #if defined(IOCHANNEL_TRANSFER_BSD)
350 if ( ( nRead = recvmsg(PipeFD, &msghdr, 0) ) > 0 )
352 OSL_TRACE("receiveFdPipe : received '%i' bytes\n",nRead);
354 #else
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));
362 #endif
363 else
365 OSL_TRACE("receiveFdPipe : receiving failed (%s)",strerror(errno));
368 if ( newfd >= 0 )
370 pSocket = __osl_createSocketImpl(newfd);
371 nRetCode=1;
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)
379 free(cmptr);
380 #endif
382 return pSocket;
385 /**********************************************
386 osl_sendResourcePipe
387 *********************************************/
389 sal_Bool osl_sendResourcePipe(oslPipe pPipe, oslSocket pSocket)
391 sal_Bool bRet = sal_False;
393 if ( pSocket == 0 || pPipe == 0 )
395 return sal_False;
398 bRet = sendFdPipe(pPipe->m_Socket,pSocket->m_Socket);
400 return bRet;
403 /**********************************************
404 osl_receiveResourcePipe
405 *********************************************/
407 oslSocket osl_receiveResourcePipe(oslPipe pPipe)
409 oslSocket pSocket=0;
411 if ( pPipe == 0 )
413 return 0;
416 pSocket = receiveFdPipe(pPipe->m_Socket);
418 return (oslSocket) pSocket;
423 /******************************************************************************
425 * Functions for starting a process
427 *****************************************************************************/
429 static void ChildStatusProc(void *pData)
431 pid_t pid = -1;
432 int status = 0;
433 int channel[2];
434 ProcessData data;
435 ProcessData *pdata;
436 int stdOutput[2] = { -1, -1 }, stdInput[2] = { -1, -1 }, stdError[2] = { -1, -1 };
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)
446 status = errno;
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)
454 status = errno;
456 if ( status == 0 && data.m_pOutputRead )
457 if (pipe( stdOutput ) == -1)
458 status = errno;
460 if ( status == 0 && data.m_pErrorRead )
461 if (pipe( stdError ) == -1)
462 status = errno;
464 if ( (status == 0) && ((pid = fork()) == 0) )
466 /* Child */
467 int chstatus = 0;
468 sal_Int32 nWrote;
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)
479 unsetenv("HOME");
480 #else
481 putenv("HOME=");
482 #endif
485 if (data.m_pszDir)
486 chstatus = chdir(data.m_pszDir);
488 if (chstatus == 0 && ((data.m_uid == (uid_t)-1) || ((data.m_uid == getuid()) && (data.m_gid == getgid()))))
490 int i;
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*/
497 else
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]);
551 _exit(255);
553 else
554 { /* Parent */
555 int i = -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] );
563 if (pid > 0)
565 while (((i = read(channel[0], &status, sizeof(status))) < 0))
567 if (errno != EINTR)
568 break;
572 if (channel[0] != -1) close(channel[0]);
574 if ((pid > 0) && (i == 0))
576 pid_t child_pid;
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 );
603 if ( child_pid < 0)
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 */
611 child_pid = pid;
615 if ( child_pid > 0 )
617 oslProcessImpl* pChild;
619 osl_acquireMutex(ChildListMutex);
621 pChild = ChildList;
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);
630 else
631 pChild->m_status = -1;
633 osl_setCondition(pChild->m_terminated);
636 pChild = pChild->m_pnext;
639 osl_releaseMutex(ChildListMutex);
642 else
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
664 if (pid > 0)
666 pid_t child_pid;
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;
703 unsigned int idx;
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);
738 pArguments[idx+1]=0;
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,
763 pArguments,
764 Options,
765 Security,
766 pszWorkDir,
767 pEnvironment,
768 pProcess,
769 pInputWrite,
770 pOutputRead,
771 pErrorRead
774 if ( pArguments != 0 )
776 for ( idx = 0 ; idx < nArguments ; ++idx )
778 if ( pArguments[idx] != 0 )
780 free(pArguments[idx]);
783 free(pArguments);
786 if ( pEnvironment != 0 )
788 for ( idx = 0 ; idx < nEnvironmentVars ; ++idx )
790 if ( pEnvironment[idx] != 0 )
792 free(pEnvironment[idx]);
795 free(pEnvironment);
798 return Error;
801 /**********************************************
802 osl_executeProcess
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,
814 oslProcess *pProcess
817 return osl_executeProcess_WithRedirectedIO(
818 ustrImageName,
819 ustrArguments,
820 nArguments,
821 Options,
822 Security,
823 ustrWorkDir,
824 ustrEnvironment,
825 nEnvironmentVars,
826 pProcess,
827 NULL,
828 NULL,
829 NULL
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
849 int i;
850 sal_Char path[PATH_MAX + 1];
851 ProcessData Data;
852 oslThread hThread;
854 path[0] = '\0';
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))
873 pszImageName = path;
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;
894 else
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;
903 else
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 /**********************************************
959 osl_terminateProcess
960 *********************************************/
962 oslProcessError SAL_CALL osl_terminateProcess(oslProcess Process)
964 if (Process == NULL)
965 return osl_Process_E_Unknown;
967 if (kill(((oslProcessImpl*)Process)->m_pid, SIGKILL) != 0)
969 switch (errno)
971 case EPERM:
972 return osl_Process_E_NoPermission;
974 case ESRCH:
975 return osl_Process_E_NotFound;
977 default:
978 return osl_Process_E_Unknown;
982 return osl_Process_E_None;
985 /**********************************************
986 osl_getProcess
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);
1002 pChild = ChildList;
1004 /* check if it is one of our child processes */
1005 while (pChild != NULL)
1007 if (Ident == (sal_uInt32) pChild->m_pid)
1008 break;
1010 pChild = pChild->m_pnext;
1013 pProcImpl = (oslProcessImpl*) malloc(sizeof(oslProcessImpl));
1014 pProcImpl->m_pid = Ident;
1015 pProcImpl->m_terminated = osl_createCondition();
1017 if (pChild != NULL)
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);
1028 else
1029 pProcImpl->m_pnext = NULL;
1031 osl_releaseMutex(ChildListMutex);
1033 else
1034 pProcImpl = NULL;
1036 return (pProcImpl);
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 )
1053 return;
1056 osl_acquireMutex(ChildListMutex);
1058 pChild = ChildList;
1060 /* remove process from child list */
1061 while (pChild != NULL)
1063 if (pChild == (oslProcessImpl*)Process)
1065 if (pPrev != NULL)
1066 pPrev->m_pnext = pChild->m_pnext;
1067 else
1068 ChildList = pChild->m_pnext;
1070 break;
1073 pPrev = pChild;
1074 pChild = pChild->m_pnext;
1077 osl_releaseMutex(ChildListMutex);
1079 osl_destroyCondition(((oslProcessImpl*)Process)->m_terminated);
1081 free(Process);
1085 #if defined(LINUX)
1086 struct osl_procStat
1088 /* from 'stat' */
1089 pid_t pid; /* pid */
1090 char command[16]; /* 'argv[0]' */ /* mfe: it all right char comm[16] in kernel! */
1091 char state; /* state (running, stopped, ...) */
1092 pid_t ppid; /* parent pid */
1093 pid_t pgrp; /* parent group */
1094 int session; /* session ID */
1095 int tty; /* no of tty */
1096 pid_t tpgid; /* group of process owning the tty */
1097 unsigned long flags; /* flags dunno */
1098 unsigned long minflt; /* minor page faults */
1099 unsigned long cminflt; /* minor page faults with children */
1100 unsigned long majflt; /* major page faults */
1101 unsigned long cmajflt; /* major page faults with children */
1102 unsigned long utime; /* no of jiffies in user mode */
1103 unsigned long stime; /* no of jiffies in kernel mode */
1104 unsigned long cutime; /* no of jiffies in user mode with children */
1105 unsigned long cstime; /* no of jiffies in kernel mode with children */
1106 unsigned long priority; /* nice value + 15 (kernel scheduling prio)*/
1107 long nice; /* nice value */
1108 long timeout; /* no of jiffies of next process timeout */
1109 long itrealvalue; /* no jiffies before next SIGALRM */
1110 unsigned long starttime; /* process started this no of jiffies after boot */
1111 unsigned long vsize; /* virtual memory size (in bytes) */
1112 long rss; /* resident set size (in pages) */
1113 unsigned long rss_rlim; /* rss limit (in bytes) */
1114 unsigned long startcode; /* address above program text can run */
1115 unsigned long endcode; /* address below program text can run */
1116 unsigned long startstack; /* address of start of stack */
1117 unsigned long kstkesp; /* current value of 'esp' (stack pointer) */
1118 unsigned long kstkeip; /* current value of 'eip' (instruction pointer) */
1119 /* mfe: Linux > 2.1.7x have more signals (88) */
1120 /*#ifdef LINUX */
1121 char signal[24]; /* pending signals */
1122 char blocked[24]; /* blocked signals */
1123 char sigignore[24]; /* ignored signals */
1124 char sigcatch[24]; /* catched signals */
1125 /*#else*/
1126 /* long long signal;*/
1127 /* long long blocked;*/
1128 /* long long sigignore;*/
1129 /* long long sigcatch;*/
1130 /*#endif */
1131 unsigned long wchan; /* 'channel' the process is waiting in */
1132 unsigned long nswap; /* ? */
1133 unsigned long cnswap; /* ? */
1135 /* from 'status' */
1136 int ruid; /* real uid */
1137 int euid; /* effective uid */
1138 int suid; /* saved uid */
1139 int fuid; /* file access uid */
1140 int rgid; /* real gid */
1141 int egid; /* effective gid */
1142 int sgid; /* saved gid */
1143 int fgid; /* file access gid */
1144 unsigned long vm_size; /* like vsize but on kb */
1145 unsigned long vm_lock; /* locked pages in kb */
1146 unsigned long vm_rss; /* like rss but in kb */
1147 unsigned long vm_data; /* data size */
1148 unsigned long vm_stack; /* stack size */
1149 unsigned long vm_exe; /* executable size */
1150 unsigned long vm_lib; /* library size */
1153 /**********************************************
1154 osl_getProcStat
1155 *********************************************/
1157 sal_Bool osl_getProcStat(pid_t pid, struct osl_procStat* procstat)
1159 int fd = 0;
1160 sal_Bool bRet = sal_False;
1161 char name[PATH_MAX + 1];
1162 snprintf(name, sizeof(name), "/proc/%u/stat", pid);
1164 if ((fd = open(name,O_RDONLY)) >=0 )
1166 char* tmp=0;
1167 char prstatbuf[512];
1168 memset(prstatbuf,0,512);
1169 bRet = read(fd,prstatbuf,511) == 511;
1171 close(fd);
1172 /*printf("%s\n\n",prstatbuf);*/
1174 if (!bRet)
1175 return sal_False;
1177 tmp = strrchr(prstatbuf, ')');
1178 *tmp = '\0';
1179 memset(procstat->command, 0, sizeof(procstat->command));
1181 sscanf(prstatbuf, "%d (%15c", &procstat->pid, procstat->command);
1182 sscanf(tmp + 2,
1183 "%c"
1184 "%i %i %i %i %i"
1185 "%lu %lu %lu %lu %lu"
1186 "%lu %lu %lu %lu"
1187 "%lu %li %li %li"
1188 "%lu %lu %li %lu"
1189 "%lu %lu %lu %lu %lu"
1190 "%s %s %s %s"
1191 "%lu %lu %lu",
1192 &procstat->state,
1193 &procstat->ppid, &procstat->pgrp, &procstat->session, &procstat->tty, &procstat->tpgid,
1194 &procstat->flags, &procstat->minflt, &procstat->cminflt, &procstat->majflt, &procstat->cmajflt,
1195 &procstat->utime, &procstat->stime, &procstat->cutime, &procstat->cstime,
1196 &procstat->priority, &procstat->nice, &procstat->timeout, &procstat->itrealvalue,
1197 &procstat->starttime, &procstat->vsize, &procstat->rss, &procstat->rss_rlim,
1198 &procstat->startcode, &procstat->endcode, &procstat->startstack, &procstat->kstkesp, &procstat->kstkeip,
1199 procstat->signal, procstat->blocked, procstat->sigignore, procstat->sigcatch,
1200 &procstat->wchan, &procstat->nswap, &procstat->cnswap
1203 return bRet;
1206 /**********************************************
1207 osl_getProcStatus
1208 *********************************************/
1210 sal_Bool osl_getProcStatus(pid_t pid, struct osl_procStat* procstat)
1212 int fd = 0;
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 )
1220 char* tmp=0;
1221 char prstatusbuf[512];
1222 memset(prstatusbuf,0,512);
1223 bRet = read(fd,prstatusbuf,511) == 511;
1225 close(fd);
1227 /* printf("\n\n%s\n\n",prstatusbuf);*/
1229 if (!bRet)
1230 return sal_False;
1232 tmp = strstr(prstatusbuf,"Uid:");
1233 if(tmp)
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:");
1242 if(tmp)
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:");
1250 if(tmp)
1252 sscanf(tmp,
1253 "VmSize: %lu kB\n"
1254 "VmLck: %lu kB\n"
1255 "VmRSS: %lu kB\n"
1256 "VmData: %lu kB\n"
1257 "VmStk: %lu kB\n"
1258 "VmExe: %lu kB\n"
1259 "VmLib: %lu kB\n",
1260 &procstat->vm_size, &procstat->vm_lock, &procstat->vm_rss, &procstat->vm_data,
1261 &procstat->vm_stack, &procstat->vm_exe, &procstat->vm_lib
1265 tmp = strstr(prstatusbuf,"SigPnd:");
1266 if(tmp)
1268 sscanf(tmp, "SigPnd: %s SigBlk: %s SigIgn: %s %*s %s",
1269 procstat->signal, procstat->blocked, procstat->sigignore, procstat->sigcatch
1273 return bRet;
1276 #endif
1278 /**********************************************
1279 osl_getProcessInfo
1280 *********************************************/
1282 oslProcessError SAL_CALL osl_getProcessInfo(oslProcess Process, oslProcessData Fields, oslProcessInfo* pInfo)
1284 pid_t pid;
1286 if (Process == NULL)
1287 pid = getpid();
1288 else
1289 pid = ((oslProcessImpl*)Process)->m_pid;
1291 if (! pInfo || (pInfo->Size != sizeof(oslProcessInfo)))
1292 return osl_Process_E_Unknown;
1294 pInfo->Fields = 0;
1296 if (Fields & osl_Process_IDENTIFIER)
1298 pInfo->Ident = pid;
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)
1317 int fd;
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;
1345 close(fd);
1347 return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown;
1349 else
1350 close(fd);
1353 #elif defined(HPUX)
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) )
1389 * mfe:
1390 * We calculate only time of the process proper.
1391 * Threads are processes, we do not consider their time here!
1392 * (For this, cutime and cstime should be used, it seems not
1393 * to work in 2.0.36)
1396 long clktck;
1397 unsigned long hz;
1398 unsigned long userseconds;
1399 unsigned long systemseconds;
1401 clktck = sysconf(_SC_CLK_TCK);
1402 if (clktck < 0) {
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) )
1421 * mfe:
1422 * vm_data (found in status) shows the size of the data segment
1423 * it a rough approximation of the core heap size
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;
1432 #endif
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
1455 a zombie.
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)
1484 break;
1486 pChild = pChild->m_pnext;
1489 osl_releaseMutex(ChildListMutex);
1491 if (pChild != NULL)
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;
1505 if (pTimeout)
1507 int timeout = 0;
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))
1515 sleep(1);
1517 if (timeout)
1518 osl_error = osl_Process_E_TimedOut;
1520 else /* infinite */
1522 while (!is_process_dead(pid))
1523 sleep(1);
1526 return osl_error;
1529 /**********************************************
1530 osl_joinProcess
1531 *********************************************/
1533 oslProcessError SAL_CALL osl_joinProcess(oslProcess Process)
1535 return osl_joinProcessWithTimeout(Process, NULL);