xref: /trunk/main/sal/osl/unx/process.c (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
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.
14  *
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).
20  *
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.
25  *
26  ************************************************************************/
27 
28 
29 /*
30  *   ToDo:
31  *      - cleanup of process status things
32  *      - cleanup of process spawning
33  *      - cleanup of resource transfer
34  */
35 
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
42 
43 
44 #ifdef FREEBSD
45 #include <machine/param.h>
46 #endif
47 
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>
54 
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>
62 
63 #include <grp.h>
64 
65 #include "procimpl.h"
66 #include "sockimpl.h"
67 #include "secimpl.h"
68 
69 
70 #define MAX_ARGS        255
71 #define MAX_ENVS        255
72 
73 #if defined(MACOSX) || defined(IORESOURCE_TRANSFER_BSD)
74 #define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(int))
75 #endif
76 
77 /* implemented in file.c */
78 extern oslFileError FileURLToPath( char *, size_t, rtl_uString* );
79 extern oslFileHandle osl_createFileHandleFromFD( int fd );
80 
81 /******************************************************************************
82  *
83  *                  Data Type Definition
84  *
85  ******************************************************************************/
86 
87 typedef struct {
88     int  m_hPipe;
89     int  m_hConn;
90     sal_Char m_Name[PATH_MAX + 1];
91 } Pipe;
92 
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;
107 
108 typedef struct _oslPipeImpl {
109     int      m_Socket;
110     sal_Char m_Name[PATH_MAX + 1];
111 } oslPipeImpl;
112 
113 
114 /******************************************************************************
115  *
116  *                  Function Declarations
117  *
118  *****************************************************************************/
119 
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 );
130 
131 
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);
138 
139 
140 sal_Bool osl_getFullPath(const sal_Char* pszFilename, sal_Char* pszPath, sal_uInt32 MaxLen);
141 
142 static oslProcessImpl* ChildList;
143 static oslMutex        ChildListMutex;
144 
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  *****************************************************************************/
151 
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)
154 {
155     sal_Char path[PATH_MAX + 1];
156     sal_Char *pchr;
157 
158     path[0] = '\0';
159 
160     OSL_ASSERT(pszName != NULL);
161 
162     if ( pszName == 0 )
163     {
164         return osl_Process_E_NotFound;
165     }
166 
167     if (pszPath == NULL)
168         pszPath = "PATH";
169 
170     if (Separator == '\0')
171         Separator = ':';
172 
173 
174     if ( (pchr = getenv(pszPath)) != 0 )
175     {
176         sal_Char *pstr;
177 
178         while (*pchr != '\0')
179         {
180             pstr = path;
181 
182             while ((*pchr != '\0') && (*pchr != Separator))
183                 *pstr++ = *pchr++;
184 
185             if ((pstr > path) && ((*(pstr - 1) != '/')))
186                 *pstr++ = '/';
187 
188             *pstr = '\0';
189 
190             strcat(path, pszName);
191 
192             if (access(path, 0) == 0)
193             {
194                 char szRealPathBuf[PATH_MAX] = "";
195 
196                 if( NULL == realpath(path, szRealPathBuf) || (strlen(szRealPathBuf) >= (sal_uInt32)Max))
197                     return osl_Process_E_Unknown;
198 
199                 strcpy(pszBuffer, path);
200 
201                 return osl_Process_E_None;
202             }
203 
204             if (*pchr == Separator)
205                 pchr++;
206         }
207     }
208 
209     return osl_Process_E_NotFound;
210 }
211 
212 /******************************************************************************
213  *
214  *                  New io resource transfer functions
215  *
216  *****************************************************************************/
217 
218 
219 /**********************************************
220  sendFdPipe
221  *********************************************/
222 
223 static sal_Bool sendFdPipe(int PipeFD, int SocketFD)
224 {
225     sal_Bool bRet = sal_False;
226 
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;
232 
233 #if defined(IOCHANNEL_TRANSFER_BSD)
234 
235     OSL_TRACE("IOCHANNEL_TRANSFER_BSD send");
236 /*      OSL_TRACE("sending fd %i\n",SocketFD); */
237 
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;
244 
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() */
249 
250 #else
251 
252     struct cmsghdr* cmptr = (struct cmsghdr*)malloc(CONTROLLEN);
253 
254     OSL_TRACE("!!!!!! IOCHANNEL_TRANSFER_BSD_RENO send");
255 /*      OSL_TRACE("sending fd %i\n",SocketFD); */
256 
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;
265 
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));
270 
271 #endif
272 
273     if ( ( nSend = sendmsg(PipeFD, &msg, 0) ) > 0 )
274     {
275         bRet = sal_True;
276         OSL_TRACE("sendFdPipe : send '%i' bytes\n",nSend);
277 
278     }
279     else
280     {
281         OSL_TRACE("sendFdPipe : sending failed (%s)",strerror(errno));
282     }
283 
284     nSend=read(PipeFD,&RetCode,sizeof(RetCode));
285 
286     if ( nSend > 0 && RetCode == 1 )
287     {
288         OSL_TRACE("sendFdPipe : resource was received\n");
289     }
290     else
291     {
292         OSL_TRACE("sendFdPipe : resource wasn't received\n");
293     }
294 
295 #if defined(IOCHANNEL_TRANSFER_BSD_RENO)
296     free(cmptr);
297 #endif
298 
299     return bRet;
300 }
301 
302 /**********************************************
303  receiveFdPipe
304  *********************************************/
305 
306 static oslSocket receiveFdPipe(int PipeFD)
307 {
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; */
316 
317 #if defined(IOCHANNEL_TRANSFER_BSD)
318 
319     OSL_TRACE("IOCHANNEL_TRANSFER_BSD receive\n");
320 
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 */
329 
330 #else
331     struct cmsghdr* cmptr = (struct cmsghdr*)malloc(CONTROLLEN);
332 
333     OSL_TRACE(" !!!! IOCHANNEL_TRANSFER_BSD_RENO receive");
334 
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;
341 
342     msghdr.msg_control = (caddr_t) cmptr;
343     msghdr.msg_controllen = CONTROLLEN;
344 
345 #endif
346 
347 
348 #if defined(IOCHANNEL_TRANSFER_BSD)
349 
350     if ( ( nRead = recvmsg(PipeFD, &msghdr, 0) ) > 0 )
351     {
352         OSL_TRACE("receiveFdPipe : received '%i' bytes\n",nRead);
353     }
354 #else
355 
356     if ( ( ( nRead = recvmsg(PipeFD, &msghdr, 0) ) > 0 ) &&
357          ( msghdr.msg_controllen == CONTROLLEN ) )
358     {
359         OSL_TRACE("receiveFdPipe : received '%i' bytes\n",nRead);
360         memcpy(&newfd, CMSG_DATA(cmptr), sizeof(int));
361     }
362 #endif
363     else
364     {
365         OSL_TRACE("receiveFdPipe : receiving failed (%s)",strerror(errno));
366     }
367 
368     if ( newfd >= 0 )
369     {
370         pSocket = __osl_createSocketImpl(newfd);
371         nRetCode=1;
372         OSL_TRACE("received fd %i\n",newfd);
373     }
374 
375     OSL_TRACE("receiveFdPipe : writing back %i",nRetCode);
376     nRead=write(PipeFD,&nRetCode,sizeof(nRetCode));
377 
378 #if defined(IOCHANNEL_TRANSFER_BSD_RENO)
379     free(cmptr);
380 #endif
381 
382     return pSocket;
383 }
384 
385 /**********************************************
386  osl_sendResourcePipe
387  *********************************************/
388 
389 sal_Bool osl_sendResourcePipe(oslPipe pPipe, oslSocket pSocket)
390 {
391     sal_Bool bRet = sal_False;
392 
393     if ( pSocket == 0 || pPipe == 0 )
394     {
395         return sal_False;
396     }
397 
398     bRet = sendFdPipe(pPipe->m_Socket,pSocket->m_Socket);
399 
400     return bRet;
401 }
402 
403 /**********************************************
404  osl_receiveResourcePipe
405  *********************************************/
406 
407 oslSocket osl_receiveResourcePipe(oslPipe pPipe)
408 {
409     oslSocket pSocket=0;
410 
411     if ( pPipe ==  0 )
412     {
413         return 0;
414     }
415 
416     pSocket = receiveFdPipe(pPipe->m_Socket);
417 
418     return (oslSocket) pSocket;
419 }
420 
421 
422 
423 /******************************************************************************
424  *
425  *                  Functions for starting a process
426  *
427  *****************************************************************************/
428 
429 static void ChildStatusProc(void *pData)
430 {
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 };
437 
438     pdata = (ProcessData *)pData;
439 
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));
444 
445     if (socketpair(AF_UNIX, SOCK_STREAM, 0, channel) == -1)
446         status = errno;
447 
448     fcntl(channel[0], F_SETFD, FD_CLOEXEC);
449     fcntl(channel[1], F_SETFD, FD_CLOEXEC);
450 
451     /* Create redirected IO pipes */
452     if ( status == 0 && data.m_pInputWrite )
453         if (pipe( stdInput ) == -1)
454             status = errno;
455 
456     if ( status == 0 && data.m_pOutputRead )
457         if (pipe( stdOutput ) == -1)
458             status = errno;
459 
460     if ( status == 0 && data.m_pErrorRead )
461         if (pipe( stdError ) == -1)
462             status = errno;
463 
464     if ( (status == 0) && ((pid = fork()) == 0) )
465     {
466         /* Child */
467         int chstatus = 0;
468         sal_Int32 nWrote;
469 
470         if (channel[0] != -1) close(channel[0]);
471 
472         if ((data.m_uid != (uid_t)-1) && ((data.m_uid != getuid()) || (data.m_gid != getgid())))
473         {
474             OSL_ASSERT(geteuid() == 0);     /* must be root */
475 
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
483         }
484 
485         if (data.m_pszDir)
486             chstatus = chdir(data.m_pszDir);
487 
488         if (chstatus == 0 && ((data.m_uid == (uid_t)-1) || ((data.m_uid == getuid()) && (data.m_gid == getgid()))))
489         {
490             int i;
491             for (i = 0; data.m_pszEnv[i] != NULL; i++)
492             {
493                 if (strchr(data.m_pszEnv[i], '=') == NULL)
494                 {
495                     unsetenv(data.m_pszEnv[i]); /*TODO: check error return*/
496                 }
497                 else
498                 {
499                     putenv(data.m_pszEnv[i]); /*TODO: check error return*/
500                 }
501             }
502 
503             OSL_TRACE("ChildStatusProc : starting '%s'",data.m_pszArgs[0]);
504 
505             /* Connect std IO to pipe ends */
506 
507             /* Write end of stdInput not used in child process */
508             if (stdInput[1] != -1) close( stdInput[1] );
509 
510             /* Read end of stdOutput not used in child process */
511             if (stdOutput[0] != -1) close( stdOutput[0] );
512 
513             /* Read end of stdError not used in child process */
514             if (stdError[0] != -1) close( stdError[0] );
515 
516             /* Redirect pipe ends to std IO */
517 
518             if ( stdInput[0] != STDIN_FILENO )
519             {
520                 dup2( stdInput[0], STDIN_FILENO );
521                 if (stdInput[0] != -1) close( stdInput[0] );
522             }
523 
524             if ( stdOutput[1] != STDOUT_FILENO )
525             {
526                 dup2( stdOutput[1], STDOUT_FILENO );
527                 if (stdOutput[1] != -1) close( stdOutput[1] );
528             }
529 
530             if ( stdError[1] != STDERR_FILENO )
531             {
532                 dup2( stdError[1], STDERR_FILENO );
533                 if (stdError[1] != -1) close( stdError[1] );
534             }
535 
536             pid=execv(data.m_pszArgs[0], (sal_Char **)data.m_pszArgs);
537 
538         }
539 
540         OSL_TRACE("Failed to exec, errno=%d (%s)\n", errno, strerror(errno));
541 
542         OSL_TRACE("ChildStatusProc : starting '%s' failed",data.m_pszArgs[0]);
543 
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));
548 
549         if (channel[1] != -1) close(channel[1]);
550 
551         _exit(255);
552     }
553     else
554     {   /* Parent  */
555         int i = -1;
556         if (channel[1] != -1) close(channel[1]);
557 
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] );
562 
563         if (pid > 0)
564         {
565             while (((i = read(channel[0], &status, sizeof(status))) < 0))
566             {
567                 if (errno != EINTR)
568                     break;
569             }
570         }
571 
572         if (channel[0] != -1) close(channel[0]);
573 
574         if ((pid > 0) && (i == 0))
575         {
576             pid_t   child_pid;
577             osl_acquireMutex(ChildListMutex);
578 
579             pdata->m_pProcImpl->m_pid = pid;
580             pdata->m_pProcImpl->m_pnext = ChildList;
581             ChildList = pdata->m_pProcImpl;
582 
583             /* Store used pipe ends in data structure */
584 
585             if ( pdata->m_pInputWrite )
586                 *(pdata->m_pInputWrite) = osl_createFileHandleFromFD( stdInput[1] );
587 
588             if ( pdata->m_pOutputRead )
589                 *(pdata->m_pOutputRead) = osl_createFileHandleFromFD( stdOutput[0] );
590 
591             if ( pdata->m_pErrorRead )
592                 *(pdata->m_pErrorRead) = osl_createFileHandleFromFD( stdError[0] );
593 
594             osl_releaseMutex(ChildListMutex);
595 
596             osl_setCondition(pdata->m_started);
597 
598             do
599             {
600                 child_pid = waitpid(pid, &status, 0);
601             } while ( 0 > child_pid && EINTR == errno );
602 
603             if ( child_pid < 0)
604             {
605                 OSL_TRACE("Failed to wait for child process, errno=%d (%s)\n", errno, strerror(errno));
606 
607                 /*
608                 We got an other error than EINTR. Anyway we have to wake up the
609                 waiting thread under any circumstances */
610 
611                 child_pid = pid;
612             }
613 
614 
615             if ( child_pid > 0 )
616             {
617                 oslProcessImpl* pChild;
618 
619                 osl_acquireMutex(ChildListMutex);
620 
621                 pChild = ChildList;
622 
623                 /* check if it is one of our child processes */
624                 while (pChild != NULL)
625                 {
626                     if (pChild->m_pid == child_pid)
627                     {
628                         if (WIFEXITED(status))
629                             pChild->m_status = WEXITSTATUS(status);
630                         else
631                             pChild->m_status = -1;
632 
633                         osl_setCondition(pChild->m_terminated);
634                     }
635 
636                     pChild = pChild->m_pnext;
637                 }
638 
639                 osl_releaseMutex(ChildListMutex);
640             }
641         }
642         else
643         {
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));
646 
647             /* Close pipe ends */
648             if ( pdata->m_pInputWrite )
649                 *pdata->m_pInputWrite = NULL;
650 
651             if ( pdata->m_pOutputRead )
652                 *pdata->m_pOutputRead = NULL;
653 
654             if ( pdata->m_pErrorRead )
655                 *pdata->m_pErrorRead = NULL;
656 
657             if (stdInput[1] != -1) close( stdInput[1] );
658             if (stdOutput[0] != -1) close( stdOutput[0] );
659             if (stdError[0] != -1) close( stdError[0] );
660 
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)
665             {
666                 pid_t child_pid;
667                 do
668                 {
669                     child_pid = waitpid(pid, &status, 0);
670                 } while ( 0 > child_pid && EINTR == errno );
671             }
672 
673             /* notify (and unblock) parent thread */
674             osl_setCondition(pdata->m_started);
675         }
676     }
677 }
678 
679 /**********************************************
680  osl_executeProcess_WithRedirectedIO
681  *********************************************/
682 
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
696                                             )
697 {
698 
699     oslProcessError Error;
700     sal_Char* pszWorkDir=0;
701     sal_Char** pArguments=0;
702     sal_Char** pEnvironment=0;
703     unsigned int idx;
704 
705     char szImagePath[PATH_MAX] = "";
706     char szWorkDir[PATH_MAX] = "";
707 
708     if ( ustrImageName && ustrImageName->length )
709     {
710         FileURLToPath( szImagePath, PATH_MAX, ustrImageName );
711     }
712 
713     if ( ustrWorkDir != 0 && ustrWorkDir->length )
714     {
715         FileURLToPath( szWorkDir, PATH_MAX, ustrWorkDir );
716         pszWorkDir = szWorkDir;
717     }
718 
719     if ( pArguments == 0 && nArguments > 0 )
720     {
721         pArguments = (sal_Char**) malloc( ( nArguments + 2 ) * sizeof(sal_Char*) );
722     }
723 
724 
725     for ( idx = 0 ; idx < nArguments ; ++idx )
726     {
727         rtl_String* strArg =0;
728 
729 
730         rtl_uString2String( &strArg,
731                             rtl_uString_getStr(ustrArguments[idx]),
732                             rtl_uString_getLength(ustrArguments[idx]),
733                             osl_getThreadTextEncoding(),
734                             OUSTRING_TO_OSTRING_CVTFLAGS );
735 
736         pArguments[idx]=strdup(rtl_string_getStr(strArg));
737         rtl_string_release(strArg);
738         pArguments[idx+1]=0;
739     }
740 
741     for ( idx = 0 ; idx < nEnvironmentVars ; ++idx )
742     {
743         rtl_String* strEnv=0;
744 
745         if ( pEnvironment == 0 )
746         {
747             pEnvironment = (sal_Char**) malloc( ( nEnvironmentVars + 2 ) * sizeof(sal_Char*) );
748         }
749 
750         rtl_uString2String( &strEnv,
751                             rtl_uString_getStr(ustrEnvironment[idx]),
752                             rtl_uString_getLength(ustrEnvironment[idx]),
753                             osl_getThreadTextEncoding(),
754                             OUSTRING_TO_OSTRING_CVTFLAGS );
755 
756         pEnvironment[idx]=strdup(rtl_string_getStr(strEnv));
757         rtl_string_release(strEnv);
758         pEnvironment[idx+1]=0;
759     }
760 
761 
762     Error = osl_psz_executeProcess(szImagePath,
763                                    pArguments,
764                                    Options,
765                                    Security,
766                                    pszWorkDir,
767                                    pEnvironment,
768                                    pProcess,
769                                    pInputWrite,
770                                    pOutputRead,
771                                    pErrorRead
772                                    );
773 
774     if ( pArguments != 0 )
775     {
776         for ( idx = 0 ; idx < nArguments ; ++idx )
777         {
778             if ( pArguments[idx] != 0 )
779             {
780                 free(pArguments[idx]);
781             }
782         }
783         free(pArguments);
784     }
785 
786     if ( pEnvironment != 0 )
787     {
788         for ( idx = 0 ; idx < nEnvironmentVars ; ++idx )
789         {
790             if ( pEnvironment[idx] != 0 )
791             {
792                 free(pEnvironment[idx]);
793             }
794         }
795         free(pEnvironment);
796     }
797 
798     return Error;
799 }
800 
801 /**********************************************
802  osl_executeProcess
803  *********************************************/
804 
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
815                                             )
816 {
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
830         );
831 }
832 
833 /**********************************************
834  osl_psz_executeProcess
835  *********************************************/
836 
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
847                                                 )
848 {
849     int     i;
850     sal_Char    path[PATH_MAX + 1];
851     ProcessData Data;
852     oslThread hThread;
853 
854     path[0] = '\0';
855 
856     memset(&Data,0,sizeof(ProcessData));
857     Data.m_pInputWrite = pInputWrite;
858     Data.m_pOutputRead = pOutputRead;
859     Data.m_pErrorRead = pErrorRead;
860 
861     if (pszImageName == NULL)
862         pszImageName = pszArguments[0];
863 
864     OSL_ASSERT(pszImageName != NULL);
865 
866     if ( pszImageName == 0 )
867     {
868         return osl_Process_E_NotFound;
869     }
870 
871     if ((Options & osl_Process_SEARCHPATH) &&
872         (osl_searchPath_impl(pszImageName, NULL, '\0', path, sizeof(path)) == osl_Process_E_None))
873         pszImageName = path;
874 
875     Data.m_pszArgs[0] = strdup(pszImageName);
876     Data.m_pszArgs[1] = 0;
877 
878     if ( pszArguments != 0 )
879     {
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;
883     }
884 
885     Data.m_options = Options;
886     Data.m_pszDir  = (pszDirectory != NULL) ? strdup(pszDirectory) : NULL;
887 
888     if (pszEnvironments != NULL)
889     {
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;
893     }
894     else
895         Data.m_pszEnv[0] = NULL;
896 
897     if (Security != NULL)
898     {
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;
902     }
903     else
904         Data.m_uid = (uid_t)-1;
905 
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;
910 
911     if (ChildListMutex == NULL)
912         ChildListMutex = osl_createMutex();
913 
914     Data.m_started = osl_createCondition();
915 
916     hThread = osl_createThread(ChildStatusProc, &Data);
917 
918     osl_waitCondition(Data.m_started, NULL);
919     osl_destroyCondition(Data.m_started);
920 
921     for (i = 0; Data.m_pszArgs[i] != NULL; i++)
922           free((void *)Data.m_pszArgs[i]);
923 
924     for (i = 0; Data.m_pszEnv[i] != NULL; i++)
925           free((void *)Data.m_pszEnv[i]);
926 
927     if ( Data.m_pszDir != 0 )
928     {
929         free((void *)Data.m_pszDir);
930     }
931 
932     osl_destroyThread(hThread);
933 
934     if (Data.m_pProcImpl->m_pid != 0)
935     {
936         *pProcess = Data.m_pProcImpl;
937 
938         if (Options & osl_Process_WAIT)
939             osl_joinProcess(*pProcess);
940 
941         return osl_Process_E_None;
942     }
943 
944     osl_destroyCondition(Data.m_pProcImpl->m_terminated);
945     free(Data.m_pProcImpl);
946 
947     return osl_Process_E_Unknown;
948 }
949 
950 
951 /******************************************************************************
952  *
953  *                  Functions for processes
954  *
955  *****************************************************************************/
956 
957 
958 /**********************************************
959  osl_terminateProcess
960  *********************************************/
961 
962 oslProcessError SAL_CALL osl_terminateProcess(oslProcess Process)
963 {
964     if (Process == NULL)
965         return osl_Process_E_Unknown;
966 
967     if (kill(((oslProcessImpl*)Process)->m_pid, SIGKILL) != 0)
968     {
969         switch (errno)
970         {
971             case EPERM:
972                 return osl_Process_E_NoPermission;
973 
974             case ESRCH:
975                 return osl_Process_E_NotFound;
976 
977             default:
978                 return osl_Process_E_Unknown;
979         }
980     }
981 
982     return osl_Process_E_None;
983 }
984 
985 /**********************************************
986  osl_getProcess
987  *********************************************/
988 
989 oslProcess SAL_CALL osl_getProcess(oslProcessIdentifier Ident)
990 {
991     oslProcessImpl *pProcImpl;
992 
993     if (kill(Ident, 0) != -1)
994     {
995         oslProcessImpl* pChild;
996 
997         if (ChildListMutex == NULL)
998             ChildListMutex = osl_createMutex();
999 
1000         osl_acquireMutex(ChildListMutex);
1001 
1002         pChild = ChildList;
1003 
1004         /* check if it is one of our child processes */
1005         while (pChild != NULL)
1006         {
1007             if (Ident == (sal_uInt32) pChild->m_pid)
1008                 break;
1009 
1010             pChild = pChild->m_pnext;
1011         }
1012 
1013         pProcImpl = (oslProcessImpl*) malloc(sizeof(oslProcessImpl));
1014         pProcImpl->m_pid        = Ident;
1015         pProcImpl->m_terminated = osl_createCondition();
1016 
1017         if (pChild != NULL)
1018         {
1019             /* process is a child so insert into list */
1020             pProcImpl->m_pnext = pChild->m_pnext;
1021             pChild->m_pnext = pProcImpl;
1022 
1023             pProcImpl->m_status = pChild->m_status;
1024 
1025             if (osl_checkCondition(pChild->m_terminated))
1026                 osl_setCondition(pProcImpl->m_terminated);
1027         }
1028         else
1029             pProcImpl->m_pnext = NULL;
1030 
1031         osl_releaseMutex(ChildListMutex);
1032     }
1033     else
1034         pProcImpl = NULL;
1035 
1036     return (pProcImpl);
1037 }
1038 
1039 /**********************************************
1040  osl_freeProcessHandle
1041  *********************************************/
1042 
1043 void SAL_CALL osl_freeProcessHandle(oslProcess Process)
1044 {
1045     if (Process != NULL)
1046     {
1047         oslProcessImpl *pChild, *pPrev = NULL;
1048 
1049         OSL_ASSERT(ChildListMutex != NULL);
1050 
1051         if ( ChildListMutex == 0 )
1052         {
1053             return;
1054         }
1055 
1056         osl_acquireMutex(ChildListMutex);
1057 
1058         pChild = ChildList;
1059 
1060         /* remove process from child list */
1061         while (pChild != NULL)
1062         {
1063             if (pChild == (oslProcessImpl*)Process)
1064             {
1065                 if (pPrev != NULL)
1066                     pPrev->m_pnext = pChild->m_pnext;
1067                 else
1068                     ChildList = pChild->m_pnext;
1069 
1070                 break;
1071             }
1072 
1073             pPrev  = pChild;
1074             pChild = pChild->m_pnext;
1075         }
1076 
1077         osl_releaseMutex(ChildListMutex);
1078 
1079         osl_destroyCondition(((oslProcessImpl*)Process)->m_terminated);
1080 
1081         free(Process);
1082     }
1083 }
1084 
1085 #if defined(LINUX)
1086 struct osl_procStat
1087 {
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;     /* ? */
1134 
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 */
1151 };
1152 
1153 /**********************************************
1154  osl_getProcStat
1155  *********************************************/
1156 
1157 sal_Bool osl_getProcStat(pid_t pid, struct osl_procStat* procstat)
1158 {
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);
1163 
1164     if ((fd = open(name,O_RDONLY)) >=0 )
1165     {
1166         char* tmp=0;
1167         char prstatbuf[512];
1168         memset(prstatbuf,0,512);
1169         bRet = read(fd,prstatbuf,511) == 511;
1170 
1171         close(fd);
1172         /*printf("%s\n\n",prstatbuf);*/
1173 
1174         if (!bRet)
1175             return sal_False;
1176 
1177         tmp = strrchr(prstatbuf, ')');
1178         *tmp = '\0';
1179         memset(procstat->command, 0, sizeof(procstat->command));
1180 
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
1201             );
1202     }
1203     return bRet;
1204 }
1205 
1206 /**********************************************
1207  osl_getProcStatus
1208  *********************************************/
1209 
1210 sal_Bool osl_getProcStatus(pid_t pid, struct osl_procStat* procstat)
1211 {
1212     int fd = 0;
1213     char name[PATH_MAX + 1];
1214     snprintf(name, sizeof(name), "/proc/%u/status", pid);
1215 
1216     sal_Bool bRet = sal_False;
1217 
1218     if ((fd = open(name,O_RDONLY)) >=0 )
1219     {
1220         char* tmp=0;
1221         char prstatusbuf[512];
1222         memset(prstatusbuf,0,512);
1223         bRet = read(fd,prstatusbuf,511) == 511;
1224 
1225         close(fd);
1226 
1227         /*      printf("\n\n%s\n\n",prstatusbuf);*/
1228 
1229         if (!bRet)
1230             return sal_False;
1231 
1232         tmp = strstr(prstatusbuf,"Uid:");
1233         if(tmp)
1234         {
1235             sscanf(tmp,"Uid:\t%d\t%d\t%d\t%d",
1236                    &procstat->ruid, &procstat->euid, &procstat->suid, &procstat->fuid
1237                 );
1238         }
1239 
1240 
1241         tmp = strstr(prstatusbuf,"Gid:");
1242         if(tmp)
1243         {
1244             sscanf(tmp,"Gid:\t%d\t%d\t%d\t%d",
1245                    &procstat->rgid, &procstat->egid, &procstat->sgid, &procstat->fgid
1246                 );
1247         }
1248 
1249         tmp = strstr(prstatusbuf,"VmSize:");
1250         if(tmp)
1251         {
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
1262                 );
1263         }
1264 
1265         tmp = strstr(prstatusbuf,"SigPnd:");
1266         if(tmp)
1267         {
1268             sscanf(tmp, "SigPnd: %s SigBlk: %s SigIgn: %s %*s %s",
1269                    procstat->signal, procstat->blocked, procstat->sigignore, procstat->sigcatch
1270                 );
1271         }
1272     }
1273     return bRet;
1274 }
1275 
1276 #endif
1277 
1278 /**********************************************
1279  osl_getProcessInfo
1280  *********************************************/
1281 
1282 oslProcessError SAL_CALL osl_getProcessInfo(oslProcess Process, oslProcessData Fields, oslProcessInfo* pInfo)
1283 {
1284     pid_t   pid;
1285 
1286     if (Process == NULL)
1287         pid = getpid();
1288     else
1289         pid = ((oslProcessImpl*)Process)->m_pid;
1290 
1291     if (! pInfo || (pInfo->Size != sizeof(oslProcessInfo)))
1292         return osl_Process_E_Unknown;
1293 
1294     pInfo->Fields = 0;
1295 
1296     if (Fields & osl_Process_IDENTIFIER)
1297     {
1298         pInfo->Ident  = pid;
1299         pInfo->Fields |= osl_Process_IDENTIFIER;
1300     }
1301 
1302     if (Fields & osl_Process_EXITCODE)
1303     {
1304         if ((Process != NULL) &&
1305             osl_checkCondition(((oslProcessImpl*)Process)->m_terminated))
1306         {
1307             pInfo->Code = ((oslProcessImpl*)Process)->m_status;
1308             pInfo->Fields |= osl_Process_EXITCODE;
1309         }
1310     }
1311 
1312     if (Fields & (osl_Process_HEAPUSAGE | osl_Process_CPUTIMES))
1313     {
1314 
1315 #if defined(SOLARIS)
1316 
1317         int  fd;
1318         sal_Char name[PATH_MAX + 1];
1319 
1320         snprintf(name, sizeof(name), "/proc/%u", pid);
1321 
1322         if ((fd = open(name, O_RDONLY)) >= 0)
1323         {
1324             prstatus_t prstatus;
1325 
1326             if (ioctl(fd, PIOCSTATUS, &prstatus) >= 0)
1327             {
1328                 if (Fields & osl_Process_CPUTIMES)
1329                 {
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;
1334 
1335                     pInfo->Fields |= osl_Process_CPUTIMES;
1336                 }
1337 
1338                 if (Fields & osl_Process_HEAPUSAGE)
1339                 {
1340                     pInfo->HeapUsage = prstatus.pr_brksize;
1341 
1342                     pInfo->Fields |= osl_Process_HEAPUSAGE;
1343                 }
1344 
1345                 close(fd);
1346 
1347                 return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown;
1348             }
1349             else
1350                 close(fd);
1351         }
1352 
1353 #elif defined(HPUX)
1354 
1355         struct pst_status prstatus;
1356 
1357         if (pstat_getproc(&prstatus, sizeof(prstatus), (size_t)0, pid) == 1)
1358         {
1359             if (Fields & osl_Process_CPUTIMES)
1360             {
1361                 pInfo->UserTime.Seconds   = prstatus.pst_utime;
1362                 pInfo->UserTime.Nanosec   = 500000L;
1363                 pInfo->SystemTime.Seconds = prstatus.pst_stime;
1364                 pInfo->SystemTime.Nanosec = 500000L;
1365 
1366                 pInfo->Fields |= osl_Process_CPUTIMES;
1367             }
1368 
1369             if (Fields & osl_Process_HEAPUSAGE)
1370             {
1371                 pInfo->HeapUsage = prstatus.pst_vdsize*PAGESIZE;
1372 
1373                 pInfo->Fields |= osl_Process_HEAPUSAGE;
1374             }
1375 
1376             return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown;
1377         }
1378 
1379 #elif defined(LINUX)
1380 
1381         if ( (Fields & osl_Process_CPUTIMES) || (Fields & osl_Process_HEAPUSAGE) )
1382         {
1383             struct osl_procStat procstat;
1384             memset(&procstat,0,sizeof(procstat));
1385 
1386             if ( (Fields & osl_Process_CPUTIMES) && osl_getProcStat(pid, &procstat) )
1387             {
1388                 /*
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)
1394                  */
1395 
1396                 long clktck;
1397                 unsigned long hz;
1398                 unsigned long userseconds;
1399                 unsigned long systemseconds;
1400 
1401                 clktck = sysconf(_SC_CLK_TCK);
1402                 if (clktck < 0) {
1403                     return osl_Process_E_Unknown;
1404                 }
1405                 hz = (unsigned long) clktck;
1406 
1407                 userseconds = procstat.utime/hz;
1408                 systemseconds = procstat.stime/hz;
1409 
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);
1414 
1415                 pInfo->Fields |= osl_Process_CPUTIMES;
1416             }
1417 
1418             if ( (Fields & osl_Process_HEAPUSAGE) && osl_getProcStatus(pid, &procstat) )
1419             {
1420                 /*
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
1424                  */
1425                 pInfo->HeapUsage = procstat.vm_data*1024;
1426 
1427                 pInfo->Fields |= osl_Process_HEAPUSAGE;
1428             }
1429         }
1430 
1431         return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown;
1432 #endif
1433 
1434     }
1435 
1436     return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown;
1437 }
1438 
1439 
1440 /***********************************************
1441  helper function for osl_joinProcessWithTimeout
1442  **********************************************/
1443 
1444 static int is_timeout(const struct timeval* tend)
1445 {
1446     struct timeval tcurrent;
1447     gettimeofday(&tcurrent, NULL);
1448     return (tcurrent.tv_sec >= tend->tv_sec);
1449 }
1450 
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  *********************************************/
1457 
1458 static int is_process_dead(pid_t pid)
1459 {
1460     return ((-1 == kill(pid, 0)) && (ESRCH == errno));
1461 }
1462 
1463 /**********************************************
1464  osl_joinProcessWithTimeout
1465  *********************************************/
1466 
1467 oslProcessError SAL_CALL osl_joinProcessWithTimeout(oslProcess Process, const TimeValue* pTimeout)
1468 {
1469     oslProcessImpl* pChild    = ChildList;
1470     oslProcessError osl_error = osl_Process_E_None;
1471 
1472     OSL_PRECOND(Process, "osl_joinProcess: Invalid parameter");
1473     OSL_ASSERT(ChildListMutex);
1474 
1475     if (NULL == Process || 0 == ChildListMutex)
1476         return osl_Process_E_Unknown;
1477 
1478     osl_acquireMutex(ChildListMutex);
1479 
1480     /* check if process is a child of ours */
1481     while (pChild != NULL)
1482     {
1483         if (pChild == (oslProcessImpl*)Process)
1484             break;
1485 
1486         pChild = pChild->m_pnext;
1487     }
1488 
1489     osl_releaseMutex(ChildListMutex);
1490 
1491     if (pChild != NULL)
1492     {
1493         oslConditionResult cond_res = osl_waitCondition(pChild->m_terminated, pTimeout);
1494 
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;
1499     }
1500     else /* alien process; StatusThread will not be able
1501             to set the condition terminated */
1502     {
1503         pid_t pid = ((oslProcessImpl*)Process)->m_pid;
1504 
1505         if (pTimeout)
1506         {
1507             int timeout = 0;
1508             struct timeval tend;
1509 
1510             gettimeofday(&tend, NULL);
1511 
1512             tend.tv_sec += pTimeout->Seconds;
1513 
1514             while (!is_process_dead(pid) && ((timeout = is_timeout(&tend)) == 0))
1515                 sleep(1);
1516 
1517             if (timeout)
1518                 osl_error = osl_Process_E_TimedOut;
1519         }
1520         else /* infinite */
1521         {
1522             while (!is_process_dead(pid))
1523                 sleep(1);
1524         }
1525     }
1526     return osl_error;
1527 }
1528 
1529 /**********************************************
1530  osl_joinProcess
1531  *********************************************/
1532 
1533 oslProcessError SAL_CALL osl_joinProcess(oslProcess Process)
1534 {
1535     return osl_joinProcessWithTimeout(Process, NULL);
1536 }
1537