xref: /aoo42x/main/sal/osl/unx/process.c (revision cdf0e10c)
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