1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "sal/config.h"
21 #include "rtl/ustring.hxx"
27 * - cleanup of process status things
28 * - cleanup of process spawning
29 * - cleanup of resource transfer
33 // The procfs may only be used without LFS in 32bits.
34 # ifdef _FILE_OFFSET_BITS
35 # undef _FILE_OFFSET_BITS
40 #if defined(FREEBSD) || defined(NETBSD) || defined(DRAGONFLY)
41 #include <machine/param.h>
46 # include <sys/procfs.h>
48 #include <osl/diagnose.h>
49 #include <osl/mutex.h>
50 #include <osl/conditn.h>
51 #include <osl/thread.h>
53 #include <osl/signal.h>
54 #include <rtl/alloc.h>
55 #include <sal/log.hxx>
59 #include "createfilehandlefromfd.hxx"
62 #include "readwrite_helper.h"
74 const sal_Char
* m_pszArgs
[MAX_ARGS
+ 1];
75 oslProcessOption m_options
;
76 const sal_Char
* m_pszDir
;
77 sal_Char
* m_pszEnv
[MAX_ENVS
+ 1];
81 oslCondition m_started
;
82 oslProcessImpl
* m_pProcImpl
;
83 oslFileHandle
*m_pInputWrite
;
84 oslFileHandle
*m_pOutputRead
;
85 oslFileHandle
*m_pErrorRead
;
88 static oslProcessImpl
* ChildList
;
89 static oslMutex ChildListMutex
;
91 /******************************************************************************
93 Old and buggy implementation of osl_searchPath used only by
94 osl_psz_executeProcess.
95 A new implemenation is in file_path_helper.cxx
96 *****************************************************************************/
98 static oslProcessError SAL_CALL
osl_searchPath_impl(const sal_Char
* pszName
,
99 sal_Char
*pszBuffer
, sal_uInt32 Max
)
101 sal_Char path
[PATH_MAX
+ 1];
106 OSL_ASSERT(pszName
!= NULL
);
110 return osl_Process_E_NotFound
;
113 if ( (pchr
= getenv("PATH")) != 0 )
117 while (*pchr
!= '\0')
121 while ((*pchr
!= '\0') && (*pchr
!= ':'))
124 if ((pstr
> path
) && ((*(pstr
- 1) != '/')))
129 strcat(path
, pszName
);
131 if (access(path
, 0) == 0)
133 char szRealPathBuf
[PATH_MAX
] = "";
135 if( NULL
== realpath(path
, szRealPathBuf
) || (strlen(szRealPathBuf
) >= (sal_uInt32
)Max
))
136 return osl_Process_E_Unknown
;
138 strcpy(pszBuffer
, path
);
140 return osl_Process_E_None
;
148 return osl_Process_E_NotFound
;
151 } //Anonymous namespace
153 oslProcessError SAL_CALL
osl_psz_executeProcess(sal_Char
*pszImageName
,
154 sal_Char
*pszArguments
[],
155 oslProcessOption Options
,
156 oslSecurity Security
,
157 sal_Char
*pszDirectory
,
158 sal_Char
*pszEnvironments
[],
159 oslProcess
*pProcess
,
160 oslFileHandle
*pInputWrite
,
161 oslFileHandle
*pOutputRead
,
162 oslFileHandle
*pErrorRead
);
164 /******************************************************************************
166 * New io resource transfer functions
168 *****************************************************************************/
171 sal_Bool
osl_sendResourcePipe(oslPipe
/*pPipe*/, oslSocket
/*pSocket*/)
173 return osl_Process_E_InvalidError
;
176 oslSocket
osl_receiveResourcePipe(oslPipe
/*pPipe*/)
178 oslSocket pSocket
= 0;
184 /******************************************************************************
186 * Functions for starting a process
188 *****************************************************************************/
192 static void ChildStatusProc(void *pData
)
196 int channel
[2] = { -1, -1 };
199 int stdOutput
[2] = { -1, -1 }, stdInput
[2] = { -1, -1 }, stdError
[2] = { -1, -1 };
201 pdata
= (ProcessData
*)pData
;
203 /* make a copy of our data, because forking will only copy
204 our local stack of the thread, so the process data will not be accessible
205 in our child process */
206 memcpy(&data
, pData
, sizeof(data
));
208 #ifdef NO_CHILD_PROCESSES
209 #define fork() (errno = EINVAL, -1)
211 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, channel
) == -1)
214 SAL_WARN("sal.osl", "executeProcess socketpair() errno " << status
);
217 fcntl(channel
[0], F_SETFD
, FD_CLOEXEC
);
218 fcntl(channel
[1], F_SETFD
, FD_CLOEXEC
);
220 /* Create redirected IO pipes */
221 if ( status
== 0 && data
.m_pInputWrite
&& pipe( stdInput
) == -1 )
225 SAL_WARN("sal.osl", "executeProcess pipe(stdInput) errno " << status
);
228 if ( status
== 0 && data
.m_pOutputRead
&& pipe( stdOutput
) == -1 )
232 SAL_WARN("sal.osl", "executeProcess pipe(stdOutput) errno " << status
);
235 if ( status
== 0 && data
.m_pErrorRead
&& pipe( stdError
) == -1 )
239 SAL_WARN("sal.osl", "executeProcess pipe(stdError) errno " << status
);
242 if ( (status
== 0) && ((pid
= fork()) == 0) )
248 if (channel
[0] != -1) close(channel
[0]);
250 if ((data
.m_uid
!= (uid_t
)-1) && ((data
.m_uid
!= getuid()) || (data
.m_gid
!= getgid())))
252 OSL_ASSERT(geteuid() == 0); /* must be root */
254 if (! INIT_GROUPS(data
.m_name
, data
.m_gid
) || (setuid(data
.m_uid
) != 0))
255 OSL_TRACE("Failed to change uid and guid, errno=%d (%s)", errno
, strerror(errno
));
257 const rtl::OUString
envVar("HOME");
258 osl_clearEnvironment(envVar
.pData
);
262 chstatus
= chdir(data
.m_pszDir
);
264 if (chstatus
== 0 && ((data
.m_uid
== (uid_t
)-1) || ((data
.m_uid
== getuid()) && (data
.m_gid
== getgid()))))
267 for (i
= 0; data
.m_pszEnv
[i
] != NULL
; i
++)
269 if (strchr(data
.m_pszEnv
[i
], '=') == NULL
)
271 unsetenv(data
.m_pszEnv
[i
]); /*TODO: check error return*/
275 putenv(data
.m_pszEnv
[i
]); /*TODO: check error return*/
279 OSL_TRACE("ChildStatusProc : starting '%s'",data
.m_pszArgs
[0]);
281 /* Connect std IO to pipe ends */
283 /* Write end of stdInput not used in child process */
284 if (stdInput
[1] != -1) close( stdInput
[1] );
286 /* Read end of stdOutput not used in child process */
287 if (stdOutput
[0] != -1) close( stdOutput
[0] );
289 /* Read end of stdError not used in child process */
290 if (stdError
[0] != -1) close( stdError
[0] );
292 /* Redirect pipe ends to std IO */
294 if ( stdInput
[0] != STDIN_FILENO
)
296 dup2( stdInput
[0], STDIN_FILENO
);
297 if (stdInput
[0] != -1) close( stdInput
[0] );
300 if ( stdOutput
[1] != STDOUT_FILENO
)
302 dup2( stdOutput
[1], STDOUT_FILENO
);
303 if (stdOutput
[1] != -1) close( stdOutput
[1] );
306 if ( stdError
[1] != STDERR_FILENO
)
308 dup2( stdError
[1], STDERR_FILENO
);
309 if (stdError
[1] != -1) close( stdError
[1] );
312 // No need to check the return value of execv. If we return from
313 // it, an error has occurred.
314 execv(data
.m_pszArgs
[0], (sal_Char
**)data
.m_pszArgs
);
317 OSL_TRACE("Failed to exec, errno=%d (%s)", errno
, strerror(errno
));
319 OSL_TRACE("ChildStatusProc : starting '%s' failed",data
.m_pszArgs
[0]);
321 /* if we reach here, something went wrong */
323 if ( !safeWrite(channel
[1], &errno_copy
, sizeof(errno_copy
)) )
324 OSL_TRACE("sendFdPipe : sending failed (%s)",strerror(errno
));
326 if ( channel
[1] != -1 )
334 if (channel
[1] != -1) close(channel
[1]);
336 /* Close unused pipe ends */
337 if (stdInput
[0] != -1) close( stdInput
[0] );
338 if (stdOutput
[1] != -1) close( stdOutput
[1] );
339 if (stdError
[1] != -1) close( stdError
[1] );
343 while (((i
= read(channel
[0], &status
, sizeof(status
))) < 0))
350 if (channel
[0] != -1) close(channel
[0]);
352 if ((pid
> 0) && (i
== 0))
355 osl_acquireMutex(ChildListMutex
);
357 pdata
->m_pProcImpl
->m_pid
= pid
;
358 pdata
->m_pProcImpl
->m_pnext
= ChildList
;
359 ChildList
= pdata
->m_pProcImpl
;
361 /* Store used pipe ends in data structure */
363 if ( pdata
->m_pInputWrite
)
364 *(pdata
->m_pInputWrite
) = osl::detail::createFileHandleFromFD( stdInput
[1] );
366 if ( pdata
->m_pOutputRead
)
367 *(pdata
->m_pOutputRead
) = osl::detail::createFileHandleFromFD( stdOutput
[0] );
369 if ( pdata
->m_pErrorRead
)
370 *(pdata
->m_pErrorRead
) = osl::detail::createFileHandleFromFD( stdError
[0] );
372 osl_releaseMutex(ChildListMutex
);
374 osl_setCondition(pdata
->m_started
);
378 child_pid
= waitpid(pid
, &status
, 0);
379 } while ( 0 > child_pid
&& EINTR
== errno
);
383 OSL_TRACE("Failed to wait for child process, errno=%d (%s)", errno
, strerror(errno
));
386 We got an other error than EINTR. Anyway we have to wake up the
387 waiting thread under any circumstances */
395 oslProcessImpl
* pChild
;
397 osl_acquireMutex(ChildListMutex
);
401 /* check if it is one of our child processes */
402 while (pChild
!= NULL
)
404 if (pChild
->m_pid
== child_pid
)
406 if (WIFEXITED(status
))
407 pChild
->m_status
= WEXITSTATUS(status
);
408 else if (WIFSIGNALED(status
))
409 pChild
->m_status
= 128 + WTERMSIG(status
);
411 pChild
->m_status
= -1;
413 osl_setCondition(pChild
->m_terminated
);
416 pChild
= pChild
->m_pnext
;
419 osl_releaseMutex(ChildListMutex
);
424 OSL_TRACE("ChildStatusProc : starting '%s' failed",data
.m_pszArgs
[0]);
425 OSL_TRACE("Failed to launch child process, child reports errno=%d (%s)", status
, strerror(status
));
427 /* Close pipe ends */
428 if ( pdata
->m_pInputWrite
)
429 *pdata
->m_pInputWrite
= NULL
;
431 if ( pdata
->m_pOutputRead
)
432 *pdata
->m_pOutputRead
= NULL
;
434 if ( pdata
->m_pErrorRead
)
435 *pdata
->m_pErrorRead
= NULL
;
437 if (stdInput
[1] != -1) close( stdInput
[1] );
438 if (stdOutput
[0] != -1) close( stdOutput
[0] );
439 if (stdError
[0] != -1) close( stdError
[0] );
441 //if pid > 0 then a process was created, even if it later failed
442 //e.g. bash searching for a command to execute, and we still
443 //need to clean it up to avoid "defunct" processes
449 child_pid
= waitpid(pid
, &status
, 0);
450 } while ( 0 > child_pid
&& EINTR
== errno
);
453 /* notify (and unblock) parent thread */
454 osl_setCondition(pdata
->m_started
);
461 oslProcessError SAL_CALL
osl_executeProcess_WithRedirectedIO(
462 rtl_uString
*ustrImageName
,
463 rtl_uString
*ustrArguments
[],
464 sal_uInt32 nArguments
,
465 oslProcessOption Options
,
466 oslSecurity Security
,
467 rtl_uString
*ustrWorkDir
,
468 rtl_uString
*ustrEnvironment
[],
469 sal_uInt32 nEnvironmentVars
,
470 oslProcess
*pProcess
,
471 oslFileHandle
*pInputWrite
,
472 oslFileHandle
*pOutputRead
,
473 oslFileHandle
*pErrorRead
477 oslProcessError Error
;
478 sal_Char
* pszWorkDir
=0;
479 sal_Char
** pArguments
=0;
480 sal_Char
** pEnvironment
=0;
483 char szImagePath
[PATH_MAX
] = "";
484 char szWorkDir
[PATH_MAX
] = "";
486 if ( ustrImageName
&& ustrImageName
->length
)
488 FileURLToPath( szImagePath
, PATH_MAX
, ustrImageName
);
491 if ( ustrWorkDir
!= 0 && ustrWorkDir
->length
)
493 FileURLToPath( szWorkDir
, PATH_MAX
, ustrWorkDir
);
494 pszWorkDir
= szWorkDir
;
497 if ( pArguments
== 0 && nArguments
> 0 )
499 pArguments
= (sal_Char
**) malloc( ( nArguments
+ 2 ) * sizeof(sal_Char
*) );
503 for ( idx
= 0 ; idx
< nArguments
; ++idx
)
505 rtl_String
* strArg
=0;
508 rtl_uString2String( &strArg
,
509 rtl_uString_getStr(ustrArguments
[idx
]),
510 rtl_uString_getLength(ustrArguments
[idx
]),
511 osl_getThreadTextEncoding(),
512 OUSTRING_TO_OSTRING_CVTFLAGS
);
514 pArguments
[idx
]=strdup(rtl_string_getStr(strArg
));
515 rtl_string_release(strArg
);
519 for ( idx
= 0 ; idx
< nEnvironmentVars
; ++idx
)
521 rtl_String
* strEnv
=0;
523 if ( pEnvironment
== 0 )
525 pEnvironment
= (sal_Char
**) malloc( ( nEnvironmentVars
+ 2 ) * sizeof(sal_Char
*) );
528 rtl_uString2String( &strEnv
,
529 rtl_uString_getStr(ustrEnvironment
[idx
]),
530 rtl_uString_getLength(ustrEnvironment
[idx
]),
531 osl_getThreadTextEncoding(),
532 OUSTRING_TO_OSTRING_CVTFLAGS
);
534 pEnvironment
[idx
]=strdup(rtl_string_getStr(strEnv
));
535 rtl_string_release(strEnv
);
536 pEnvironment
[idx
+1]=0;
540 Error
= osl_psz_executeProcess(szImagePath
,
552 if ( pArguments
!= 0 )
554 for ( idx
= 0 ; idx
< nArguments
; ++idx
)
556 if ( pArguments
[idx
] != 0 )
558 free(pArguments
[idx
]);
564 if ( pEnvironment
!= 0 )
566 for ( idx
= 0 ; idx
< nEnvironmentVars
; ++idx
)
568 if ( pEnvironment
[idx
] != 0 )
570 free(pEnvironment
[idx
]);
579 oslProcessError SAL_CALL
osl_executeProcess(
580 rtl_uString
*ustrImageName
,
581 rtl_uString
*ustrArguments
[],
582 sal_uInt32 nArguments
,
583 oslProcessOption Options
,
584 oslSecurity Security
,
585 rtl_uString
*ustrWorkDir
,
586 rtl_uString
*ustrEnvironment
[],
587 sal_uInt32 nEnvironmentVars
,
591 return osl_executeProcess_WithRedirectedIO(
607 oslProcessError SAL_CALL
osl_psz_executeProcess(sal_Char
*pszImageName
,
608 sal_Char
*pszArguments
[],
609 oslProcessOption Options
,
610 oslSecurity Security
,
611 sal_Char
*pszDirectory
,
612 sal_Char
*pszEnvironments
[],
613 oslProcess
*pProcess
,
614 oslFileHandle
*pInputWrite
,
615 oslFileHandle
*pOutputRead
,
616 oslFileHandle
*pErrorRead
620 sal_Char path
[PATH_MAX
+ 1];
626 memset(&Data
,0,sizeof(ProcessData
));
627 Data
.m_pInputWrite
= pInputWrite
;
628 Data
.m_pOutputRead
= pOutputRead
;
629 Data
.m_pErrorRead
= pErrorRead
;
631 if (pszImageName
== NULL
)
632 pszImageName
= pszArguments
[0];
634 OSL_ASSERT(pszImageName
!= NULL
);
636 if ( pszImageName
== 0 )
638 return osl_Process_E_NotFound
;
641 if ((Options
& osl_Process_SEARCHPATH
) &&
642 (osl_searchPath_impl(pszImageName
, path
, sizeof(path
)) == osl_Process_E_None
))
645 Data
.m_pszArgs
[0] = strdup(pszImageName
);
646 Data
.m_pszArgs
[1] = 0;
648 if ( pszArguments
!= 0 )
650 for (i
= 0; ((i
+ 2) < MAX_ARGS
) && (pszArguments
[i
] != NULL
); i
++)
651 Data
.m_pszArgs
[i
+1] = strdup(pszArguments
[i
]);
652 Data
.m_pszArgs
[i
+2] = NULL
;
655 Data
.m_options
= Options
;
656 Data
.m_pszDir
= (pszDirectory
!= NULL
) ? strdup(pszDirectory
) : NULL
;
658 if (pszEnvironments
!= NULL
)
660 for (i
= 0; ((i
+ 1) < MAX_ENVS
) && (pszEnvironments
[i
] != NULL
); i
++)
661 Data
.m_pszEnv
[i
] = strdup(pszEnvironments
[i
]);
662 Data
.m_pszEnv
[i
+1] = NULL
;
665 Data
.m_pszEnv
[0] = NULL
;
667 if (Security
!= NULL
)
669 Data
.m_uid
= ((oslSecurityImpl
*)Security
)->m_pPasswd
.pw_uid
;
670 Data
.m_gid
= ((oslSecurityImpl
*)Security
)->m_pPasswd
.pw_gid
;
671 Data
.m_name
= ((oslSecurityImpl
*)Security
)->m_pPasswd
.pw_name
;
674 Data
.m_uid
= (uid_t
)-1;
676 Data
.m_pProcImpl
= (oslProcessImpl
*) malloc(sizeof(oslProcessImpl
));
677 Data
.m_pProcImpl
->m_pid
= 0;
678 Data
.m_pProcImpl
->m_terminated
= osl_createCondition();
679 Data
.m_pProcImpl
->m_pnext
= NULL
;
681 if (ChildListMutex
== NULL
)
682 ChildListMutex
= osl_createMutex();
684 Data
.m_started
= osl_createCondition();
686 hThread
= osl_createThread(ChildStatusProc
, &Data
);
688 osl_waitCondition(Data
.m_started
, NULL
);
689 osl_destroyCondition(Data
.m_started
);
691 for (i
= 0; Data
.m_pszArgs
[i
] != NULL
; i
++)
692 free((void *)Data
.m_pszArgs
[i
]);
694 for (i
= 0; Data
.m_pszEnv
[i
] != NULL
; i
++)
695 free((void *)Data
.m_pszEnv
[i
]);
697 if ( Data
.m_pszDir
!= 0 )
699 free((void *)Data
.m_pszDir
);
702 osl_destroyThread(hThread
);
704 if (Data
.m_pProcImpl
->m_pid
!= 0)
706 *pProcess
= Data
.m_pProcImpl
;
708 if (Options
& osl_Process_WAIT
)
709 osl_joinProcess(*pProcess
);
711 return osl_Process_E_None
;
714 osl_destroyCondition(Data
.m_pProcImpl
->m_terminated
);
715 free(Data
.m_pProcImpl
);
717 return osl_Process_E_Unknown
;
720 /******************************************************************************
722 * Functions for processes
724 *****************************************************************************/
727 oslProcessError SAL_CALL
osl_terminateProcess(oslProcess Process
)
730 return osl_Process_E_Unknown
;
732 if (kill(((oslProcessImpl
*)Process
)->m_pid
, SIGKILL
) != 0)
737 return osl_Process_E_NoPermission
;
740 return osl_Process_E_NotFound
;
743 return osl_Process_E_Unknown
;
747 return osl_Process_E_None
;
750 oslProcess SAL_CALL
osl_getProcess(oslProcessIdentifier Ident
)
752 oslProcessImpl
*pProcImpl
;
754 if (kill(Ident
, 0) != -1)
756 oslProcessImpl
* pChild
;
758 if (ChildListMutex
== NULL
)
759 ChildListMutex
= osl_createMutex();
761 osl_acquireMutex(ChildListMutex
);
765 /* check if it is one of our child processes */
766 while (pChild
!= NULL
)
768 if (Ident
== (sal_uInt32
) pChild
->m_pid
)
771 pChild
= pChild
->m_pnext
;
774 pProcImpl
= (oslProcessImpl
*) malloc(sizeof(oslProcessImpl
));
775 pProcImpl
->m_pid
= Ident
;
776 pProcImpl
->m_terminated
= osl_createCondition();
780 /* process is a child so insert into list */
781 pProcImpl
->m_pnext
= pChild
->m_pnext
;
782 pChild
->m_pnext
= pProcImpl
;
784 pProcImpl
->m_status
= pChild
->m_status
;
786 if (osl_checkCondition(pChild
->m_terminated
))
787 osl_setCondition(pProcImpl
->m_terminated
);
790 pProcImpl
->m_pnext
= NULL
;
792 osl_releaseMutex(ChildListMutex
);
800 void SAL_CALL
osl_freeProcessHandle(oslProcess Process
)
804 oslProcessImpl
*pChild
, *pPrev
= NULL
;
806 OSL_ASSERT(ChildListMutex
!= NULL
);
808 if ( ChildListMutex
== 0 )
813 osl_acquireMutex(ChildListMutex
);
817 /* remove process from child list */
818 while (pChild
!= NULL
)
820 if (pChild
== (oslProcessImpl
*)Process
)
823 pPrev
->m_pnext
= pChild
->m_pnext
;
825 ChildList
= pChild
->m_pnext
;
831 pChild
= pChild
->m_pnext
;
834 osl_releaseMutex(ChildListMutex
);
836 osl_destroyCondition(((oslProcessImpl
*)Process
)->m_terminated
);
847 char command
[16]; /* 'argv[0]' */ /* mfe: it all right char comm[16] in kernel! */
848 char state
; /* state (running, stopped, ...) */
849 pid_t ppid
; /* parent pid */
850 pid_t pgrp
; /* parent group */
851 int session
; /* session ID */
852 int tty
; /* no of tty */
853 pid_t tpgid
; /* group of process owning the tty */
854 unsigned long flags
; /* flags dunno */
855 unsigned long minflt
; /* minor page faults */
856 unsigned long cminflt
; /* minor page faults with children */
857 unsigned long majflt
; /* major page faults */
858 unsigned long cmajflt
; /* major page faults with children */
859 unsigned long utime
; /* no of jiffies in user mode */
860 unsigned long stime
; /* no of jiffies in kernel mode */
861 unsigned long cutime
; /* no of jiffies in user mode with children */
862 unsigned long cstime
; /* no of jiffies in kernel mode with children */
863 unsigned long priority
; /* nice value + 15 (kernel scheduling prio)*/
864 long nice
; /* nice value */
865 long timeout
; /* no of jiffies of next process timeout */
866 long itrealvalue
; /* no jiffies before next SIGALRM */
867 unsigned long starttime
; /* process started this no of jiffies after boot */
868 unsigned long vsize
; /* virtual memory size (in bytes) */
869 long rss
; /* resident set size (in pages) */
870 unsigned long rss_rlim
; /* rss limit (in bytes) */
871 unsigned long startcode
; /* address above program text can run */
872 unsigned long endcode
; /* address below program text can run */
873 unsigned long startstack
; /* address of start of stack */
874 unsigned long kstkesp
; /* current value of 'esp' (stack pointer) */
875 unsigned long kstkeip
; /* current value of 'eip' (instruction pointer) */
876 /* mfe: Linux > 2.1.7x have more signals (88) */
877 char signal
[24]; /* pending signals */
878 char blocked
[24]; /* blocked signals */
879 char sigignore
[24]; /* ignored signals */
880 char sigcatch
[24]; /* catched signals */
881 unsigned long wchan
; /* 'channel' the process is waiting in */
882 unsigned long nswap
; /* ? */
883 unsigned long cnswap
; /* ? */
886 int ruid
; /* real uid */
887 int euid
; /* effective uid */
888 int suid
; /* saved uid */
889 int fuid
; /* file access uid */
890 int rgid
; /* real gid */
891 int egid
; /* effective gid */
892 int sgid
; /* saved gid */
893 int fgid
; /* file access gid */
894 unsigned long vm_size
; /* like vsize but on kb */
895 unsigned long vm_lock
; /* locked pages in kb */
896 unsigned long vm_rss
; /* like rss but in kb */
897 unsigned long vm_data
; /* data size */
898 unsigned long vm_stack
; /* stack size */
899 unsigned long vm_exe
; /* executable size */
900 unsigned long vm_lib
; /* library size */
903 sal_Bool
osl_getProcStat(pid_t pid
, struct osl_procStat
* procstat
)
906 sal_Bool bRet
= sal_False
;
907 char name
[PATH_MAX
+ 1];
908 snprintf(name
, sizeof(name
), "/proc/%u/stat", pid
);
910 if ((fd
= open(name
,O_RDONLY
)) >=0 )
914 memset(prstatbuf
,0,512);
915 bRet
= safeRead(fd
, prstatbuf
, 511);
922 tmp
= strrchr(prstatbuf
, ')');
924 memset(procstat
->command
, 0, sizeof(procstat
->command
));
926 sscanf(prstatbuf
, "%d (%15c", &procstat
->pid
, procstat
->command
);
930 "%lu %lu %lu %lu %lu"
934 "%lu %lu %lu %lu %lu"
938 &procstat
->ppid
, &procstat
->pgrp
, &procstat
->session
, &procstat
->tty
, &procstat
->tpgid
,
939 &procstat
->flags
, &procstat
->minflt
, &procstat
->cminflt
, &procstat
->majflt
, &procstat
->cmajflt
,
940 &procstat
->utime
, &procstat
->stime
, &procstat
->cutime
, &procstat
->cstime
,
941 &procstat
->priority
, &procstat
->nice
, &procstat
->timeout
, &procstat
->itrealvalue
,
942 &procstat
->starttime
, &procstat
->vsize
, &procstat
->rss
, &procstat
->rss_rlim
,
943 &procstat
->startcode
, &procstat
->endcode
, &procstat
->startstack
, &procstat
->kstkesp
, &procstat
->kstkeip
,
944 procstat
->signal
, procstat
->blocked
, procstat
->sigignore
, procstat
->sigcatch
,
945 &procstat
->wchan
, &procstat
->nswap
, &procstat
->cnswap
951 sal_Bool
osl_getProcStatus(pid_t pid
, struct osl_procStat
* procstat
)
954 char name
[PATH_MAX
+ 1];
955 sal_Bool bRet
= sal_False
;
957 snprintf(name
, sizeof(name
), "/proc/%u/status", pid
);
959 if ((fd
= open(name
,O_RDONLY
)) >=0 )
962 char prstatusbuf
[512];
963 memset(prstatusbuf
,0,512);
964 bRet
= safeRead(fd
, prstatusbuf
, 511);
971 tmp
= strstr(prstatusbuf
,"Uid:");
974 sscanf(tmp
,"Uid:\t%d\t%d\t%d\t%d",
975 &procstat
->ruid
, &procstat
->euid
, &procstat
->suid
, &procstat
->fuid
980 tmp
= strstr(prstatusbuf
,"Gid:");
983 sscanf(tmp
,"Gid:\t%d\t%d\t%d\t%d",
984 &procstat
->rgid
, &procstat
->egid
, &procstat
->sgid
, &procstat
->fgid
988 tmp
= strstr(prstatusbuf
,"VmSize:");
999 &procstat
->vm_size
, &procstat
->vm_lock
, &procstat
->vm_rss
, &procstat
->vm_data
,
1000 &procstat
->vm_stack
, &procstat
->vm_exe
, &procstat
->vm_lib
1004 tmp
= strstr(prstatusbuf
,"SigPnd:");
1007 sscanf(tmp
, "SigPnd: %s SigBlk: %s SigIgn: %s %*s %s",
1008 procstat
->signal
, procstat
->blocked
, procstat
->sigignore
, procstat
->sigcatch
1017 oslProcessError SAL_CALL
osl_getProcessInfo(oslProcess Process
, oslProcessData Fields
, oslProcessInfo
* pInfo
)
1021 if (Process
== NULL
)
1024 pid
= ((oslProcessImpl
*)Process
)->m_pid
;
1026 if (! pInfo
|| (pInfo
->Size
!= sizeof(oslProcessInfo
)))
1027 return osl_Process_E_Unknown
;
1031 if (Fields
& osl_Process_IDENTIFIER
)
1034 pInfo
->Fields
|= osl_Process_IDENTIFIER
;
1037 if (Fields
& osl_Process_EXITCODE
)
1039 if ((Process
!= NULL
) &&
1040 osl_checkCondition(((oslProcessImpl
*)Process
)->m_terminated
))
1042 pInfo
->Code
= ((oslProcessImpl
*)Process
)->m_status
;
1043 pInfo
->Fields
|= osl_Process_EXITCODE
;
1047 if (Fields
& (osl_Process_HEAPUSAGE
| osl_Process_CPUTIMES
))
1050 #if defined(SOLARIS)
1053 sal_Char name
[PATH_MAX
+ 1];
1055 snprintf(name
, sizeof(name
), "/proc/%u", pid
);
1057 if ((fd
= open(name
, O_RDONLY
)) >= 0)
1059 prstatus_t prstatus
;
1061 if (ioctl(fd
, PIOCSTATUS
, &prstatus
) >= 0)
1063 if (Fields
& osl_Process_CPUTIMES
)
1065 pInfo
->UserTime
.Seconds
= prstatus
.pr_utime
.tv_sec
;
1066 pInfo
->UserTime
.Nanosec
= prstatus
.pr_utime
.tv_nsec
;
1067 pInfo
->SystemTime
.Seconds
= prstatus
.pr_stime
.tv_sec
;
1068 pInfo
->SystemTime
.Nanosec
= prstatus
.pr_stime
.tv_nsec
;
1070 pInfo
->Fields
|= osl_Process_CPUTIMES
;
1073 if (Fields
& osl_Process_HEAPUSAGE
)
1075 pInfo
->HeapUsage
= prstatus
.pr_brksize
;
1077 pInfo
->Fields
|= osl_Process_HEAPUSAGE
;
1082 return (pInfo
->Fields
== Fields
) ? osl_Process_E_None
: osl_Process_E_Unknown
;
1088 #elif defined(LINUX)
1090 if ( (Fields
& osl_Process_CPUTIMES
) || (Fields
& osl_Process_HEAPUSAGE
) )
1092 struct osl_procStat procstat
;
1093 memset(&procstat
,0,sizeof(procstat
));
1095 if ( (Fields
& osl_Process_CPUTIMES
) && osl_getProcStat(pid
, &procstat
) )
1099 * We calculate only time of the process proper.
1100 * Threads are processes, we do not consider their time here!
1101 * (For this, cutime and cstime should be used, it seems not
1102 * to work in 2.0.36)
1107 unsigned long userseconds
;
1108 unsigned long systemseconds
;
1110 clktck
= sysconf(_SC_CLK_TCK
);
1112 return osl_Process_E_Unknown
;
1114 hz
= (unsigned long) clktck
;
1116 userseconds
= procstat
.utime
/hz
;
1117 systemseconds
= procstat
.stime
/hz
;
1119 pInfo
->UserTime
.Seconds
= userseconds
;
1120 pInfo
->UserTime
.Nanosec
= procstat
.utime
- (userseconds
* hz
);
1121 pInfo
->SystemTime
.Seconds
= systemseconds
;
1122 pInfo
->SystemTime
.Nanosec
= procstat
.stime
- (systemseconds
* hz
);
1124 pInfo
->Fields
|= osl_Process_CPUTIMES
;
1127 if ( (Fields
& osl_Process_HEAPUSAGE
) && osl_getProcStatus(pid
, &procstat
) )
1131 * vm_data (found in status) shows the size of the data segment
1132 * it a rough approximation of the core heap size
1134 pInfo
->HeapUsage
= procstat
.vm_data
*1024;
1136 pInfo
->Fields
|= osl_Process_HEAPUSAGE
;
1140 return (pInfo
->Fields
== Fields
) ? osl_Process_E_None
: osl_Process_E_Unknown
;
1145 return (pInfo
->Fields
== Fields
) ? osl_Process_E_None
: osl_Process_E_Unknown
;
1149 /***********************************************
1150 helper function for osl_joinProcessWithTimeout
1151 **********************************************/
1153 static int is_timeout(const struct timeval
* tend
)
1155 struct timeval tcurrent
;
1156 gettimeofday(&tcurrent
, NULL
);
1157 return (tcurrent
.tv_sec
>= tend
->tv_sec
);
1160 /**********************************************
1161 kill(pid, 0) is useful for checking if a
1162 process is still alive, but remember that
1163 kill even returns 0 if the process is already
1165 *********************************************/
1167 static int is_process_dead(pid_t pid
)
1169 return ((-1 == kill(pid
, 0)) && (ESRCH
== errno
));
1172 /**********************************************
1173 osl_joinProcessWithTimeout
1174 *********************************************/
1176 oslProcessError SAL_CALL
osl_joinProcessWithTimeout(oslProcess Process
, const TimeValue
* pTimeout
)
1178 oslProcessImpl
* pChild
= ChildList
;
1179 oslProcessError osl_error
= osl_Process_E_None
;
1181 OSL_PRECOND(Process
, "osl_joinProcess: Invalid parameter");
1182 OSL_ASSERT(ChildListMutex
);
1184 if (NULL
== Process
|| 0 == ChildListMutex
)
1185 return osl_Process_E_Unknown
;
1187 osl_acquireMutex(ChildListMutex
);
1189 /* check if process is a child of ours */
1190 while (pChild
!= NULL
)
1192 if (pChild
== (oslProcessImpl
*)Process
)
1195 pChild
= pChild
->m_pnext
;
1198 osl_releaseMutex(ChildListMutex
);
1202 oslConditionResult cond_res
= osl_waitCondition(pChild
->m_terminated
, pTimeout
);
1204 if (osl_cond_result_timeout
== cond_res
)
1205 osl_error
= osl_Process_E_TimedOut
;
1206 else if (osl_cond_result_ok
!= cond_res
)
1207 osl_error
= osl_Process_E_Unknown
;
1209 else /* alien process; StatusThread will not be able
1210 to set the condition terminated */
1212 pid_t pid
= ((oslProcessImpl
*)Process
)->m_pid
;
1217 struct timeval tend
;
1219 gettimeofday(&tend
, NULL
);
1221 tend
.tv_sec
+= pTimeout
->Seconds
;
1223 while (!is_process_dead(pid
) && ((timeout
= is_timeout(&tend
)) == 0))
1227 osl_error
= osl_Process_E_TimedOut
;
1231 while (!is_process_dead(pid
))
1238 oslProcessError SAL_CALL
osl_joinProcess(oslProcess Process
)
1240 return osl_joinProcessWithTimeout(Process
, NULL
);
1243 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */