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