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