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
39 #if defined(FREEBSD) || defined(NETBSD) || defined(DRAGONFLY)
40 #include <machine/param.h>
45 # include <sys/procfs.h>
47 #include <osl/diagnose.h>
48 #include <osl/mutex.h>
49 #include <osl/conditn.h>
50 #include <osl/thread.h>
52 #include <osl/signal.h>
53 #include <rtl/alloc.h>
54 #include <sal/log.hxx>
58 #include "createfilehandlefromfd.hxx"
61 #include "readwrite_helper.h"
73 const sal_Char
* m_pszArgs
[MAX_ARGS
+ 1];
74 oslProcessOption m_options
;
75 const sal_Char
* m_pszDir
;
76 sal_Char
* m_pszEnv
[MAX_ENVS
+ 1];
80 oslCondition m_started
;
81 oslProcessImpl
* m_pProcImpl
;
82 oslFileHandle
*m_pInputWrite
;
83 oslFileHandle
*m_pOutputRead
;
84 oslFileHandle
*m_pErrorRead
;
87 static oslProcessImpl
* ChildList
;
88 static oslMutex ChildListMutex
;
90 /******************************************************************************
92 Old and buggy implementation of osl_searchPath used only by
93 osl_psz_executeProcess.
94 A new implemenation is in file_path_helper.cxx
95 *****************************************************************************/
97 static oslProcessError SAL_CALL
osl_searchPath_impl(const sal_Char
* pszName
,
98 sal_Char
*pszBuffer
, sal_uInt32 Max
)
100 sal_Char path
[PATH_MAX
+ 1];
105 OSL_ASSERT(pszName
!= NULL
);
109 return osl_Process_E_NotFound
;
112 if ( (pchr
= getenv("PATH")) != 0 )
116 while (*pchr
!= '\0')
120 while ((*pchr
!= '\0') && (*pchr
!= ':'))
123 if ((pstr
> path
) && ((*(pstr
- 1) != '/')))
128 strcat(path
, pszName
);
130 if (access(path
, 0) == 0)
132 char szRealPathBuf
[PATH_MAX
] = "";
134 if( NULL
== realpath(path
, szRealPathBuf
) || (strlen(szRealPathBuf
) >= (sal_uInt32
)Max
))
135 return osl_Process_E_Unknown
;
137 strcpy(pszBuffer
, path
);
139 return osl_Process_E_None
;
147 return osl_Process_E_NotFound
;
150 } //Anonymous namespace
152 oslProcessError SAL_CALL
osl_psz_executeProcess(sal_Char
*pszImageName
,
153 sal_Char
*pszArguments
[],
154 oslProcessOption Options
,
155 oslSecurity Security
,
156 sal_Char
*pszDirectory
,
157 sal_Char
*pszEnvironments
[],
158 oslProcess
*pProcess
,
159 oslFileHandle
*pInputWrite
,
160 oslFileHandle
*pOutputRead
,
161 oslFileHandle
*pErrorRead
);
163 /******************************************************************************
165 * New io resource transfer functions
167 *****************************************************************************/
169 sal_Bool
osl_sendResourcePipe(oslPipe
/*pPipe*/, oslSocket
/*pSocket*/)
171 return osl_Process_E_InvalidError
;
174 oslSocket
osl_receiveResourcePipe(oslPipe
/*pPipe*/)
176 oslSocket pSocket
= 0;
180 /******************************************************************************
182 * Functions for starting a process
184 *****************************************************************************/
188 static void ChildStatusProc(void *pData
)
192 int channel
[2] = { -1, -1 };
195 int stdOutput
[2] = { -1, -1 }, stdInput
[2] = { -1, -1 }, stdError
[2] = { -1, -1 };
197 pdata
= (ProcessData
*)pData
;
199 /* make a copy of our data, because forking will only copy
200 our local stack of the thread, so the process data will not be accessible
201 in our child process */
202 memcpy(&data
, pData
, sizeof(data
));
204 #ifdef NO_CHILD_PROCESSES
205 #define fork() (errno = EINVAL, -1)
207 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, channel
) == -1)
210 SAL_WARN("sal.osl", "executeProcess socketpair() errno " << status
);
213 fcntl(channel
[0], F_SETFD
, FD_CLOEXEC
);
214 fcntl(channel
[1], F_SETFD
, FD_CLOEXEC
);
216 /* Create redirected IO pipes */
217 if ( status
== 0 && data
.m_pInputWrite
&& pipe( stdInput
) == -1 )
221 SAL_WARN("sal.osl", "executeProcess pipe(stdInput) errno " << status
);
224 if ( status
== 0 && data
.m_pOutputRead
&& pipe( stdOutput
) == -1 )
228 SAL_WARN("sal.osl", "executeProcess pipe(stdOutput) errno " << status
);
231 if ( status
== 0 && data
.m_pErrorRead
&& pipe( stdError
) == -1 )
235 SAL_WARN("sal.osl", "executeProcess pipe(stdError) errno " << status
);
238 if ( (status
== 0) && ((pid
= fork()) == 0) )
244 if (channel
[0] != -1) close(channel
[0]);
246 if ((data
.m_uid
!= (uid_t
)-1) && ((data
.m_uid
!= getuid()) || (data
.m_gid
!= getgid())))
248 OSL_ASSERT(geteuid() == 0); /* must be root */
250 if (! INIT_GROUPS(data
.m_name
, data
.m_gid
) || (setuid(data
.m_uid
) != 0))
251 OSL_TRACE("Failed to change uid and guid, errno=%d (%s)", errno
, strerror(errno
));
253 const rtl::OUString
envVar("HOME");
254 osl_clearEnvironment(envVar
.pData
);
258 chstatus
= chdir(data
.m_pszDir
);
260 if (chstatus
== 0 && ((data
.m_uid
== (uid_t
)-1) || ((data
.m_uid
== getuid()) && (data
.m_gid
== getgid()))))
263 for (i
= 0; data
.m_pszEnv
[i
] != NULL
; i
++)
265 if (strchr(data
.m_pszEnv
[i
], '=') == NULL
)
267 unsetenv(data
.m_pszEnv
[i
]); /*TODO: check error return*/
271 putenv(data
.m_pszEnv
[i
]); /*TODO: check error return*/
275 OSL_TRACE("ChildStatusProc : starting '%s'",data
.m_pszArgs
[0]);
277 /* Connect std IO to pipe ends */
279 /* Write end of stdInput not used in child process */
280 if (stdInput
[1] != -1) close( stdInput
[1] );
282 /* Read end of stdOutput not used in child process */
283 if (stdOutput
[0] != -1) close( stdOutput
[0] );
285 /* Read end of stdError not used in child process */
286 if (stdError
[0] != -1) close( stdError
[0] );
288 /* Redirect pipe ends to std IO */
290 if ( stdInput
[0] != STDIN_FILENO
)
292 dup2( stdInput
[0], STDIN_FILENO
);
293 if (stdInput
[0] != -1) close( stdInput
[0] );
296 if ( stdOutput
[1] != STDOUT_FILENO
)
298 dup2( stdOutput
[1], STDOUT_FILENO
);
299 if (stdOutput
[1] != -1) close( stdOutput
[1] );
302 if ( stdError
[1] != STDERR_FILENO
)
304 dup2( stdError
[1], STDERR_FILENO
);
305 if (stdError
[1] != -1) close( stdError
[1] );
308 // No need to check the return value of execv. If we return from
309 // it, an error has occurred.
310 execv(data
.m_pszArgs
[0], (sal_Char
**)data
.m_pszArgs
);
313 OSL_TRACE("Failed to exec, errno=%d (%s)", errno
, strerror(errno
));
315 OSL_TRACE("ChildStatusProc : starting '%s' failed",data
.m_pszArgs
[0]);
317 /* if we reach here, something went wrong */
319 if ( !safeWrite(channel
[1], &errno_copy
, sizeof(errno_copy
)) )
320 OSL_TRACE("sendFdPipe : sending failed (%s)",strerror(errno
));
322 if ( channel
[1] != -1 )
330 if (channel
[1] != -1) close(channel
[1]);
332 /* Close unused pipe ends */
333 if (stdInput
[0] != -1) close( stdInput
[0] );
334 if (stdOutput
[1] != -1) close( stdOutput
[1] );
335 if (stdError
[1] != -1) close( stdError
[1] );
339 while (((i
= read(channel
[0], &status
, sizeof(status
))) < 0))
346 if (channel
[0] != -1) close(channel
[0]);
348 if ((pid
> 0) && (i
== 0))
351 osl_acquireMutex(ChildListMutex
);
353 pdata
->m_pProcImpl
->m_pid
= pid
;
354 pdata
->m_pProcImpl
->m_pnext
= ChildList
;
355 ChildList
= pdata
->m_pProcImpl
;
357 /* Store used pipe ends in data structure */
359 if ( pdata
->m_pInputWrite
)
360 *(pdata
->m_pInputWrite
) = osl::detail::createFileHandleFromFD( stdInput
[1] );
362 if ( pdata
->m_pOutputRead
)
363 *(pdata
->m_pOutputRead
) = osl::detail::createFileHandleFromFD( stdOutput
[0] );
365 if ( pdata
->m_pErrorRead
)
366 *(pdata
->m_pErrorRead
) = osl::detail::createFileHandleFromFD( stdError
[0] );
368 osl_releaseMutex(ChildListMutex
);
370 osl_setCondition(pdata
->m_started
);
374 child_pid
= waitpid(pid
, &status
, 0);
375 } while ( 0 > child_pid
&& EINTR
== errno
);
379 OSL_TRACE("Failed to wait for child process, errno=%d (%s)", errno
, strerror(errno
));
382 We got an other error than EINTR. Anyway we have to wake up the
383 waiting thread under any circumstances */
390 oslProcessImpl
* pChild
;
392 osl_acquireMutex(ChildListMutex
);
396 /* check if it is one of our child processes */
397 while (pChild
!= NULL
)
399 if (pChild
->m_pid
== child_pid
)
401 if (WIFEXITED(status
))
402 pChild
->m_status
= WEXITSTATUS(status
);
403 else if (WIFSIGNALED(status
))
404 pChild
->m_status
= 128 + WTERMSIG(status
);
406 pChild
->m_status
= -1;
408 osl_setCondition(pChild
->m_terminated
);
411 pChild
= pChild
->m_pnext
;
414 osl_releaseMutex(ChildListMutex
);
419 OSL_TRACE("ChildStatusProc : starting '%s' failed",data
.m_pszArgs
[0]);
420 OSL_TRACE("Failed to launch child process, child reports errno=%d (%s)", status
, strerror(status
));
422 /* Close pipe ends */
423 if ( pdata
->m_pInputWrite
)
424 *pdata
->m_pInputWrite
= NULL
;
426 if ( pdata
->m_pOutputRead
)
427 *pdata
->m_pOutputRead
= NULL
;
429 if ( pdata
->m_pErrorRead
)
430 *pdata
->m_pErrorRead
= NULL
;
432 if (stdInput
[1] != -1) close( stdInput
[1] );
433 if (stdOutput
[0] != -1) close( stdOutput
[0] );
434 if (stdError
[0] != -1) close( stdError
[0] );
436 //if pid > 0 then a process was created, even if it later failed
437 //e.g. bash searching for a command to execute, and we still
438 //need to clean it up to avoid "defunct" processes
444 child_pid
= waitpid(pid
, &status
, 0);
445 } while ( 0 > child_pid
&& EINTR
== errno
);
448 /* notify (and unblock) parent thread */
449 osl_setCondition(pdata
->m_started
);
456 oslProcessError SAL_CALL
osl_executeProcess_WithRedirectedIO(
457 rtl_uString
*ustrImageName
,
458 rtl_uString
*ustrArguments
[],
459 sal_uInt32 nArguments
,
460 oslProcessOption Options
,
461 oslSecurity Security
,
462 rtl_uString
*ustrWorkDir
,
463 rtl_uString
*ustrEnvironment
[],
464 sal_uInt32 nEnvironmentVars
,
465 oslProcess
*pProcess
,
466 oslFileHandle
*pInputWrite
,
467 oslFileHandle
*pOutputRead
,
468 oslFileHandle
*pErrorRead
472 oslProcessError Error
;
473 sal_Char
* pszWorkDir
=0;
474 sal_Char
** pArguments
=0;
475 sal_Char
** pEnvironment
=0;
478 char szImagePath
[PATH_MAX
] = "";
479 char szWorkDir
[PATH_MAX
] = "";
481 if ( ustrImageName
&& ustrImageName
->length
)
483 FileURLToPath( szImagePath
, PATH_MAX
, ustrImageName
);
486 if ( ustrWorkDir
!= 0 && ustrWorkDir
->length
)
488 FileURLToPath( szWorkDir
, PATH_MAX
, ustrWorkDir
);
489 pszWorkDir
= szWorkDir
;
492 if ( pArguments
== 0 && nArguments
> 0 )
494 pArguments
= (sal_Char
**) malloc( ( nArguments
+ 2 ) * sizeof(sal_Char
*) );
497 for ( idx
= 0 ; idx
< nArguments
; ++idx
)
499 rtl_String
* strArg
=0;
501 rtl_uString2String( &strArg
,
502 rtl_uString_getStr(ustrArguments
[idx
]),
503 rtl_uString_getLength(ustrArguments
[idx
]),
504 osl_getThreadTextEncoding(),
505 OUSTRING_TO_OSTRING_CVTFLAGS
);
507 pArguments
[idx
]=strdup(rtl_string_getStr(strArg
));
508 rtl_string_release(strArg
);
512 for ( idx
= 0 ; idx
< nEnvironmentVars
; ++idx
)
514 rtl_String
* strEnv
=0;
516 if ( pEnvironment
== 0 )
518 pEnvironment
= (sal_Char
**) malloc( ( nEnvironmentVars
+ 2 ) * sizeof(sal_Char
*) );
521 rtl_uString2String( &strEnv
,
522 rtl_uString_getStr(ustrEnvironment
[idx
]),
523 rtl_uString_getLength(ustrEnvironment
[idx
]),
524 osl_getThreadTextEncoding(),
525 OUSTRING_TO_OSTRING_CVTFLAGS
);
527 pEnvironment
[idx
]=strdup(rtl_string_getStr(strEnv
));
528 rtl_string_release(strEnv
);
529 pEnvironment
[idx
+1]=0;
532 Error
= osl_psz_executeProcess(szImagePath
,
544 if ( pArguments
!= 0 )
546 for ( idx
= 0 ; idx
< nArguments
; ++idx
)
548 if ( pArguments
[idx
] != 0 )
550 free(pArguments
[idx
]);
556 if ( pEnvironment
!= 0 )
558 for ( idx
= 0 ; idx
< nEnvironmentVars
; ++idx
)
560 if ( pEnvironment
[idx
] != 0 )
562 free(pEnvironment
[idx
]);
571 oslProcessError SAL_CALL
osl_executeProcess(
572 rtl_uString
*ustrImageName
,
573 rtl_uString
*ustrArguments
[],
574 sal_uInt32 nArguments
,
575 oslProcessOption Options
,
576 oslSecurity Security
,
577 rtl_uString
*ustrWorkDir
,
578 rtl_uString
*ustrEnvironment
[],
579 sal_uInt32 nEnvironmentVars
,
583 return osl_executeProcess_WithRedirectedIO(
599 oslProcessError SAL_CALL
osl_psz_executeProcess(sal_Char
*pszImageName
,
600 sal_Char
*pszArguments
[],
601 oslProcessOption Options
,
602 oslSecurity Security
,
603 sal_Char
*pszDirectory
,
604 sal_Char
*pszEnvironments
[],
605 oslProcess
*pProcess
,
606 oslFileHandle
*pInputWrite
,
607 oslFileHandle
*pOutputRead
,
608 oslFileHandle
*pErrorRead
612 sal_Char path
[PATH_MAX
+ 1];
618 memset(&Data
,0,sizeof(ProcessData
));
619 Data
.m_pInputWrite
= pInputWrite
;
620 Data
.m_pOutputRead
= pOutputRead
;
621 Data
.m_pErrorRead
= pErrorRead
;
623 if (pszImageName
== NULL
)
624 pszImageName
= pszArguments
[0];
626 OSL_ASSERT(pszImageName
!= NULL
);
628 if ( pszImageName
== 0 )
630 return osl_Process_E_NotFound
;
633 if ((Options
& osl_Process_SEARCHPATH
) &&
634 (osl_searchPath_impl(pszImageName
, path
, sizeof(path
)) == osl_Process_E_None
))
637 Data
.m_pszArgs
[0] = strdup(pszImageName
);
638 Data
.m_pszArgs
[1] = 0;
640 if ( pszArguments
!= 0 )
642 for (i
= 0; ((i
+ 2) < MAX_ARGS
) && (pszArguments
[i
] != NULL
); i
++)
643 Data
.m_pszArgs
[i
+1] = strdup(pszArguments
[i
]);
644 Data
.m_pszArgs
[i
+2] = NULL
;
647 Data
.m_options
= Options
;
648 Data
.m_pszDir
= (pszDirectory
!= NULL
) ? strdup(pszDirectory
) : NULL
;
650 if (pszEnvironments
!= NULL
)
652 for (i
= 0; ((i
+ 1) < MAX_ENVS
) && (pszEnvironments
[i
] != NULL
); i
++)
653 Data
.m_pszEnv
[i
] = strdup(pszEnvironments
[i
]);
654 Data
.m_pszEnv
[i
+1] = NULL
;
657 Data
.m_pszEnv
[0] = NULL
;
659 if (Security
!= NULL
)
661 Data
.m_uid
= ((oslSecurityImpl
*)Security
)->m_pPasswd
.pw_uid
;
662 Data
.m_gid
= ((oslSecurityImpl
*)Security
)->m_pPasswd
.pw_gid
;
663 Data
.m_name
= ((oslSecurityImpl
*)Security
)->m_pPasswd
.pw_name
;
666 Data
.m_uid
= (uid_t
)-1;
668 Data
.m_pProcImpl
= (oslProcessImpl
*) malloc(sizeof(oslProcessImpl
));
669 Data
.m_pProcImpl
->m_pid
= 0;
670 Data
.m_pProcImpl
->m_terminated
= osl_createCondition();
671 Data
.m_pProcImpl
->m_pnext
= NULL
;
673 if (ChildListMutex
== NULL
)
674 ChildListMutex
= osl_createMutex();
676 Data
.m_started
= osl_createCondition();
678 hThread
= osl_createThread(ChildStatusProc
, &Data
);
682 osl_waitCondition(Data
.m_started
, NULL
);
684 osl_destroyCondition(Data
.m_started
);
686 for (i
= 0; Data
.m_pszArgs
[i
] != NULL
; i
++)
687 free((void *)Data
.m_pszArgs
[i
]);
689 for (i
= 0; Data
.m_pszEnv
[i
] != NULL
; i
++)
690 free((void *)Data
.m_pszEnv
[i
]);
692 if ( Data
.m_pszDir
!= 0 )
694 free((void *)Data
.m_pszDir
);
697 osl_destroyThread(hThread
);
699 if (Data
.m_pProcImpl
->m_pid
!= 0)
701 assert(hThread
!= 0);
703 *pProcess
= Data
.m_pProcImpl
;
705 if (Options
& osl_Process_WAIT
)
706 osl_joinProcess(*pProcess
);
708 return osl_Process_E_None
;
711 osl_destroyCondition(Data
.m_pProcImpl
->m_terminated
);
712 free(Data
.m_pProcImpl
);
714 return osl_Process_E_Unknown
;
717 /******************************************************************************
719 * Functions for processes
721 *****************************************************************************/
723 oslProcessError SAL_CALL
osl_terminateProcess(oslProcess Process
)
726 return osl_Process_E_Unknown
;
728 if (kill(((oslProcessImpl
*)Process
)->m_pid
, SIGKILL
) != 0)
733 return osl_Process_E_NoPermission
;
736 return osl_Process_E_NotFound
;
739 return osl_Process_E_Unknown
;
743 return osl_Process_E_None
;
746 oslProcess SAL_CALL
osl_getProcess(oslProcessIdentifier Ident
)
748 oslProcessImpl
*pProcImpl
;
750 if (kill(Ident
, 0) != -1)
752 oslProcessImpl
* pChild
;
754 if (ChildListMutex
== NULL
)
755 ChildListMutex
= osl_createMutex();
757 osl_acquireMutex(ChildListMutex
);
761 /* check if it is one of our child processes */
762 while (pChild
!= NULL
)
764 if (Ident
== (sal_uInt32
) pChild
->m_pid
)
767 pChild
= pChild
->m_pnext
;
770 pProcImpl
= (oslProcessImpl
*) malloc(sizeof(oslProcessImpl
));
771 pProcImpl
->m_pid
= Ident
;
772 pProcImpl
->m_terminated
= osl_createCondition();
776 /* process is a child so insert into list */
777 pProcImpl
->m_pnext
= pChild
->m_pnext
;
778 pChild
->m_pnext
= pProcImpl
;
780 pProcImpl
->m_status
= pChild
->m_status
;
782 if (osl_checkCondition(pChild
->m_terminated
))
783 osl_setCondition(pProcImpl
->m_terminated
);
786 pProcImpl
->m_pnext
= NULL
;
788 osl_releaseMutex(ChildListMutex
);
796 void SAL_CALL
osl_freeProcessHandle(oslProcess Process
)
800 oslProcessImpl
*pChild
, *pPrev
= NULL
;
802 OSL_ASSERT(ChildListMutex
!= NULL
);
804 if ( ChildListMutex
== 0 )
809 osl_acquireMutex(ChildListMutex
);
813 /* remove process from child list */
814 while (pChild
!= NULL
)
816 if (pChild
== (oslProcessImpl
*)Process
)
819 pPrev
->m_pnext
= pChild
->m_pnext
;
821 ChildList
= pChild
->m_pnext
;
827 pChild
= pChild
->m_pnext
;
830 osl_releaseMutex(ChildListMutex
);
832 osl_destroyCondition(((oslProcessImpl
*)Process
)->m_terminated
);
843 char command
[16]; /* 'argv[0]' */ /* mfe: it all right char comm[16] in kernel! */
844 char state
; /* state (running, stopped, ...) */
845 pid_t ppid
; /* parent pid */
846 pid_t pgrp
; /* parent group */
847 int session
; /* session ID */
848 int tty
; /* no of tty */
849 pid_t tpgid
; /* group of process owning the tty */
850 unsigned long flags
; /* flags dunno */
851 unsigned long minflt
; /* minor page faults */
852 unsigned long cminflt
; /* minor page faults with children */
853 unsigned long majflt
; /* major page faults */
854 unsigned long cmajflt
; /* major page faults with children */
855 unsigned long utime
; /* no of jiffies in user mode */
856 unsigned long stime
; /* no of jiffies in kernel mode */
857 unsigned long cutime
; /* no of jiffies in user mode with children */
858 unsigned long cstime
; /* no of jiffies in kernel mode with children */
859 unsigned long priority
; /* nice value + 15 (kernel scheduling prio)*/
860 long nice
; /* nice value */
861 long timeout
; /* no of jiffies of next process timeout */
862 long itrealvalue
; /* no jiffies before next SIGALRM */
863 unsigned long starttime
; /* process started this no of jiffies after boot */
864 unsigned long vsize
; /* virtual memory size (in bytes) */
865 long rss
; /* resident set size (in pages) */
866 unsigned long rss_rlim
; /* rss limit (in bytes) */
867 unsigned long startcode
; /* address above program text can run */
868 unsigned long endcode
; /* address below program text can run */
869 unsigned long startstack
; /* address of start of stack */
870 unsigned long kstkesp
; /* current value of 'esp' (stack pointer) */
871 unsigned long kstkeip
; /* current value of 'eip' (instruction pointer) */
872 /* mfe: Linux > 2.1.7x have more signals (88) */
873 char signal
[24]; /* pending signals */
874 char blocked
[24]; /* blocked signals */
875 char sigignore
[24]; /* ignored signals */
876 char sigcatch
[24]; /* catched signals */
877 unsigned long wchan
; /* 'channel' the process is waiting in */
878 unsigned long nswap
; /* ? */
879 unsigned long cnswap
; /* ? */
882 int ruid
; /* real uid */
883 int euid
; /* effective uid */
884 int suid
; /* saved uid */
885 int fuid
; /* file access uid */
886 int rgid
; /* real gid */
887 int egid
; /* effective gid */
888 int sgid
; /* saved gid */
889 int fgid
; /* file access gid */
890 unsigned long vm_size
; /* like vsize but on kb */
891 unsigned long vm_lock
; /* locked pages in kb */
892 unsigned long vm_rss
; /* like rss but in kb */
893 unsigned long vm_data
; /* data size */
894 unsigned long vm_stack
; /* stack size */
895 unsigned long vm_exe
; /* executable size */
896 unsigned long vm_lib
; /* library size */
899 bool osl_getProcStat(pid_t pid
, struct osl_procStat
* procstat
)
903 char name
[PATH_MAX
+ 1];
904 snprintf(name
, sizeof(name
), "/proc/%u/stat", pid
);
906 if ((fd
= open(name
,O_RDONLY
)) >=0 )
910 memset(prstatbuf
,0,512);
911 bRet
= safeRead(fd
, prstatbuf
, 511);
918 tmp
= strrchr(prstatbuf
, ')');
920 memset(procstat
->command
, 0, sizeof(procstat
->command
));
922 sscanf(prstatbuf
, "%d (%15c", &procstat
->pid
, procstat
->command
);
926 "%lu %lu %lu %lu %lu"
930 "%lu %lu %lu %lu %lu"
934 &procstat
->ppid
, &procstat
->pgrp
, &procstat
->session
, &procstat
->tty
, &procstat
->tpgid
,
935 &procstat
->flags
, &procstat
->minflt
, &procstat
->cminflt
, &procstat
->majflt
, &procstat
->cmajflt
,
936 &procstat
->utime
, &procstat
->stime
, &procstat
->cutime
, &procstat
->cstime
,
937 &procstat
->priority
, &procstat
->nice
, &procstat
->timeout
, &procstat
->itrealvalue
,
938 &procstat
->starttime
, &procstat
->vsize
, &procstat
->rss
, &procstat
->rss_rlim
,
939 &procstat
->startcode
, &procstat
->endcode
, &procstat
->startstack
, &procstat
->kstkesp
, &procstat
->kstkeip
,
940 procstat
->signal
, procstat
->blocked
, procstat
->sigignore
, procstat
->sigcatch
,
941 &procstat
->wchan
, &procstat
->nswap
, &procstat
->cnswap
947 bool osl_getProcStatus(pid_t pid
, struct osl_procStat
* procstat
)
950 char name
[PATH_MAX
+ 1];
953 snprintf(name
, sizeof(name
), "/proc/%u/status", pid
);
955 if ((fd
= open(name
,O_RDONLY
)) >=0 )
958 char prstatusbuf
[512];
959 memset(prstatusbuf
,0,512);
960 bRet
= safeRead(fd
, prstatusbuf
, 511);
967 tmp
= strstr(prstatusbuf
,"Uid:");
970 sscanf(tmp
,"Uid:\t%d\t%d\t%d\t%d",
971 &procstat
->ruid
, &procstat
->euid
, &procstat
->suid
, &procstat
->fuid
975 tmp
= strstr(prstatusbuf
,"Gid:");
978 sscanf(tmp
,"Gid:\t%d\t%d\t%d\t%d",
979 &procstat
->rgid
, &procstat
->egid
, &procstat
->sgid
, &procstat
->fgid
983 tmp
= strstr(prstatusbuf
,"VmSize:");
994 &procstat
->vm_size
, &procstat
->vm_lock
, &procstat
->vm_rss
, &procstat
->vm_data
,
995 &procstat
->vm_stack
, &procstat
->vm_exe
, &procstat
->vm_lib
999 tmp
= strstr(prstatusbuf
,"SigPnd:");
1002 sscanf(tmp
, "SigPnd: %s SigBlk: %s SigIgn: %s %*s %s",
1003 procstat
->signal
, procstat
->blocked
, procstat
->sigignore
, procstat
->sigcatch
1012 oslProcessError SAL_CALL
osl_getProcessInfo(oslProcess Process
, oslProcessData Fields
, oslProcessInfo
* pInfo
)
1016 if (Process
== NULL
)
1019 pid
= ((oslProcessImpl
*)Process
)->m_pid
;
1021 if (! pInfo
|| (pInfo
->Size
!= sizeof(oslProcessInfo
)))
1022 return osl_Process_E_Unknown
;
1026 if (Fields
& osl_Process_IDENTIFIER
)
1029 pInfo
->Fields
|= osl_Process_IDENTIFIER
;
1032 if (Fields
& osl_Process_EXITCODE
)
1034 if ((Process
!= NULL
) &&
1035 osl_checkCondition(((oslProcessImpl
*)Process
)->m_terminated
))
1037 pInfo
->Code
= ((oslProcessImpl
*)Process
)->m_status
;
1038 pInfo
->Fields
|= osl_Process_EXITCODE
;
1042 if (Fields
& (osl_Process_HEAPUSAGE
| osl_Process_CPUTIMES
))
1045 #if defined(SOLARIS)
1048 sal_Char name
[PATH_MAX
+ 1];
1050 snprintf(name
, sizeof(name
), "/proc/%u", pid
);
1052 if ((fd
= open(name
, O_RDONLY
)) >= 0)
1054 prstatus_t prstatus
;
1056 if (ioctl(fd
, PIOCSTATUS
, &prstatus
) >= 0)
1058 if (Fields
& osl_Process_CPUTIMES
)
1060 pInfo
->UserTime
.Seconds
= prstatus
.pr_utime
.tv_sec
;
1061 pInfo
->UserTime
.Nanosec
= prstatus
.pr_utime
.tv_nsec
;
1062 pInfo
->SystemTime
.Seconds
= prstatus
.pr_stime
.tv_sec
;
1063 pInfo
->SystemTime
.Nanosec
= prstatus
.pr_stime
.tv_nsec
;
1065 pInfo
->Fields
|= osl_Process_CPUTIMES
;
1068 if (Fields
& osl_Process_HEAPUSAGE
)
1070 pInfo
->HeapUsage
= prstatus
.pr_brksize
;
1072 pInfo
->Fields
|= osl_Process_HEAPUSAGE
;
1077 return (pInfo
->Fields
== Fields
) ? osl_Process_E_None
: osl_Process_E_Unknown
;
1083 #elif defined(LINUX)
1085 if ( (Fields
& osl_Process_CPUTIMES
) || (Fields
& osl_Process_HEAPUSAGE
) )
1087 struct osl_procStat procstat
;
1088 memset(&procstat
,0,sizeof(procstat
));
1090 if ( (Fields
& osl_Process_CPUTIMES
) && osl_getProcStat(pid
, &procstat
) )
1094 * We calculate only time of the process proper.
1095 * Threads are processes, we do not consider their time here!
1096 * (For this, cutime and cstime should be used, it seems not
1097 * to work in 2.0.36)
1102 unsigned long userseconds
;
1103 unsigned long systemseconds
;
1105 clktck
= sysconf(_SC_CLK_TCK
);
1107 return osl_Process_E_Unknown
;
1109 hz
= (unsigned long) clktck
;
1111 userseconds
= procstat
.utime
/hz
;
1112 systemseconds
= procstat
.stime
/hz
;
1114 pInfo
->UserTime
.Seconds
= userseconds
;
1115 pInfo
->UserTime
.Nanosec
= procstat
.utime
- (userseconds
* hz
);
1116 pInfo
->SystemTime
.Seconds
= systemseconds
;
1117 pInfo
->SystemTime
.Nanosec
= procstat
.stime
- (systemseconds
* hz
);
1119 pInfo
->Fields
|= osl_Process_CPUTIMES
;
1122 if ( (Fields
& osl_Process_HEAPUSAGE
) && osl_getProcStatus(pid
, &procstat
) )
1126 * vm_data (found in status) shows the size of the data segment
1127 * it a rough approximation of the core heap size
1129 pInfo
->HeapUsage
= procstat
.vm_data
*1024;
1131 pInfo
->Fields
|= osl_Process_HEAPUSAGE
;
1135 return (pInfo
->Fields
== Fields
) ? osl_Process_E_None
: osl_Process_E_Unknown
;
1140 return (pInfo
->Fields
== Fields
) ? osl_Process_E_None
: osl_Process_E_Unknown
;
1143 /***********************************************
1144 helper function for osl_joinProcessWithTimeout
1145 **********************************************/
1147 static bool is_timeout(const struct timeval
* tend
)
1149 struct timeval tcurrent
;
1150 gettimeofday(&tcurrent
, NULL
);
1151 return (tcurrent
.tv_sec
>= tend
->tv_sec
);
1154 /**********************************************
1155 kill(pid, 0) is useful for checking if a
1156 process is still alive, but remember that
1157 kill even returns 0 if the process is already
1159 *********************************************/
1161 static bool is_process_dead(pid_t pid
)
1163 return ((-1 == kill(pid
, 0)) && (ESRCH
== errno
));
1166 /**********************************************
1167 osl_joinProcessWithTimeout
1168 *********************************************/
1170 oslProcessError SAL_CALL
osl_joinProcessWithTimeout(oslProcess Process
, const TimeValue
* pTimeout
)
1172 oslProcessImpl
* pChild
= ChildList
;
1173 oslProcessError osl_error
= osl_Process_E_None
;
1175 OSL_PRECOND(Process
, "osl_joinProcess: Invalid parameter");
1176 OSL_ASSERT(ChildListMutex
);
1178 if (NULL
== Process
|| 0 == ChildListMutex
)
1179 return osl_Process_E_Unknown
;
1181 osl_acquireMutex(ChildListMutex
);
1183 /* check if process is a child of ours */
1184 while (pChild
!= NULL
)
1186 if (pChild
== (oslProcessImpl
*)Process
)
1189 pChild
= pChild
->m_pnext
;
1192 osl_releaseMutex(ChildListMutex
);
1196 oslConditionResult cond_res
= osl_waitCondition(pChild
->m_terminated
, pTimeout
);
1198 if (osl_cond_result_timeout
== cond_res
)
1199 osl_error
= osl_Process_E_TimedOut
;
1200 else if (osl_cond_result_ok
!= cond_res
)
1201 osl_error
= osl_Process_E_Unknown
;
1203 else /* alien process; StatusThread will not be able
1204 to set the condition terminated */
1206 pid_t pid
= ((oslProcessImpl
*)Process
)->m_pid
;
1210 bool timeout
= false;
1211 struct timeval tend
;
1213 gettimeofday(&tend
, NULL
);
1215 tend
.tv_sec
+= pTimeout
->Seconds
;
1217 while (!is_process_dead(pid
) && !(timeout
= is_timeout(&tend
)))
1221 osl_error
= osl_Process_E_TimedOut
;
1225 while (!is_process_dead(pid
))
1232 oslProcessError SAL_CALL
osl_joinProcess(oslProcess Process
)
1234 return osl_joinProcessWithTimeout(Process
, NULL
);
1237 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */