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