xref: /AOO41X/main/sal/osl/unx/process.c (revision 647f063d49501903f1667b75f5634541fc603283)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 
25 /*
26  *   ToDo:
27  *      - cleanup of process status things
28  *      - cleanup of process spawning
29  *      - cleanup of resource transfer
30  */
31 
32 #if defined(SOLARIS)
33   // The procfs may only be used without LFS in 32bits.
34 # ifdef _FILE_OFFSET_BITS
35 #   undef   _FILE_OFFSET_BITS
36 # endif
37 #endif
38 
39 
40 #ifdef FREEBSD
41 #include <machine/param.h>
42 #endif
43 
44 #include "system.h"
45 #if defined(SOLARIS)
46 # include <sys/procfs.h>
47 #endif
48 #include <osl/diagnose.h>
49 #include <osl/mutex.h>
50 
51 #ifndef _OSL_CONDITN_H_
52 #include <osl/conditn.h>
53 #endif
54 #include <osl/thread.h>
55 #include <osl/file.h>
56 #include <osl/signal.h>
57 #include <rtl/alloc.h>
58 
59 #include <grp.h>
60 
61 #include "procimpl.h"
62 #include "sockimpl.h"
63 #include "secimpl.h"
64 
65 
66 #define MAX_ARGS        255
67 #define MAX_ENVS        255
68 
69 #if defined(MACOSX) || defined(IORESOURCE_TRANSFER_BSD)
70 #define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(int))
71 #endif
72 
73 /* implemented in file.c */
74 extern oslFileError FileURLToPath( char *, size_t, rtl_uString* );
75 extern oslFileHandle osl_createFileHandleFromFD( int fd );
76 
77 /******************************************************************************
78  *
79  *                  Data Type Definition
80  *
81  ******************************************************************************/
82 
83 typedef struct {
84     int  m_hPipe;
85     int  m_hConn;
86     sal_Char m_Name[PATH_MAX + 1];
87 } Pipe;
88 
89 typedef struct {
90     const sal_Char*  m_pszArgs[MAX_ARGS + 1];
91     oslProcessOption m_options;
92     const sal_Char*  m_pszDir;
93     sal_Char*        m_pszEnv[MAX_ENVS + 1];
94     uid_t            m_uid;
95     gid_t            m_gid;
96     sal_Char*        m_name;
97     oslCondition     m_started;
98     oslProcessImpl*  m_pProcImpl;
99     oslFileHandle    *m_pInputWrite;
100     oslFileHandle    *m_pOutputRead;
101     oslFileHandle    *m_pErrorRead;
102 } ProcessData;
103 
104 typedef struct _oslPipeImpl {
105     int      m_Socket;
106     sal_Char m_Name[PATH_MAX + 1];
107 } oslPipeImpl;
108 
109 
110 /******************************************************************************
111  *
112  *                  Function Declarations
113  *
114  *****************************************************************************/
115 
116 oslProcessError SAL_CALL osl_psz_executeProcess(sal_Char *pszImageName,
117                                                 sal_Char *pszArguments[],
118                                                 oslProcessOption Options,
119                                                 oslSecurity Security,
120                                                 sal_Char *pszDirectory,
121                                                 sal_Char *pszEnvironments[],
122                                                 oslProcess *pProcess,
123                                                 oslFileHandle *pInputWrite,
124                                                 oslFileHandle *pOutputRead,
125                                                 oslFileHandle *pErrorRead );
126 
127 
128 oslProcessError SAL_CALL osl_searchPath_impl(
129     const sal_Char* pszName,
130     const sal_Char* pszPath,
131     sal_Char Separator,
132     sal_Char *pszBuffer,
133     sal_uInt32 Max);
134 
135 
136 sal_Bool osl_getFullPath(const sal_Char* pszFilename, sal_Char* pszPath, sal_uInt32 MaxLen);
137 
138 static oslProcessImpl* ChildList;
139 static oslMutex        ChildListMutex;
140 
141 /******************************************************************************
142  Deprecated
143  Old and buggy implementation of osl_searchPath used only by
144  osl_psz_executeProcess.
145  A new implemenation is in file_path_helper.cxx
146  *****************************************************************************/
147 
osl_searchPath_impl(const sal_Char * pszName,const sal_Char * pszPath,sal_Char Separator,sal_Char * pszBuffer,sal_uInt32 Max)148 oslProcessError SAL_CALL osl_searchPath_impl(const sal_Char* pszName, const sal_Char* pszPath,
149                    sal_Char Separator, sal_Char *pszBuffer, sal_uInt32 Max)
150 {
151     sal_Char path[PATH_MAX + 1];
152     sal_Char *pchr;
153 
154     path[0] = '\0';
155 
156     OSL_ASSERT(pszName != NULL);
157 
158     if ( pszName == 0 )
159     {
160         return osl_Process_E_NotFound;
161     }
162 
163     if (pszPath == NULL)
164         pszPath = "PATH";
165 
166     if (Separator == '\0')
167         Separator = ':';
168 
169 
170     if ( (pchr = getenv(pszPath)) != 0 )
171     {
172         sal_Char *pstr;
173 
174         while (*pchr != '\0')
175         {
176             pstr = path;
177 
178             while ((*pchr != '\0') && (*pchr != Separator))
179                 *pstr++ = *pchr++;
180 
181             if ((pstr > path) && ((*(pstr - 1) != '/')))
182                 *pstr++ = '/';
183 
184             *pstr = '\0';
185 
186             strcat(path, pszName);
187 
188             if (access(path, 0) == 0)
189             {
190                 char szRealPathBuf[PATH_MAX] = "";
191 
192                 if( NULL == realpath(path, szRealPathBuf) || (strlen(szRealPathBuf) >= (sal_uInt32)Max))
193                     return osl_Process_E_Unknown;
194 
195                 strcpy(pszBuffer, path);
196 
197                 return osl_Process_E_None;
198             }
199 
200             if (*pchr == Separator)
201                 pchr++;
202         }
203     }
204 
205     return osl_Process_E_NotFound;
206 }
207 
208 /******************************************************************************
209  *
210  *                  New io resource transfer functions
211  *
212  *****************************************************************************/
213 
214 
215 /**********************************************
216  sendFdPipe
217  *********************************************/
218 
sendFdPipe(int PipeFD,int SocketFD)219 static sal_Bool sendFdPipe(int PipeFD, int SocketFD)
220 {
221     sal_Bool bRet = sal_False;
222 
223     struct iovec    iov[1];
224     struct msghdr   msg;
225     char            buf[2]; /* send_fd()/recv_fd() 2-byte protocol */
226     int nSend;
227     int RetCode=0;
228 
229 #if defined(IOCHANNEL_TRANSFER_BSD)
230 
231     OSL_TRACE("IOCHANNEL_TRANSFER_BSD send");
232 /*      OSL_TRACE("sending fd %i\n",SocketFD); */
233 
234     iov[0].iov_base = buf;
235     iov[0].iov_len  = sizeof(buf);
236     msg.msg_iov     = iov;
237     msg.msg_iovlen  = 1;
238     msg.msg_name    = NULL;
239     msg.msg_namelen = 0;
240 
241     msg.msg_accrights    = (caddr_t) &SocketFD; /* addr of descriptor */
242     msg.msg_accrightslen = sizeof(int);     /* pass 1 descriptor */
243     buf[1] = 0;                             /* zero status means OK */
244     buf[0] = 0;                             /* null byte flag to recv_fd() */
245 
246 #else
247 
248     struct cmsghdr* cmptr = (struct cmsghdr*)malloc(CONTROLLEN);
249 
250     OSL_TRACE("!!!!!! IOCHANNEL_TRANSFER_BSD_RENO send");
251 /*      OSL_TRACE("sending fd %i\n",SocketFD); */
252 
253     iov[0].iov_base = buf;
254     iov[0].iov_len = sizeof(buf);
255     msg.msg_iov = iov;
256     msg.msg_iovlen = 1;
257     msg.msg_name = NULL;
258     msg.msg_namelen = 0;
259     msg.msg_control = (caddr_t) cmptr;
260     msg.msg_controllen = CONTROLLEN;
261 
262     cmptr->cmsg_level = SOL_SOCKET;
263     cmptr->cmsg_type = SCM_RIGHTS;
264     cmptr->cmsg_len = CONTROLLEN;
265     memcpy(CMSG_DATA(cmptr), &SocketFD, sizeof(int));
266 
267 #endif
268 
269     if ( ( nSend = sendmsg(PipeFD, &msg, 0) ) > 0 )
270     {
271         bRet = sal_True;
272         OSL_TRACE("sendFdPipe : send '%i' bytes\n",nSend);
273 
274     }
275     else
276     {
277         OSL_TRACE("sendFdPipe : sending failed (%s)",strerror(errno));
278     }
279 
280     nSend=read(PipeFD,&RetCode,sizeof(RetCode));
281 
282     if ( nSend > 0 && RetCode == 1 )
283     {
284         OSL_TRACE("sendFdPipe : resource was received\n");
285     }
286     else
287     {
288         OSL_TRACE("sendFdPipe : resource wasn't received\n");
289     }
290 
291 #if defined(IOCHANNEL_TRANSFER_BSD_RENO)
292     free(cmptr);
293 #endif
294 
295     return bRet;
296 }
297 
298 /**********************************************
299  receiveFdPipe
300  *********************************************/
301 
receiveFdPipe(int PipeFD)302 static oslSocket receiveFdPipe(int PipeFD)
303 {
304     oslSocket pSocket = 0;
305     struct msghdr msghdr;
306     struct iovec iov[1];
307     char buffer[2];
308     sal_Int32 nRead;
309     int newfd=-1;
310     int nRetCode=0;
311 /*      char *ptr; */
312 
313 #if defined(IOCHANNEL_TRANSFER_BSD)
314 
315     OSL_TRACE("IOCHANNEL_TRANSFER_BSD receive\n");
316 
317     iov[0].iov_base = buffer;
318     iov[0].iov_len = sizeof(buffer);
319     msghdr.msg_name = NULL;
320     msghdr.msg_namelen = 0;
321     msghdr.msg_iov = iov;
322     msghdr.msg_iovlen = 1;
323     msghdr.msg_accrights = (caddr_t) &newfd; /* addr of descriptor   */
324     msghdr.msg_accrightslen = sizeof(int);   /* receive 1 descriptor */
325 
326 #else
327     struct cmsghdr* cmptr = (struct cmsghdr*)malloc(CONTROLLEN);
328 
329     OSL_TRACE(" !!!! IOCHANNEL_TRANSFER_BSD_RENO receive");
330 
331     iov[0].iov_base = buffer;
332     iov[0].iov_len = sizeof(buffer);
333     msghdr.msg_name = NULL;
334     msghdr.msg_namelen = 0;
335     msghdr.msg_iov = iov;
336     msghdr.msg_iovlen = 1;
337 
338     msghdr.msg_control = (caddr_t) cmptr;
339     msghdr.msg_controllen = CONTROLLEN;
340 
341 #endif
342 
343 
344 #if defined(IOCHANNEL_TRANSFER_BSD)
345 
346     if ( ( nRead = recvmsg(PipeFD, &msghdr, 0) ) > 0 )
347     {
348         OSL_TRACE("receiveFdPipe : received '%i' bytes\n",nRead);
349     }
350 #else
351 
352     if ( ( ( nRead = recvmsg(PipeFD, &msghdr, 0) ) > 0 ) &&
353          ( msghdr.msg_controllen == CONTROLLEN ) )
354     {
355         OSL_TRACE("receiveFdPipe : received '%i' bytes\n",nRead);
356         memcpy(&newfd, CMSG_DATA(cmptr), sizeof(int));
357     }
358 #endif
359     else
360     {
361         OSL_TRACE("receiveFdPipe : receiving failed (%s)",strerror(errno));
362     }
363 
364     if ( newfd >= 0 )
365     {
366         pSocket = __osl_createSocketImpl(newfd);
367         nRetCode=1;
368         OSL_TRACE("received fd %i\n",newfd);
369     }
370 
371     OSL_TRACE("receiveFdPipe : writing back %i",nRetCode);
372     nRead=write(PipeFD,&nRetCode,sizeof(nRetCode));
373 
374 #if defined(IOCHANNEL_TRANSFER_BSD_RENO)
375     free(cmptr);
376 #endif
377 
378     return pSocket;
379 }
380 
381 /**********************************************
382  osl_sendResourcePipe
383  *********************************************/
384 
osl_sendResourcePipe(oslPipe pPipe,oslSocket pSocket)385 sal_Bool osl_sendResourcePipe(oslPipe pPipe, oslSocket pSocket)
386 {
387     sal_Bool bRet = sal_False;
388 
389     if ( pSocket == 0 || pPipe == 0 )
390     {
391         return sal_False;
392     }
393 
394     bRet = sendFdPipe(pPipe->m_Socket,pSocket->m_Socket);
395 
396     return bRet;
397 }
398 
399 /**********************************************
400  osl_receiveResourcePipe
401  *********************************************/
402 
osl_receiveResourcePipe(oslPipe pPipe)403 oslSocket osl_receiveResourcePipe(oslPipe pPipe)
404 {
405     oslSocket pSocket=0;
406 
407     if ( pPipe ==  0 )
408     {
409         return 0;
410     }
411 
412     pSocket = receiveFdPipe(pPipe->m_Socket);
413 
414     return (oslSocket) pSocket;
415 }
416 
417 
418 
419 /******************************************************************************
420  *
421  *                  Functions for starting a process
422  *
423  *****************************************************************************/
424 
ChildStatusProc(void * pData)425 static void ChildStatusProc(void *pData)
426 {
427     pid_t pid = -1;
428     int   status = 0;
429     int   channel[2];
430     ProcessData  data;
431     ProcessData *pdata;
432     int     stdOutput[2] = { -1, -1 }, stdInput[2] = { -1, -1 }, stdError[2] = { -1, -1 };
433 
434     pdata = (ProcessData *)pData;
435 
436     /* make a copy of our data, because forking will only copy
437        our local stack of the thread, so the process data will not be accessible
438        in our child process */
439     memcpy(&data, pData, sizeof(data));
440 
441     if (socketpair(AF_UNIX, SOCK_STREAM, 0, channel) == -1)
442         status = errno;
443 
444     fcntl(channel[0], F_SETFD, FD_CLOEXEC);
445     fcntl(channel[1], F_SETFD, FD_CLOEXEC);
446 
447     /* Create redirected IO pipes */
448     if ( status == 0 && data.m_pInputWrite )
449         if (pipe( stdInput ) == -1)
450             status = errno;
451 
452     if ( status == 0 && data.m_pOutputRead )
453         if (pipe( stdOutput ) == -1)
454             status = errno;
455 
456     if ( status == 0 && data.m_pErrorRead )
457         if (pipe( stdError ) == -1)
458             status = errno;
459 
460     if ( (status == 0) && ((pid = fork()) == 0) )
461     {
462         /* Child */
463         int chstatus = 0;
464         sal_Int32 nWrote;
465 
466         if (channel[0] != -1) close(channel[0]);
467 
468         if ((data.m_uid != (uid_t)-1) && ((data.m_uid != getuid()) || (data.m_gid != getgid())))
469         {
470             OSL_ASSERT(geteuid() == 0);     /* must be root */
471 
472             if (! INIT_GROUPS(data.m_name, data.m_gid) || (setuid(data.m_uid) != 0))
473                 OSL_TRACE("Failed to change uid and guid, errno=%d (%s)\n", errno, strerror(errno));
474 #if defined(LINUX) || defined (FREEBSD)
475             unsetenv("HOME");
476 #else
477             putenv("HOME=");
478 #endif
479         }
480 
481         if (data.m_pszDir)
482             chstatus = chdir(data.m_pszDir);
483 
484         if (chstatus == 0 && ((data.m_uid == (uid_t)-1) || ((data.m_uid == getuid()) && (data.m_gid == getgid()))))
485         {
486             int i;
487             for (i = 0; data.m_pszEnv[i] != NULL; i++)
488             {
489                 if (strchr(data.m_pszEnv[i], '=') == NULL)
490                 {
491                     unsetenv(data.m_pszEnv[i]); /*TODO: check error return*/
492                 }
493                 else
494                 {
495                     putenv(data.m_pszEnv[i]); /*TODO: check error return*/
496                 }
497             }
498 
499             OSL_TRACE("ChildStatusProc : starting '%s'",data.m_pszArgs[0]);
500 
501             /* Connect std IO to pipe ends */
502 
503             /* Write end of stdInput not used in child process */
504             if (stdInput[1] != -1) close( stdInput[1] );
505 
506             /* Read end of stdOutput not used in child process */
507             if (stdOutput[0] != -1) close( stdOutput[0] );
508 
509             /* Read end of stdError not used in child process */
510             if (stdError[0] != -1) close( stdError[0] );
511 
512             /* Redirect pipe ends to std IO */
513 
514             if ( stdInput[0] != STDIN_FILENO )
515             {
516                 dup2( stdInput[0], STDIN_FILENO );
517                 if (stdInput[0] != -1) close( stdInput[0] );
518             }
519 
520             if ( stdOutput[1] != STDOUT_FILENO )
521             {
522                 dup2( stdOutput[1], STDOUT_FILENO );
523                 if (stdOutput[1] != -1) close( stdOutput[1] );
524             }
525 
526             if ( stdError[1] != STDERR_FILENO )
527             {
528                 dup2( stdError[1], STDERR_FILENO );
529                 if (stdError[1] != -1) close( stdError[1] );
530             }
531 
532             pid=execv(data.m_pszArgs[0], (sal_Char **)data.m_pszArgs);
533 
534         }
535 
536         OSL_TRACE("Failed to exec, errno=%d (%s)\n", errno, strerror(errno));
537 
538         OSL_TRACE("ChildStatusProc : starting '%s' failed",data.m_pszArgs[0]);
539 
540         /* if we reach here, something went wrong */
541         nWrote = write(channel[1], &errno, sizeof(errno));
542         if (nWrote != sizeof(errno))
543             OSL_TRACE("sendFdPipe : sending failed (%s)",strerror(errno));
544 
545         if (channel[1] != -1) close(channel[1]);
546 
547         _exit(255);
548     }
549     else
550     {   /* Parent  */
551         int i = -1;
552         if (channel[1] != -1) close(channel[1]);
553 
554         /* Close unused pipe ends */
555         if (stdInput[0] != -1) close( stdInput[0] );
556         if (stdOutput[1] != -1) close( stdOutput[1] );
557         if (stdError[1] != -1) close( stdError[1] );
558 
559         if (pid > 0)
560         {
561             while (((i = read(channel[0], &status, sizeof(status))) < 0))
562             {
563                 if (errno != EINTR)
564                     break;
565             }
566         }
567 
568         if (channel[0] != -1) close(channel[0]);
569 
570         if ((pid > 0) && (i == 0))
571         {
572             pid_t   child_pid;
573             osl_acquireMutex(ChildListMutex);
574 
575             pdata->m_pProcImpl->m_pid = pid;
576             pdata->m_pProcImpl->m_pnext = ChildList;
577             ChildList = pdata->m_pProcImpl;
578 
579             /* Store used pipe ends in data structure */
580 
581             if ( pdata->m_pInputWrite )
582                 *(pdata->m_pInputWrite) = osl_createFileHandleFromFD( stdInput[1] );
583 
584             if ( pdata->m_pOutputRead )
585                 *(pdata->m_pOutputRead) = osl_createFileHandleFromFD( stdOutput[0] );
586 
587             if ( pdata->m_pErrorRead )
588                 *(pdata->m_pErrorRead) = osl_createFileHandleFromFD( stdError[0] );
589 
590             osl_releaseMutex(ChildListMutex);
591 
592             osl_setCondition(pdata->m_started);
593 
594             do
595             {
596                 child_pid = waitpid(pid, &status, 0);
597             } while ( 0 > child_pid && EINTR == errno );
598 
599             if ( child_pid < 0)
600             {
601                 OSL_TRACE("Failed to wait for child process, errno=%d (%s)\n", errno, strerror(errno));
602 
603                 /*
604                 We got an other error than EINTR. Anyway we have to wake up the
605                 waiting thread under any circumstances */
606 
607                 child_pid = pid;
608             }
609 
610 
611             if ( child_pid > 0 )
612             {
613                 oslProcessImpl* pChild;
614 
615                 osl_acquireMutex(ChildListMutex);
616 
617                 pChild = ChildList;
618 
619                 /* check if it is one of our child processes */
620                 while (pChild != NULL)
621                 {
622                     if (pChild->m_pid == child_pid)
623                     {
624                         if (WIFEXITED(status))
625                             pChild->m_status = WEXITSTATUS(status);
626                         else
627                             pChild->m_status = -1;
628 
629                         osl_setCondition(pChild->m_terminated);
630                     }
631 
632                     pChild = pChild->m_pnext;
633                 }
634 
635                 osl_releaseMutex(ChildListMutex);
636             }
637         }
638         else
639         {
640             OSL_TRACE("ChildStatusProc : starting '%s' failed",data.m_pszArgs[0]);
641             OSL_TRACE("Failed to launch child process, child reports errno=%d (%s)\n", status, strerror(status));
642 
643             /* Close pipe ends */
644             if ( pdata->m_pInputWrite )
645                 *pdata->m_pInputWrite = NULL;
646 
647             if ( pdata->m_pOutputRead )
648                 *pdata->m_pOutputRead = NULL;
649 
650             if ( pdata->m_pErrorRead )
651                 *pdata->m_pErrorRead = NULL;
652 
653             if (stdInput[1] != -1) close( stdInput[1] );
654             if (stdOutput[0] != -1) close( stdOutput[0] );
655             if (stdError[0] != -1) close( stdError[0] );
656 
657             //if pid > 0 then a process was created, even if it later failed
658             //e.g. bash searching for a command to execute, and we still
659             //need to clean it up to avoid "defunct" processes
660             if (pid > 0)
661             {
662                 pid_t child_pid;
663                 do
664                 {
665                     child_pid = waitpid(pid, &status, 0);
666                 } while ( 0 > child_pid && EINTR == errno );
667             }
668 
669             /* notify (and unblock) parent thread */
670             osl_setCondition(pdata->m_started);
671         }
672     }
673 }
674 
675 /**********************************************
676  osl_executeProcess_WithRedirectedIO
677  *********************************************/
678 
osl_executeProcess_WithRedirectedIO(rtl_uString * ustrImageName,rtl_uString * ustrArguments[],sal_uInt32 nArguments,oslProcessOption Options,oslSecurity Security,rtl_uString * ustrWorkDir,rtl_uString * ustrEnvironment[],sal_uInt32 nEnvironmentVars,oslProcess * pProcess,oslFileHandle * pInputWrite,oslFileHandle * pOutputRead,oslFileHandle * pErrorRead)679 oslProcessError SAL_CALL osl_executeProcess_WithRedirectedIO(
680                                             rtl_uString *ustrImageName,
681                                             rtl_uString *ustrArguments[],
682                                             sal_uInt32   nArguments,
683                                             oslProcessOption Options,
684                                             oslSecurity Security,
685                                             rtl_uString *ustrWorkDir,
686                                             rtl_uString *ustrEnvironment[],
687                                             sal_uInt32   nEnvironmentVars,
688                                             oslProcess *pProcess,
689                                             oslFileHandle   *pInputWrite,
690                                             oslFileHandle   *pOutputRead,
691                                             oslFileHandle   *pErrorRead
692                                             )
693 {
694 
695     oslProcessError Error;
696     sal_Char* pszWorkDir=0;
697     sal_Char** pArguments=0;
698     sal_Char** pEnvironment=0;
699     unsigned int idx;
700 
701     char szImagePath[PATH_MAX] = "";
702     char szWorkDir[PATH_MAX] = "";
703 
704     if ( ustrImageName && ustrImageName->length )
705     {
706         FileURLToPath( szImagePath, PATH_MAX, ustrImageName );
707     }
708 
709     if ( ustrWorkDir != 0 && ustrWorkDir->length )
710     {
711         FileURLToPath( szWorkDir, PATH_MAX, ustrWorkDir );
712         pszWorkDir = szWorkDir;
713     }
714 
715     if ( pArguments == 0 && nArguments > 0 )
716     {
717         pArguments = (sal_Char**) malloc( ( nArguments + 2 ) * sizeof(sal_Char*) );
718     }
719 
720 
721     for ( idx = 0 ; idx < nArguments ; ++idx )
722     {
723         rtl_String* strArg =0;
724 
725 
726         rtl_uString2String( &strArg,
727                             rtl_uString_getStr(ustrArguments[idx]),
728                             rtl_uString_getLength(ustrArguments[idx]),
729                             osl_getThreadTextEncoding(),
730                             OUSTRING_TO_OSTRING_CVTFLAGS );
731 
732         pArguments[idx]=strdup(rtl_string_getStr(strArg));
733         rtl_string_release(strArg);
734         pArguments[idx+1]=0;
735     }
736 
737     for ( idx = 0 ; idx < nEnvironmentVars ; ++idx )
738     {
739         rtl_String* strEnv=0;
740 
741         if ( pEnvironment == 0 )
742         {
743             pEnvironment = (sal_Char**) malloc( ( nEnvironmentVars + 2 ) * sizeof(sal_Char*) );
744         }
745 
746         rtl_uString2String( &strEnv,
747                             rtl_uString_getStr(ustrEnvironment[idx]),
748                             rtl_uString_getLength(ustrEnvironment[idx]),
749                             osl_getThreadTextEncoding(),
750                             OUSTRING_TO_OSTRING_CVTFLAGS );
751 
752         pEnvironment[idx]=strdup(rtl_string_getStr(strEnv));
753         rtl_string_release(strEnv);
754         pEnvironment[idx+1]=0;
755     }
756 
757 
758     Error = osl_psz_executeProcess(szImagePath,
759                                    pArguments,
760                                    Options,
761                                    Security,
762                                    pszWorkDir,
763                                    pEnvironment,
764                                    pProcess,
765                                    pInputWrite,
766                                    pOutputRead,
767                                    pErrorRead
768                                    );
769 
770     if ( pArguments != 0 )
771     {
772         for ( idx = 0 ; idx < nArguments ; ++idx )
773         {
774             if ( pArguments[idx] != 0 )
775             {
776                 free(pArguments[idx]);
777             }
778         }
779         free(pArguments);
780     }
781 
782     if ( pEnvironment != 0 )
783     {
784         for ( idx = 0 ; idx < nEnvironmentVars ; ++idx )
785         {
786             if ( pEnvironment[idx] != 0 )
787             {
788                 free(pEnvironment[idx]);
789             }
790         }
791         free(pEnvironment);
792     }
793 
794     return Error;
795 }
796 
797 /**********************************************
798  osl_executeProcess
799  *********************************************/
800 
osl_executeProcess(rtl_uString * ustrImageName,rtl_uString * ustrArguments[],sal_uInt32 nArguments,oslProcessOption Options,oslSecurity Security,rtl_uString * ustrWorkDir,rtl_uString * ustrEnvironment[],sal_uInt32 nEnvironmentVars,oslProcess * pProcess)801 oslProcessError SAL_CALL osl_executeProcess(
802                                             rtl_uString *ustrImageName,
803                                             rtl_uString *ustrArguments[],
804                                             sal_uInt32   nArguments,
805                                             oslProcessOption Options,
806                                             oslSecurity Security,
807                                             rtl_uString *ustrWorkDir,
808                                             rtl_uString *ustrEnvironment[],
809                                             sal_uInt32   nEnvironmentVars,
810                                             oslProcess *pProcess
811                                             )
812 {
813     return osl_executeProcess_WithRedirectedIO(
814         ustrImageName,
815         ustrArguments,
816         nArguments,
817         Options,
818         Security,
819         ustrWorkDir,
820         ustrEnvironment,
821         nEnvironmentVars,
822         pProcess,
823         NULL,
824         NULL,
825         NULL
826         );
827 }
828 
829 /**********************************************
830  osl_psz_executeProcess
831  *********************************************/
832 
osl_psz_executeProcess(sal_Char * pszImageName,sal_Char * pszArguments[],oslProcessOption Options,oslSecurity Security,sal_Char * pszDirectory,sal_Char * pszEnvironments[],oslProcess * pProcess,oslFileHandle * pInputWrite,oslFileHandle * pOutputRead,oslFileHandle * pErrorRead)833 oslProcessError SAL_CALL osl_psz_executeProcess(sal_Char *pszImageName,
834                                                 sal_Char *pszArguments[],
835                                                 oslProcessOption Options,
836                                                 oslSecurity Security,
837                                                 sal_Char *pszDirectory,
838                                                 sal_Char *pszEnvironments[],
839                                                 oslProcess *pProcess,
840                                                 oslFileHandle   *pInputWrite,
841                                                 oslFileHandle   *pOutputRead,
842                                                 oslFileHandle   *pErrorRead
843                                                 )
844 {
845     int     i;
846     sal_Char    path[PATH_MAX + 1];
847     ProcessData Data;
848     oslThread hThread;
849 
850     path[0] = '\0';
851 
852     memset(&Data,0,sizeof(ProcessData));
853     Data.m_pInputWrite = pInputWrite;
854     Data.m_pOutputRead = pOutputRead;
855     Data.m_pErrorRead = pErrorRead;
856 
857     if (pszImageName == NULL)
858         pszImageName = pszArguments[0];
859 
860     OSL_ASSERT(pszImageName != NULL);
861 
862     if ( pszImageName == 0 )
863     {
864         return osl_Process_E_NotFound;
865     }
866 
867     if ((Options & osl_Process_SEARCHPATH) &&
868         (osl_searchPath_impl(pszImageName, NULL, '\0', path, sizeof(path)) == osl_Process_E_None))
869         pszImageName = path;
870 
871     Data.m_pszArgs[0] = strdup(pszImageName);
872     Data.m_pszArgs[1] = 0;
873 
874     if ( pszArguments != 0 )
875     {
876         for (i = 0; ((i + 2) < MAX_ARGS) && (pszArguments[i] != NULL); i++)
877             Data.m_pszArgs[i+1] = strdup(pszArguments[i]);
878         Data.m_pszArgs[i+2] = NULL;
879     }
880 
881     Data.m_options = Options;
882     Data.m_pszDir  = (pszDirectory != NULL) ? strdup(pszDirectory) : NULL;
883 
884     if (pszEnvironments != NULL)
885     {
886         for (i = 0; ((i + 1) < MAX_ENVS) &&  (pszEnvironments[i] != NULL); i++)
887             Data.m_pszEnv[i] = strdup(pszEnvironments[i]);
888         Data.m_pszEnv[i+1] = NULL;
889     }
890     else
891         Data.m_pszEnv[0] = NULL;
892 
893     if (Security != NULL)
894     {
895         Data.m_uid  = ((oslSecurityImpl*)Security)->m_pPasswd.pw_uid;
896         Data.m_gid  = ((oslSecurityImpl*)Security)->m_pPasswd.pw_gid;
897         Data.m_name = ((oslSecurityImpl*)Security)->m_pPasswd.pw_name;
898     }
899     else
900         Data.m_uid = (uid_t)-1;
901 
902     Data.m_pProcImpl = (oslProcessImpl*) malloc(sizeof(oslProcessImpl));
903     Data.m_pProcImpl->m_pid = 0;
904     Data.m_pProcImpl->m_terminated = osl_createCondition();
905     Data.m_pProcImpl->m_pnext = NULL;
906 
907     if (ChildListMutex == NULL)
908         ChildListMutex = osl_createMutex();
909 
910     Data.m_started = osl_createCondition();
911 
912     hThread = osl_createThread(ChildStatusProc, &Data);
913 
914     osl_waitCondition(Data.m_started, NULL);
915     osl_destroyCondition(Data.m_started);
916 
917     for (i = 0; Data.m_pszArgs[i] != NULL; i++)
918           free((void *)Data.m_pszArgs[i]);
919 
920     for (i = 0; Data.m_pszEnv[i] != NULL; i++)
921           free((void *)Data.m_pszEnv[i]);
922 
923     if ( Data.m_pszDir != 0 )
924     {
925         free((void *)Data.m_pszDir);
926     }
927 
928     osl_destroyThread(hThread);
929 
930     if (Data.m_pProcImpl->m_pid != 0)
931     {
932         *pProcess = Data.m_pProcImpl;
933 
934         if (Options & osl_Process_WAIT)
935             osl_joinProcess(*pProcess);
936 
937         return osl_Process_E_None;
938     }
939 
940     osl_destroyCondition(Data.m_pProcImpl->m_terminated);
941     free(Data.m_pProcImpl);
942 
943     return osl_Process_E_Unknown;
944 }
945 
946 
947 /******************************************************************************
948  *
949  *                  Functions for processes
950  *
951  *****************************************************************************/
952 
953 
954 /**********************************************
955  osl_terminateProcess
956  *********************************************/
957 
osl_terminateProcess(oslProcess Process)958 oslProcessError SAL_CALL osl_terminateProcess(oslProcess Process)
959 {
960     if (Process == NULL)
961         return osl_Process_E_Unknown;
962 
963     if (kill(((oslProcessImpl*)Process)->m_pid, SIGKILL) != 0)
964     {
965         switch (errno)
966         {
967             case EPERM:
968                 return osl_Process_E_NoPermission;
969 
970             case ESRCH:
971                 return osl_Process_E_NotFound;
972 
973             default:
974                 return osl_Process_E_Unknown;
975         }
976     }
977 
978     return osl_Process_E_None;
979 }
980 
981 /**********************************************
982  osl_getProcess
983  *********************************************/
984 
osl_getProcess(oslProcessIdentifier Ident)985 oslProcess SAL_CALL osl_getProcess(oslProcessIdentifier Ident)
986 {
987     oslProcessImpl *pProcImpl;
988 
989     if (kill(Ident, 0) != -1)
990     {
991         oslProcessImpl* pChild;
992 
993         if (ChildListMutex == NULL)
994             ChildListMutex = osl_createMutex();
995 
996         osl_acquireMutex(ChildListMutex);
997 
998         pChild = ChildList;
999 
1000         /* check if it is one of our child processes */
1001         while (pChild != NULL)
1002         {
1003             if (Ident == (sal_uInt32) pChild->m_pid)
1004                 break;
1005 
1006             pChild = pChild->m_pnext;
1007         }
1008 
1009         pProcImpl = (oslProcessImpl*) malloc(sizeof(oslProcessImpl));
1010         pProcImpl->m_pid        = Ident;
1011         pProcImpl->m_terminated = osl_createCondition();
1012 
1013         if (pChild != NULL)
1014         {
1015             /* process is a child so insert into list */
1016             pProcImpl->m_pnext = pChild->m_pnext;
1017             pChild->m_pnext = pProcImpl;
1018 
1019             pProcImpl->m_status = pChild->m_status;
1020 
1021             if (osl_checkCondition(pChild->m_terminated))
1022                 osl_setCondition(pProcImpl->m_terminated);
1023         }
1024         else
1025             pProcImpl->m_pnext = NULL;
1026 
1027         osl_releaseMutex(ChildListMutex);
1028     }
1029     else
1030         pProcImpl = NULL;
1031 
1032     return (pProcImpl);
1033 }
1034 
1035 /**********************************************
1036  osl_freeProcessHandle
1037  *********************************************/
1038 
osl_freeProcessHandle(oslProcess Process)1039 void SAL_CALL osl_freeProcessHandle(oslProcess Process)
1040 {
1041     if (Process != NULL)
1042     {
1043         oslProcessImpl *pChild, *pPrev = NULL;
1044 
1045         OSL_ASSERT(ChildListMutex != NULL);
1046 
1047         if ( ChildListMutex == 0 )
1048         {
1049             return;
1050         }
1051 
1052         osl_acquireMutex(ChildListMutex);
1053 
1054         pChild = ChildList;
1055 
1056         /* remove process from child list */
1057         while (pChild != NULL)
1058         {
1059             if (pChild == (oslProcessImpl*)Process)
1060             {
1061                 if (pPrev != NULL)
1062                     pPrev->m_pnext = pChild->m_pnext;
1063                 else
1064                     ChildList = pChild->m_pnext;
1065 
1066                 break;
1067             }
1068 
1069             pPrev  = pChild;
1070             pChild = pChild->m_pnext;
1071         }
1072 
1073         osl_releaseMutex(ChildListMutex);
1074 
1075         osl_destroyCondition(((oslProcessImpl*)Process)->m_terminated);
1076 
1077         free(Process);
1078     }
1079 }
1080 
1081 #if defined(LINUX)
1082 struct osl_procStat
1083 {
1084    /* from 'stat' */
1085     pid_t pid;                /* pid */
1086     char command[16];         /* 'argv[0]' */ /* mfe: it all right char comm[16] in kernel! */
1087     char state;               /* state (running, stopped, ...) */
1088     pid_t ppid;               /* parent pid */
1089     pid_t pgrp;               /* parent group */
1090     int session;              /* session ID */
1091     int tty;                  /* no of tty */
1092     pid_t tpgid;              /* group of process owning the tty */
1093     unsigned long flags;      /* flags dunno */
1094     unsigned long minflt;     /* minor page faults */
1095     unsigned long cminflt;    /* minor page faults with children */
1096     unsigned long majflt;     /* major page faults */
1097     unsigned long cmajflt;    /* major page faults with children */
1098     unsigned long utime;      /* no of jiffies in user mode */
1099     unsigned long stime;      /* no of jiffies in kernel mode */
1100     unsigned long cutime;     /* no of jiffies in user mode with children */
1101     unsigned long cstime;     /* no of jiffies in kernel mode with children */
1102     unsigned long priority;   /* nice value + 15 (kernel scheduling prio)*/
1103     long nice;                /* nice value */
1104     long timeout;             /* no of jiffies of next process timeout */
1105     long itrealvalue;         /* no jiffies before next SIGALRM */
1106     unsigned long starttime;  /* process started this no of jiffies after boot */
1107     unsigned long vsize;      /* virtual memory size (in bytes) */
1108     long rss;                 /* resident set size (in pages) */
1109     unsigned long rss_rlim;   /* rss limit (in bytes) */
1110     unsigned long startcode;   /* address above program text can run */
1111     unsigned long endcode;    /* address below program text can run */
1112     unsigned long startstack; /* address of start of stack */
1113     unsigned long kstkesp;    /* current value of 'esp' (stack pointer) */
1114     unsigned long kstkeip;    /* current value of 'eip' (instruction pointer) */
1115     /* mfe: Linux > 2.1.7x have more signals (88) */
1116 /*#ifdef LINUX */
1117     char signal[24];          /* pending signals */
1118     char blocked[24];         /* blocked signals */
1119     char sigignore[24];       /* ignored signals */
1120     char sigcatch[24];        /* catched signals */
1121 /*#else*/
1122 /*  long long signal;*/
1123 /*  long long blocked;*/
1124 /*  long long sigignore;*/
1125 /*  long long sigcatch;*/
1126 /*#endif */
1127     unsigned long wchan;      /* 'channel' the process is waiting in */
1128     unsigned long nswap;      /* ? */
1129     unsigned long cnswap;     /* ? */
1130 
1131     /* from 'status' */
1132     int ruid;                 /* real uid */
1133     int euid;                 /* effective uid */
1134     int suid;                 /* saved uid */
1135     int fuid;                 /* file access uid */
1136     int rgid;                 /* real gid */
1137     int egid;                 /* effective gid */
1138     int sgid;                 /* saved gid */
1139     int fgid;                 /* file access gid */
1140     unsigned long vm_size;    /* like vsize but on kb */
1141     unsigned long vm_lock;    /* locked pages in kb */
1142     unsigned long vm_rss;     /* like rss but in kb */
1143     unsigned long vm_data;    /* data size */
1144     unsigned long vm_stack;   /* stack size */
1145     unsigned long vm_exe;     /* executable size */
1146     unsigned long vm_lib;     /* library size */
1147 };
1148 
1149 /**********************************************
1150  osl_getProcStat
1151  *********************************************/
1152 
osl_getProcStat(pid_t pid,struct osl_procStat * procstat)1153 sal_Bool osl_getProcStat(pid_t pid, struct osl_procStat* procstat)
1154 {
1155     int fd = 0;
1156     sal_Bool bRet = sal_False;
1157     char name[PATH_MAX + 1];
1158     snprintf(name, sizeof(name), "/proc/%u/stat", pid);
1159 
1160     if ((fd = open(name,O_RDONLY)) >=0 )
1161     {
1162         char* tmp=0;
1163         char prstatbuf[512];
1164         memset(prstatbuf,0,512);
1165         bRet = read(fd,prstatbuf,511) == 511;
1166 
1167         close(fd);
1168         /*printf("%s\n\n",prstatbuf);*/
1169 
1170         if (!bRet)
1171             return sal_False;
1172 
1173         tmp = strrchr(prstatbuf, ')');
1174         *tmp = '\0';
1175         memset(procstat->command, 0, sizeof(procstat->command));
1176 
1177         sscanf(prstatbuf, "%d (%15c", &procstat->pid, procstat->command);
1178         sscanf(tmp + 2,
1179                "%c"
1180                "%i %i %i %i %i"
1181                "%lu %lu %lu %lu %lu"
1182                "%lu %lu %lu %lu"
1183                "%lu %li %li %li"
1184                "%lu %lu %li %lu"
1185                "%lu %lu %lu %lu %lu"
1186                "%s %s %s %s"
1187                "%lu %lu %lu",
1188                &procstat->state,
1189                &procstat->ppid,      &procstat->pgrp,    &procstat->session,    &procstat->tty,         &procstat->tpgid,
1190                &procstat->flags,     &procstat->minflt,  &procstat->cminflt,    &procstat->majflt,      &procstat->cmajflt,
1191                &procstat->utime,     &procstat->stime,   &procstat->cutime,     &procstat->cstime,
1192                &procstat->priority,  &procstat->nice,    &procstat->timeout,    &procstat->itrealvalue,
1193                &procstat->starttime, &procstat->vsize,   &procstat->rss,        &procstat->rss_rlim,
1194                &procstat->startcode, &procstat->endcode, &procstat->startstack, &procstat->kstkesp,     &procstat->kstkeip,
1195                procstat->signal,     procstat->blocked,  procstat->sigignore,   procstat->sigcatch,
1196                &procstat->wchan,     &procstat->nswap,   &procstat->cnswap
1197             );
1198     }
1199     return bRet;
1200 }
1201 
1202 /**********************************************
1203  osl_getProcStatus
1204  *********************************************/
1205 
osl_getProcStatus(pid_t pid,struct osl_procStat * procstat)1206 sal_Bool osl_getProcStatus(pid_t pid, struct osl_procStat* procstat)
1207 {
1208     int fd = 0;
1209     char name[PATH_MAX + 1];
1210     snprintf(name, sizeof(name), "/proc/%u/status", pid);
1211 
1212     sal_Bool bRet = sal_False;
1213 
1214     if ((fd = open(name,O_RDONLY)) >=0 )
1215     {
1216         char* tmp=0;
1217         char prstatusbuf[512];
1218         memset(prstatusbuf,0,512);
1219         bRet = read(fd,prstatusbuf,511) == 511;
1220 
1221         close(fd);
1222 
1223         /*      printf("\n\n%s\n\n",prstatusbuf);*/
1224 
1225         if (!bRet)
1226             return sal_False;
1227 
1228         tmp = strstr(prstatusbuf,"Uid:");
1229         if(tmp)
1230         {
1231             sscanf(tmp,"Uid:\t%d\t%d\t%d\t%d",
1232                    &procstat->ruid, &procstat->euid, &procstat->suid, &procstat->fuid
1233                 );
1234         }
1235 
1236 
1237         tmp = strstr(prstatusbuf,"Gid:");
1238         if(tmp)
1239         {
1240             sscanf(tmp,"Gid:\t%d\t%d\t%d\t%d",
1241                    &procstat->rgid, &procstat->egid, &procstat->sgid, &procstat->fgid
1242                 );
1243         }
1244 
1245         tmp = strstr(prstatusbuf,"VmSize:");
1246         if(tmp)
1247         {
1248             sscanf(tmp,
1249                    "VmSize: %lu kB\n"
1250                    "VmLck: %lu kB\n"
1251                    "VmRSS: %lu kB\n"
1252                    "VmData: %lu kB\n"
1253                    "VmStk: %lu kB\n"
1254                    "VmExe: %lu kB\n"
1255                    "VmLib: %lu kB\n",
1256                    &procstat->vm_size, &procstat->vm_lock, &procstat->vm_rss, &procstat->vm_data,
1257                    &procstat->vm_stack, &procstat->vm_exe, &procstat->vm_lib
1258                 );
1259         }
1260 
1261         tmp = strstr(prstatusbuf,"SigPnd:");
1262         if(tmp)
1263         {
1264             sscanf(tmp, "SigPnd: %s SigBlk: %s SigIgn: %s %*s %s",
1265                    procstat->signal, procstat->blocked, procstat->sigignore, procstat->sigcatch
1266                 );
1267         }
1268     }
1269     return bRet;
1270 }
1271 
1272 #endif
1273 
1274 /**********************************************
1275  osl_getProcessInfo
1276  *********************************************/
1277 
osl_getProcessInfo(oslProcess Process,oslProcessData Fields,oslProcessInfo * pInfo)1278 oslProcessError SAL_CALL osl_getProcessInfo(oslProcess Process, oslProcessData Fields, oslProcessInfo* pInfo)
1279 {
1280     pid_t   pid;
1281 
1282     if (Process == NULL)
1283         pid = getpid();
1284     else
1285         pid = ((oslProcessImpl*)Process)->m_pid;
1286 
1287     if (! pInfo || (pInfo->Size != sizeof(oslProcessInfo)))
1288         return osl_Process_E_Unknown;
1289 
1290     pInfo->Fields = 0;
1291 
1292     if (Fields & osl_Process_IDENTIFIER)
1293     {
1294         pInfo->Ident  = pid;
1295         pInfo->Fields |= osl_Process_IDENTIFIER;
1296     }
1297 
1298     if (Fields & osl_Process_EXITCODE)
1299     {
1300         if ((Process != NULL) &&
1301             osl_checkCondition(((oslProcessImpl*)Process)->m_terminated))
1302         {
1303             pInfo->Code = ((oslProcessImpl*)Process)->m_status;
1304             pInfo->Fields |= osl_Process_EXITCODE;
1305         }
1306     }
1307 
1308     if (Fields & (osl_Process_HEAPUSAGE | osl_Process_CPUTIMES))
1309     {
1310 
1311 #if defined(SOLARIS)
1312 
1313         int  fd;
1314         sal_Char name[PATH_MAX + 1];
1315 
1316         snprintf(name, sizeof(name), "/proc/%u", pid);
1317 
1318         if ((fd = open(name, O_RDONLY)) >= 0)
1319         {
1320             prstatus_t prstatus;
1321 
1322             if (ioctl(fd, PIOCSTATUS, &prstatus) >= 0)
1323             {
1324                 if (Fields & osl_Process_CPUTIMES)
1325                 {
1326                     pInfo->UserTime.Seconds   = prstatus.pr_utime.tv_sec;
1327                     pInfo->UserTime.Nanosec   = prstatus.pr_utime.tv_nsec;
1328                     pInfo->SystemTime.Seconds = prstatus.pr_stime.tv_sec;
1329                     pInfo->SystemTime.Nanosec = prstatus.pr_stime.tv_nsec;
1330 
1331                     pInfo->Fields |= osl_Process_CPUTIMES;
1332                 }
1333 
1334                 if (Fields & osl_Process_HEAPUSAGE)
1335                 {
1336                     pInfo->HeapUsage = prstatus.pr_brksize;
1337 
1338                     pInfo->Fields |= osl_Process_HEAPUSAGE;
1339                 }
1340 
1341                 close(fd);
1342 
1343                 return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown;
1344             }
1345             else
1346                 close(fd);
1347         }
1348 
1349 #elif defined(HPUX)
1350 
1351         struct pst_status prstatus;
1352 
1353         if (pstat_getproc(&prstatus, sizeof(prstatus), (size_t)0, pid) == 1)
1354         {
1355             if (Fields & osl_Process_CPUTIMES)
1356             {
1357                 pInfo->UserTime.Seconds   = prstatus.pst_utime;
1358                 pInfo->UserTime.Nanosec   = 500000L;
1359                 pInfo->SystemTime.Seconds = prstatus.pst_stime;
1360                 pInfo->SystemTime.Nanosec = 500000L;
1361 
1362                 pInfo->Fields |= osl_Process_CPUTIMES;
1363             }
1364 
1365             if (Fields & osl_Process_HEAPUSAGE)
1366             {
1367                 pInfo->HeapUsage = prstatus.pst_vdsize*PAGESIZE;
1368 
1369                 pInfo->Fields |= osl_Process_HEAPUSAGE;
1370             }
1371 
1372             return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown;
1373         }
1374 
1375 #elif defined(LINUX)
1376 
1377         if ( (Fields & osl_Process_CPUTIMES) || (Fields & osl_Process_HEAPUSAGE) )
1378         {
1379             struct osl_procStat procstat;
1380             memset(&procstat,0,sizeof(procstat));
1381 
1382             if ( (Fields & osl_Process_CPUTIMES) && osl_getProcStat(pid, &procstat) )
1383             {
1384                 /*
1385                  *  mfe:
1386                  *  We calculate only time of the process proper.
1387                  *  Threads are processes, we do not consider their time here!
1388                  *  (For this, cutime and cstime should be used, it seems not
1389                  *   to work in 2.0.36)
1390                  */
1391 
1392                 long clktck;
1393                 unsigned long hz;
1394                 unsigned long userseconds;
1395                 unsigned long systemseconds;
1396 
1397                 clktck = sysconf(_SC_CLK_TCK);
1398                 if (clktck < 0) {
1399                     return osl_Process_E_Unknown;
1400                 }
1401                 hz = (unsigned long) clktck;
1402 
1403                 userseconds = procstat.utime/hz;
1404                 systemseconds = procstat.stime/hz;
1405 
1406                 pInfo->UserTime.Seconds   = userseconds;
1407                 pInfo->UserTime.Nanosec   = procstat.utime - (userseconds * hz);
1408                 pInfo->SystemTime.Seconds = systemseconds;
1409                 pInfo->SystemTime.Nanosec = procstat.stime - (systemseconds * hz);
1410 
1411                 pInfo->Fields |= osl_Process_CPUTIMES;
1412             }
1413 
1414             if ( (Fields & osl_Process_HEAPUSAGE) && osl_getProcStatus(pid, &procstat) )
1415             {
1416                 /*
1417                  *  mfe:
1418                  *  vm_data (found in status) shows the size of the data segment
1419                  *  it a rough approximation of the core heap size
1420                  */
1421                 pInfo->HeapUsage = procstat.vm_data*1024;
1422 
1423                 pInfo->Fields |= osl_Process_HEAPUSAGE;
1424             }
1425         }
1426 
1427         return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown;
1428 #endif
1429 
1430     }
1431 
1432     return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown;
1433 }
1434 
1435 
1436 /***********************************************
1437  helper function for osl_joinProcessWithTimeout
1438  **********************************************/
1439 
is_timeout(const struct timeval * tend)1440 static int is_timeout(const struct timeval* tend)
1441 {
1442     struct timeval tcurrent;
1443     gettimeofday(&tcurrent, NULL);
1444     return (tcurrent.tv_sec >= tend->tv_sec);
1445 }
1446 
1447 /**********************************************
1448  kill(pid, 0) is usefull for checking if a
1449  process is still alive, but remember that
1450  kill even returns 0 if the process is already
1451  a zombie.
1452  *********************************************/
1453 
is_process_dead(pid_t pid)1454 static int is_process_dead(pid_t pid)
1455 {
1456     return ((-1 == kill(pid, 0)) && (ESRCH == errno));
1457 }
1458 
1459 /**********************************************
1460  osl_joinProcessWithTimeout
1461  *********************************************/
1462 
osl_joinProcessWithTimeout(oslProcess Process,const TimeValue * pTimeout)1463 oslProcessError SAL_CALL osl_joinProcessWithTimeout(oslProcess Process, const TimeValue* pTimeout)
1464 {
1465     oslProcessImpl* pChild    = ChildList;
1466     oslProcessError osl_error = osl_Process_E_None;
1467 
1468     OSL_PRECOND(Process, "osl_joinProcess: Invalid parameter");
1469     OSL_ASSERT(ChildListMutex);
1470 
1471     if (NULL == Process || 0 == ChildListMutex)
1472         return osl_Process_E_Unknown;
1473 
1474     osl_acquireMutex(ChildListMutex);
1475 
1476     /* check if process is a child of ours */
1477     while (pChild != NULL)
1478     {
1479         if (pChild == (oslProcessImpl*)Process)
1480             break;
1481 
1482         pChild = pChild->m_pnext;
1483     }
1484 
1485     osl_releaseMutex(ChildListMutex);
1486 
1487     if (pChild != NULL)
1488     {
1489         oslConditionResult cond_res = osl_waitCondition(pChild->m_terminated, pTimeout);
1490 
1491         if (osl_cond_result_timeout == cond_res)
1492             osl_error = osl_Process_E_TimedOut;
1493         else if (osl_cond_result_ok != cond_res)
1494             osl_error = osl_Process_E_Unknown;
1495     }
1496     else /* alien process; StatusThread will not be able
1497             to set the condition terminated */
1498     {
1499         pid_t pid = ((oslProcessImpl*)Process)->m_pid;
1500 
1501         if (pTimeout)
1502         {
1503             int timeout = 0;
1504             struct timeval tend;
1505 
1506             gettimeofday(&tend, NULL);
1507 
1508             tend.tv_sec += pTimeout->Seconds;
1509 
1510             while (!is_process_dead(pid) && ((timeout = is_timeout(&tend)) == 0))
1511                 sleep(1);
1512 
1513             if (timeout)
1514                 osl_error = osl_Process_E_TimedOut;
1515         }
1516         else /* infinite */
1517         {
1518             while (!is_process_dead(pid))
1519                 sleep(1);
1520         }
1521     }
1522     return osl_error;
1523 }
1524 
1525 /**********************************************
1526  osl_joinProcess
1527  *********************************************/
1528 
osl_joinProcess(oslProcess Process)1529 oslProcessError SAL_CALL osl_joinProcess(oslProcess Process)
1530 {
1531     return osl_joinProcessWithTimeout(Process, NULL);
1532 }
1533