xref: /trunk/main/sal/osl/unx/process.c (revision 86e1cf34)
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 useful 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 
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 
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 
1529 oslProcessError SAL_CALL osl_joinProcess(oslProcess Process)
1530 {
1531     return osl_joinProcessWithTimeout(Process, NULL);
1532 }
1533