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>
32 * - cleanup of process status things
33 * - cleanup of process spawning
34 * - cleanup of resource transfer
38 // The procfs may only be used without LFS in 32bits.
39 # ifdef _FILE_OFFSET_BITS
40 # undef _FILE_OFFSET_BITS
44 #if defined(FREEBSD) || defined(NETBSD) || defined(DRAGONFLY)
45 #include <machine/param.h>
53 #include "unixerrnostring.hxx"
55 # include <sys/procfs.h>
57 #include <osl/diagnose.h>
58 #include <osl/mutex.h>
59 #include <osl/process.h>
60 #include <osl/conditn.h>
61 #include <osl/thread.h>
63 #include <osl/file.hxx>
64 #include <sal/log.hxx>
66 #include "createfilehandlefromfd.hxx"
67 #include "file_url.hxx"
68 #include "readwrite_helper.hxx"
69 #include "secimpl.hxx"
77 struct oslProcessImpl
{
79 oslCondition m_terminated
;
81 oslProcessImpl
* m_pnext
;
86 const char* m_pszArgs
[MAX_ARGS
+ 1];
88 char* m_pszEnv
[MAX_ENVS
+ 1];
92 oslCondition m_started
;
93 oslProcessImpl
* m_pProcImpl
;
94 oslFileHandle
*m_pInputWrite
;
95 oslFileHandle
*m_pOutputRead
;
96 oslFileHandle
*m_pErrorRead
;
99 oslProcessImpl
* ChildList
;
100 oslMutex ChildListMutex
;
102 } //Anonymous namespace
104 static oslProcessError
osl_psz_executeProcess(char *pszImageName
,
105 char *pszArguments
[],
106 oslProcessOption Options
,
107 oslSecurity Security
,
109 char *pszEnvironments
[],
110 oslProcess
*pProcess
,
111 oslFileHandle
*pInputWrite
,
112 oslFileHandle
*pOutputRead
,
113 oslFileHandle
*pErrorRead
);
117 static void ChildStatusProc(void *pData
)
119 osl_setThreadName("osl_executeProcess");
123 int channel
[2] = { -1, -1 };
126 int stdOutput
[2] = { -1, -1 }, stdInput
[2] = { -1, -1 }, stdError
[2] = { -1, -1 };
128 pdata
= static_cast<ProcessData
*>(pData
);
130 /* make a copy of our data, because forking will only copy
131 our local stack of the thread, so the process data will not be accessible
132 in our child process */
133 memcpy(&data
, pData
, sizeof(data
));
135 #ifdef NO_CHILD_PROCESSES
136 #define fork() (errno = EINVAL, -1)
138 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, channel
) == -1)
141 SAL_WARN("sal.osl", "executeProcess socketpair() errno " << status
);
144 (void) fcntl(channel
[0], F_SETFD
, FD_CLOEXEC
);
145 (void) fcntl(channel
[1], F_SETFD
, FD_CLOEXEC
);
147 /* Create redirected IO pipes */
148 if ( status
== 0 && data
.m_pInputWrite
&& pipe( stdInput
) == -1 )
152 SAL_WARN("sal.osl", "executeProcess pipe(stdInput) errno " << status
);
155 if ( status
== 0 && data
.m_pOutputRead
&& pipe( stdOutput
) == -1 )
159 SAL_WARN("sal.osl", "executeProcess pipe(stdOutput) errno " << status
);
162 if ( status
== 0 && data
.m_pErrorRead
&& pipe( stdError
) == -1 )
166 SAL_WARN("sal.osl", "executeProcess pipe(stdError) errno " << status
);
169 if ( (status
== 0) && ((pid
= fork()) == 0) )
175 if (channel
[0] != -1) close(channel
[0]);
177 if ((data
.m_uid
!= uid_t(-1)) && ((data
.m_uid
!= getuid()) || (data
.m_gid
!= getgid())))
179 OSL_ASSERT(geteuid() == 0); /* must be root */
181 if (! INIT_GROUPS(data
.m_name
, data
.m_gid
) || (setuid(data
.m_uid
) != 0))
183 // ignore; can't do much about it here after fork
190 chstatus
= chdir(data
.m_pszDir
);
192 if (chstatus
== 0 && ((data
.m_uid
== uid_t(-1)) || ((data
.m_uid
== getuid()) && (data
.m_gid
== getgid()))))
195 for (i
= 0; data
.m_pszEnv
[i
] != nullptr; i
++)
197 if (strchr(data
.m_pszEnv
[i
], '=') == nullptr)
199 unsetenv(data
.m_pszEnv
[i
]); /*TODO: check error return*/
203 putenv(data
.m_pszEnv
[i
]); /*TODO: check error return*/
207 /* Connect std IO to pipe ends */
209 /* Write end of stdInput not used in child process */
210 if (stdInput
[1] != -1) close( stdInput
[1] );
212 /* Read end of stdOutput not used in child process */
213 if (stdOutput
[0] != -1) close( stdOutput
[0] );
215 /* Read end of stdError not used in child process */
216 if (stdError
[0] != -1) close( stdError
[0] );
218 /* Redirect pipe ends to std IO */
220 if ( stdInput
[0] != STDIN_FILENO
)
222 dup2( stdInput
[0], STDIN_FILENO
);
223 if (stdInput
[0] != -1) close( stdInput
[0] );
226 if ( stdOutput
[1] != STDOUT_FILENO
)
228 dup2( stdOutput
[1], STDOUT_FILENO
);
229 if (stdOutput
[1] != -1) close( stdOutput
[1] );
232 if ( stdError
[1] != STDERR_FILENO
)
234 dup2( stdError
[1], STDERR_FILENO
);
235 if (stdError
[1] != -1) close( stdError
[1] );
238 // No need to check the return value of execv. If we return from
239 // it, an error has occurred.
240 execv(data
.m_pszArgs
[0], const_cast<char **>(data
.m_pszArgs
));
243 /* if we reach here, something went wrong */
245 if ( !safeWrite(channel
[1], &errno_copy
, sizeof(errno_copy
)) )
247 // ignore; can't do much about it here after fork
250 if ( channel
[1] != -1 )
258 if (channel
[1] != -1) close(channel
[1]);
260 /* Close unused pipe ends */
261 if (stdInput
[0] != -1) close( stdInput
[0] );
262 if (stdOutput
[1] != -1) close( stdOutput
[1] );
263 if (stdError
[1] != -1) close( stdError
[1] );
267 while ((i
= read(channel
[0], &status
, sizeof(status
))) < 0)
274 if (channel
[0] != -1) close(channel
[0]);
276 if ((pid
> 0) && (i
== 0))
279 osl_acquireMutex(ChildListMutex
);
281 pdata
->m_pProcImpl
->m_pid
= pid
;
282 pdata
->m_pProcImpl
->m_pnext
= ChildList
;
283 ChildList
= pdata
->m_pProcImpl
;
285 /* Store used pipe ends in data structure */
287 if ( pdata
->m_pInputWrite
)
288 *(pdata
->m_pInputWrite
) = osl::detail::createFileHandleFromFD( stdInput
[1] );
290 if ( pdata
->m_pOutputRead
)
291 *(pdata
->m_pOutputRead
) = osl::detail::createFileHandleFromFD( stdOutput
[0] );
293 if ( pdata
->m_pErrorRead
)
294 *(pdata
->m_pErrorRead
) = osl::detail::createFileHandleFromFD( stdError
[0] );
296 osl_releaseMutex(ChildListMutex
);
298 osl_setCondition(pdata
->m_started
);
302 child_pid
= waitpid(pid
, &status
, 0);
303 } while ( 0 > child_pid
&& EINTR
== errno
);
307 SAL_WARN("sal.osl", "Failed to wait for child process: " << UnixErrnoString(errno
));
310 We got another error than EINTR. Anyway we have to wake up the
311 waiting thread under any circumstances */
318 oslProcessImpl
* pChild
;
320 osl_acquireMutex(ChildListMutex
);
324 /* check if it is one of our child processes */
325 while (pChild
!= nullptr)
327 if (pChild
->m_pid
== child_pid
)
329 if (WIFEXITED(status
))
330 pChild
->m_status
= WEXITSTATUS(status
);
331 else if (WIFSIGNALED(status
))
332 pChild
->m_status
= 128 + WTERMSIG(status
);
334 pChild
->m_status
= -1;
336 // coverity[lock_order : FALSE] - incorrect report of lock order error
337 osl_setCondition(pChild
->m_terminated
);
340 pChild
= pChild
->m_pnext
;
343 osl_releaseMutex(ChildListMutex
);
348 SAL_WARN("sal.osl", "ChildStatusProc : starting '" << data
.m_pszArgs
[0] << "' failed");
349 SAL_WARN("sal.osl", "Failed to launch child process, child reports " << UnixErrnoString(status
));
351 /* Close pipe ends */
352 if ( pdata
->m_pInputWrite
)
353 *pdata
->m_pInputWrite
= nullptr;
355 if ( pdata
->m_pOutputRead
)
356 *pdata
->m_pOutputRead
= nullptr;
358 if ( pdata
->m_pErrorRead
)
359 *pdata
->m_pErrorRead
= nullptr;
361 if (stdInput
[1] != -1) close( stdInput
[1] );
362 if (stdOutput
[0] != -1) close( stdOutput
[0] );
363 if (stdError
[0] != -1) close( stdError
[0] );
365 /* if pid > 0 then a process was created, even if it later failed
366 e.g. bash searching for a command to execute, and we still
367 need to clean it up to avoid "defunct" processes */
373 child_pid
= waitpid(pid
, &status
, 0);
374 } while ( 0 > child_pid
&& EINTR
== errno
);
377 /* notify (and unblock) parent thread */
378 osl_setCondition(pdata
->m_started
);
385 oslProcessError SAL_CALL
osl_executeProcess_WithRedirectedIO(
386 rtl_uString
*ustrImageName
,
387 rtl_uString
*ustrArguments
[],
388 sal_uInt32 nArguments
,
389 oslProcessOption Options
,
390 oslSecurity Security
,
391 rtl_uString
*ustrWorkDir
,
392 rtl_uString
*ustrEnvironment
[],
393 sal_uInt32 nEnvironmentVars
,
394 oslProcess
*pProcess
,
395 oslFileHandle
*pInputWrite
,
396 oslFileHandle
*pOutputRead
,
397 oslFileHandle
*pErrorRead
401 if (ustrImageName
== nullptr)
405 return osl_Process_E_InvalidError
;
407 image
= OUString::unacquired(ustrArguments
);
411 osl::FileBase::RC e
= osl::FileBase::getSystemPathFromFileURL(
412 OUString::unacquired(&ustrImageName
), image
);
413 if (e
!= osl::FileBase::E_None
)
417 "getSystemPathFromFileURL("
418 << OUString::unacquired(&ustrImageName
)
419 << ") failed with " << e
);
420 return osl_Process_E_Unknown
;
424 if ((Options
& osl_Process_SEARCHPATH
) != 0)
427 if (osl::detail::find_in_PATH(image
, path
))
433 oslProcessError Error
;
434 char* pszWorkDir
=nullptr;
435 char** pArguments
=nullptr;
436 char** pEnvironment
=nullptr;
439 char szImagePath
[PATH_MAX
] = "";
442 szImagePath
, SAL_N_ELEMENTS(szImagePath
), image
.getStr(),
447 SAL_INFO("sal.osl", "UnicodeToText(" << image
<< ") failed with " << e
);
448 return osl_Process_E_Unknown
;
451 char szWorkDir
[PATH_MAX
] = "";
452 if ( ustrWorkDir
!= nullptr && ustrWorkDir
->length
)
454 oslFileError e
= FileURLToPath( szWorkDir
, PATH_MAX
, ustrWorkDir
);
455 if (e
!= osl_File_E_None
)
459 "FileURLToPath(" << OUString::unacquired(&ustrWorkDir
)
460 << ") failed with " << e
);
461 return osl_Process_E_Unknown
;
463 pszWorkDir
= szWorkDir
;
466 if ( nArguments
> 0 )
468 pArguments
= static_cast<char**>(malloc( ( nArguments
+ 2 ) * sizeof(char*) ));
471 for ( idx
= 0 ; idx
< nArguments
; ++idx
)
473 rtl_String
* strArg
=nullptr;
475 rtl_uString2String( &strArg
,
476 rtl_uString_getStr(ustrArguments
[idx
]),
477 rtl_uString_getLength(ustrArguments
[idx
]),
478 osl_getThreadTextEncoding(),
479 OUSTRING_TO_OSTRING_CVTFLAGS
);
481 pArguments
[idx
]=strdup(rtl_string_getStr(strArg
));
482 rtl_string_release(strArg
);
483 pArguments
[idx
+1]=nullptr;
486 for ( idx
= 0 ; idx
< nEnvironmentVars
; ++idx
)
488 rtl_String
* strEnv
=nullptr;
490 if ( pEnvironment
== nullptr )
492 pEnvironment
= static_cast<char**>(malloc( ( nEnvironmentVars
+ 2 ) * sizeof(char*) ));
495 rtl_uString2String( &strEnv
,
496 rtl_uString_getStr(ustrEnvironment
[idx
]),
497 rtl_uString_getLength(ustrEnvironment
[idx
]),
498 osl_getThreadTextEncoding(),
499 OUSTRING_TO_OSTRING_CVTFLAGS
);
501 pEnvironment
[idx
]=strdup(rtl_string_getStr(strEnv
));
502 rtl_string_release(strEnv
);
503 pEnvironment
[idx
+1]=nullptr;
506 Error
= osl_psz_executeProcess(szImagePath
,
518 if ( pArguments
!= nullptr )
520 for ( idx
= 0 ; idx
< nArguments
; ++idx
)
522 if ( pArguments
[idx
] != nullptr )
524 free(pArguments
[idx
]);
530 if ( pEnvironment
!= nullptr )
532 for ( idx
= 0 ; idx
< nEnvironmentVars
; ++idx
)
534 if ( pEnvironment
[idx
] != nullptr )
536 free(pEnvironment
[idx
]);
545 oslProcessError SAL_CALL
osl_executeProcess(
546 rtl_uString
*ustrImageName
,
547 rtl_uString
*ustrArguments
[],
548 sal_uInt32 nArguments
,
549 oslProcessOption Options
,
550 oslSecurity Security
,
551 rtl_uString
*ustrWorkDir
,
552 rtl_uString
*ustrEnvironment
[],
553 sal_uInt32 nEnvironmentVars
,
557 return osl_executeProcess_WithRedirectedIO(
573 oslProcessError
osl_psz_executeProcess(char *pszImageName
,
574 char *pszArguments
[],
575 oslProcessOption Options
,
576 oslSecurity Security
,
578 char *pszEnvironments
[],
579 oslProcess
*pProcess
,
580 oslFileHandle
*pInputWrite
,
581 oslFileHandle
*pOutputRead
,
582 oslFileHandle
*pErrorRead
589 memset(&Data
,0,sizeof(ProcessData
));
590 Data
.m_pInputWrite
= pInputWrite
;
591 Data
.m_pOutputRead
= pOutputRead
;
592 Data
.m_pErrorRead
= pErrorRead
;
594 OSL_ASSERT(pszImageName
!= nullptr);
596 if ( pszImageName
== nullptr )
598 return osl_Process_E_NotFound
;
601 Data
.m_pszArgs
[0] = strdup(pszImageName
);
602 Data
.m_pszArgs
[1] = nullptr;
604 if ( pszArguments
!= nullptr )
606 for (i
= 0; ((i
+ 2) < MAX_ARGS
) && (pszArguments
[i
] != nullptr); i
++)
607 Data
.m_pszArgs
[i
+1] = strdup(pszArguments
[i
]);
608 Data
.m_pszArgs
[i
+2] = nullptr;
611 Data
.m_pszDir
= (pszDirectory
!= nullptr) ? strdup(pszDirectory
) : nullptr;
613 if (pszEnvironments
!= nullptr)
615 for (i
= 0; ((i
+ 1) < MAX_ENVS
) && (pszEnvironments
[i
] != nullptr); i
++)
616 Data
.m_pszEnv
[i
] = strdup(pszEnvironments
[i
]);
617 Data
.m_pszEnv
[i
+1] = nullptr;
620 Data
.m_pszEnv
[0] = nullptr;
622 if (Security
!= nullptr)
624 Data
.m_uid
= static_cast<oslSecurityImpl
*>(Security
)->m_pPasswd
.pw_uid
;
625 Data
.m_gid
= static_cast<oslSecurityImpl
*>(Security
)->m_pPasswd
.pw_gid
;
626 Data
.m_name
= static_cast<oslSecurityImpl
*>(Security
)->m_pPasswd
.pw_name
;
629 Data
.m_uid
= uid_t(-1);
631 Data
.m_pProcImpl
= static_cast<oslProcessImpl
*>(malloc(sizeof(oslProcessImpl
)));
632 Data
.m_pProcImpl
->m_pid
= 0;
633 Data
.m_pProcImpl
->m_terminated
= osl_createCondition();
634 Data
.m_pProcImpl
->m_pnext
= nullptr;
636 if (ChildListMutex
== nullptr)
637 ChildListMutex
= osl_createMutex();
639 Data
.m_started
= osl_createCondition();
641 hThread
= osl_createThread(ChildStatusProc
, &Data
);
643 if (hThread
!= nullptr)
645 osl_waitCondition(Data
.m_started
, nullptr);
647 osl_destroyCondition(Data
.m_started
);
649 for (i
= 0; Data
.m_pszArgs
[i
] != nullptr; i
++)
650 free(const_cast<char *>(Data
.m_pszArgs
[i
]));
652 for (i
= 0; Data
.m_pszEnv
[i
] != nullptr; i
++)
653 free(Data
.m_pszEnv
[i
]);
655 if ( Data
.m_pszDir
!= nullptr )
657 free(const_cast<char *>(Data
.m_pszDir
));
660 osl_destroyThread(hThread
);
662 if (Data
.m_pProcImpl
->m_pid
!= 0)
664 assert(hThread
!= nullptr);
666 *pProcess
= Data
.m_pProcImpl
;
668 if (Options
& osl_Process_WAIT
)
669 osl_joinProcess(*pProcess
);
671 return osl_Process_E_None
;
674 osl_destroyCondition(Data
.m_pProcImpl
->m_terminated
);
675 free(Data
.m_pProcImpl
);
677 return osl_Process_E_Unknown
;
680 oslProcessError SAL_CALL
osl_terminateProcess(oslProcess Process
)
682 if (Process
== nullptr)
683 return osl_Process_E_Unknown
;
685 if (kill(static_cast<oslProcessImpl
*>(Process
)->m_pid
, SIGKILL
) != 0)
690 return osl_Process_E_NoPermission
;
693 return osl_Process_E_NotFound
;
696 return osl_Process_E_Unknown
;
700 return osl_Process_E_None
;
703 oslProcess SAL_CALL
osl_getProcess(oslProcessIdentifier Ident
)
705 oslProcessImpl
*pProcImpl
;
707 if (kill(Ident
, 0) != -1)
709 oslProcessImpl
* pChild
;
711 if (ChildListMutex
== nullptr)
712 ChildListMutex
= osl_createMutex();
714 osl_acquireMutex(ChildListMutex
);
718 /* check if it is one of our child processes */
719 while (pChild
!= nullptr)
721 if (Ident
== static_cast<sal_uInt32
>(pChild
->m_pid
))
724 pChild
= pChild
->m_pnext
;
727 pProcImpl
= static_cast<oslProcessImpl
*>(malloc(sizeof(oslProcessImpl
)));
728 pProcImpl
->m_pid
= Ident
;
729 pProcImpl
->m_terminated
= osl_createCondition();
731 if (pChild
!= nullptr)
733 /* process is a child so insert into list */
734 pProcImpl
->m_pnext
= pChild
->m_pnext
;
735 pChild
->m_pnext
= pProcImpl
;
737 pProcImpl
->m_status
= pChild
->m_status
;
739 // coverity[lock_order : FALSE] - incorrect report of lock order error
740 if (osl_checkCondition(pChild
->m_terminated
))
742 // coverity[lock_order : FALSE] - incorrect report of lock order error
743 osl_setCondition(pProcImpl
->m_terminated
);
747 pProcImpl
->m_pnext
= nullptr;
749 osl_releaseMutex(ChildListMutex
);
757 void SAL_CALL
osl_freeProcessHandle(oslProcess Process
)
759 if (Process
== nullptr)
762 oslProcessImpl
*pChild
, *pPrev
= nullptr;
764 OSL_ASSERT(ChildListMutex
!= nullptr);
766 if ( ChildListMutex
== nullptr )
771 osl_acquireMutex(ChildListMutex
);
775 /* remove process from child list */
776 while (pChild
!= nullptr)
778 if (pChild
== static_cast<oslProcessImpl
*>(Process
))
780 if (pPrev
!= nullptr)
781 pPrev
->m_pnext
= pChild
->m_pnext
;
783 ChildList
= pChild
->m_pnext
;
789 pChild
= pChild
->m_pnext
;
792 osl_releaseMutex(ChildListMutex
);
794 osl_destroyCondition(static_cast<oslProcessImpl
*>(Process
)->m_terminated
);
806 char command
[16]; /* 'argv[0]' */ /* mfe: it all right char comm[16] in kernel! */
807 char state
; /* state (running, stopped, ...) */
808 pid_t ppid
; /* parent pid */
809 pid_t pgrp
; /* parent group */
810 int session
; /* session ID */
811 int tty
; /* no of tty */
812 pid_t tpgid
; /* group of process owning the tty */
813 unsigned long flags
; /* flags dunno */
814 unsigned long minflt
; /* minor page faults */
815 unsigned long cminflt
; /* minor page faults with children */
816 unsigned long majflt
; /* major page faults */
817 unsigned long cmajflt
; /* major page faults with children */
818 unsigned long utime
; /* no of jiffies in user mode */
819 unsigned long stime
; /* no of jiffies in kernel mode */
820 unsigned long cutime
; /* no of jiffies in user mode with children */
821 unsigned long cstime
; /* no of jiffies in kernel mode with children */
822 unsigned long priority
; /* nice value + 15 (kernel scheduling prio)*/
823 long nice
; /* nice value */
824 long timeout
; /* no of jiffies of next process timeout */
825 long itrealvalue
; /* no jiffies before next SIGALRM */
826 unsigned long starttime
; /* process started this no of jiffies after boot */
827 unsigned long vsize
; /* virtual memory size (in bytes) */
828 long rss
; /* resident set size (in pages) */
829 unsigned long rss_rlim
; /* rss limit (in bytes) */
830 unsigned long startcode
; /* address above program text can run */
831 unsigned long endcode
; /* address below program text can run */
832 unsigned long startstack
; /* address of start of stack */
833 unsigned long kstkesp
; /* current value of 'esp' (stack pointer) */
834 unsigned long kstkeip
; /* current value of 'eip' (instruction pointer) */
835 /* mfe: Linux > 2.1.7x have more signals (88) */
836 char signal
[24]; /* pending signals */
837 char blocked
[24]; /* blocked signals */
838 char sigignore
[24]; /* ignored signals */
839 char sigcatch
[24]; /* caught signals */
840 unsigned long wchan
; /* 'channel' the process is waiting in */
841 unsigned long nswap
; /* ? */
842 unsigned long cnswap
; /* ? */
845 int ruid
; /* real uid */
846 int euid
; /* effective uid */
847 int suid
; /* saved uid */
848 int fuid
; /* file access uid */
849 int rgid
; /* real gid */
850 int egid
; /* effective gid */
851 int sgid
; /* saved gid */
852 int fgid
; /* file access gid */
853 unsigned long vm_size
; /* like vsize but on kb */
854 unsigned long vm_lock
; /* locked pages in kb */
855 unsigned long vm_rss
; /* like rss but in kb */
856 unsigned long vm_data
; /* data size */
857 unsigned long vm_stack
; /* stack size */
858 unsigned long vm_exe
; /* executable size */
859 unsigned long vm_lib
; /* library size */
864 static bool osl_getProcStat(pid_t pid
, struct osl_procStat
* procstat
)
868 char name
[PATH_MAX
+ 1];
869 snprintf(name
, sizeof(name
), "/proc/%u/stat", pid
);
871 if ((fd
= open(name
,O_RDONLY
)) >=0 )
875 memset(prstatbuf
,0,512);
876 bRet
= safeRead(fd
, prstatbuf
, 511);
883 tmp
= strrchr(prstatbuf
, ')');
888 memset(procstat
->command
, 0, sizeof(procstat
->command
));
890 sscanf(prstatbuf
, "%d (%15c", &procstat
->pid
, procstat
->command
);
894 "%lu %lu %lu %lu %lu"
898 "%lu %lu %lu %lu %lu"
899 "%23s %23s %23s %23s"
902 &procstat
->ppid
, &procstat
->pgrp
, &procstat
->session
, &procstat
->tty
, &procstat
->tpgid
,
903 &procstat
->flags
, &procstat
->minflt
, &procstat
->cminflt
, &procstat
->majflt
, &procstat
->cmajflt
,
904 &procstat
->utime
, &procstat
->stime
, &procstat
->cutime
, &procstat
->cstime
,
905 &procstat
->priority
, &procstat
->nice
, &procstat
->timeout
, &procstat
->itrealvalue
,
906 &procstat
->starttime
, &procstat
->vsize
, &procstat
->rss
, &procstat
->rss_rlim
,
907 &procstat
->startcode
, &procstat
->endcode
, &procstat
->startstack
, &procstat
->kstkesp
, &procstat
->kstkeip
,
908 procstat
->signal
, procstat
->blocked
, procstat
->sigignore
, procstat
->sigcatch
,
909 &procstat
->wchan
, &procstat
->nswap
, &procstat
->cnswap
920 static bool osl_getProcStatus(pid_t pid
, struct osl_procStat
* procstat
)
923 char name
[PATH_MAX
+ 1];
926 snprintf(name
, sizeof(name
), "/proc/%u/status", pid
);
928 if ((fd
= open(name
,O_RDONLY
)) >=0 )
931 char prstatusbuf
[512];
932 memset(prstatusbuf
,0,512);
933 bRet
= safeRead(fd
, prstatusbuf
, 511);
940 tmp
= strstr(prstatusbuf
,"Uid:");
943 sscanf(tmp
,"Uid:\t%d\t%d\t%d\t%d",
944 &procstat
->ruid
, &procstat
->euid
, &procstat
->suid
, &procstat
->fuid
948 tmp
= strstr(prstatusbuf
,"Gid:");
951 sscanf(tmp
,"Gid:\t%d\t%d\t%d\t%d",
952 &procstat
->rgid
, &procstat
->egid
, &procstat
->sgid
, &procstat
->fgid
956 tmp
= strstr(prstatusbuf
,"VmSize:");
967 &procstat
->vm_size
, &procstat
->vm_lock
, &procstat
->vm_rss
, &procstat
->vm_data
,
968 &procstat
->vm_stack
, &procstat
->vm_exe
, &procstat
->vm_lib
972 tmp
= strstr(prstatusbuf
,"SigPnd:");
975 sscanf(tmp
, "SigPnd: %23s SigBlk: %23s SigIgn: %23s %*s %23s",
976 procstat
->signal
, procstat
->blocked
, procstat
->sigignore
, procstat
->sigcatch
985 oslProcessError SAL_CALL
osl_getProcessInfo(oslProcess Process
, oslProcessData Fields
, oslProcessInfo
* pInfo
)
989 if (Process
== nullptr)
992 pid
= static_cast<oslProcessImpl
*>(Process
)->m_pid
;
994 if (! pInfo
|| (pInfo
->Size
!= sizeof(oslProcessInfo
)))
995 return osl_Process_E_Unknown
;
999 if (Fields
& osl_Process_IDENTIFIER
)
1002 pInfo
->Fields
|= osl_Process_IDENTIFIER
;
1005 if (Fields
& osl_Process_EXITCODE
)
1007 if ((Process
!= nullptr) &&
1008 osl_checkCondition(static_cast<oslProcessImpl
*>(Process
)->m_terminated
))
1010 pInfo
->Code
= static_cast<oslProcessImpl
*>(Process
)->m_status
;
1011 pInfo
->Fields
|= osl_Process_EXITCODE
;
1015 if (Fields
& (osl_Process_HEAPUSAGE
| osl_Process_CPUTIMES
))
1021 char name
[PATH_MAX
+ 1];
1023 snprintf(name
, sizeof(name
), "/proc/%ld", (long)pid
);
1025 if ((fd
= open(name
, O_RDONLY
)) >= 0)
1027 prstatus_t prstatus
;
1029 if (ioctl(fd
, PIOCSTATUS
, &prstatus
) >= 0)
1031 if (Fields
& osl_Process_CPUTIMES
)
1033 pInfo
->UserTime
.Seconds
= prstatus
.pr_utime
.tv_sec
;
1034 pInfo
->UserTime
.Nanosec
= prstatus
.pr_utime
.tv_nsec
;
1035 pInfo
->SystemTime
.Seconds
= prstatus
.pr_stime
.tv_sec
;
1036 pInfo
->SystemTime
.Nanosec
= prstatus
.pr_stime
.tv_nsec
;
1038 pInfo
->Fields
|= osl_Process_CPUTIMES
;
1041 if (Fields
& osl_Process_HEAPUSAGE
)
1043 pInfo
->HeapUsage
= prstatus
.pr_brksize
;
1045 pInfo
->Fields
|= osl_Process_HEAPUSAGE
;
1050 return (pInfo
->Fields
== Fields
) ? osl_Process_E_None
: osl_Process_E_Unknown
;
1056 #elif defined(LINUX)
1058 if ( (Fields
& osl_Process_CPUTIMES
) || (Fields
& osl_Process_HEAPUSAGE
) )
1060 struct osl_procStat procstat
;
1061 memset(&procstat
,0,sizeof(procstat
));
1063 if ( (Fields
& osl_Process_CPUTIMES
) && osl_getProcStat(pid
, &procstat
) )
1067 * We calculate only time of the process proper.
1068 * Threads are processes, we do not consider their time here!
1069 * (For this, cutime and cstime should be used, it seems not
1070 * to work in 2.0.36)
1075 unsigned long userseconds
;
1076 unsigned long systemseconds
;
1078 clktck
= sysconf(_SC_CLK_TCK
);
1080 return osl_Process_E_Unknown
;
1082 hz
= static_cast<unsigned long>(clktck
);
1084 userseconds
= procstat
.utime
/hz
;
1085 systemseconds
= procstat
.stime
/hz
;
1087 pInfo
->UserTime
.Seconds
= userseconds
;
1088 pInfo
->UserTime
.Nanosec
= procstat
.utime
- (userseconds
* hz
);
1089 pInfo
->SystemTime
.Seconds
= systemseconds
;
1090 pInfo
->SystemTime
.Nanosec
= procstat
.stime
- (systemseconds
* hz
);
1092 pInfo
->Fields
|= osl_Process_CPUTIMES
;
1095 if ( (Fields
& osl_Process_HEAPUSAGE
) && osl_getProcStatus(pid
, &procstat
) )
1099 * vm_data (found in status) shows the size of the data segment
1100 * it a rough approximation of the core heap size
1102 pInfo
->HeapUsage
= procstat
.vm_data
*1024;
1104 pInfo
->Fields
|= osl_Process_HEAPUSAGE
;
1108 return (pInfo
->Fields
== Fields
) ? osl_Process_E_None
: osl_Process_E_Unknown
;
1113 return (pInfo
->Fields
== Fields
) ? osl_Process_E_None
: osl_Process_E_Unknown
;
1116 /** Helper function for osl_joinProcessWithTimeout
1119 static bool is_timeout(const struct timeval
* tend
)
1121 struct timeval tcurrent
;
1122 gettimeofday(&tcurrent
, nullptr);
1123 return (tcurrent
.tv_sec
>= tend
->tv_sec
);
1126 /* kill(pid, 0) is useful for checking if a
1127 process is still alive, but remember that
1128 kill even returns 0 if the process is already
1131 static bool is_process_dead(pid_t pid
)
1133 return ((kill(pid
, 0) == -1) && (ESRCH
== errno
));
1136 oslProcessError SAL_CALL
osl_joinProcessWithTimeout(oslProcess Process
, const TimeValue
* pTimeout
)
1138 oslProcessImpl
* pChild
= ChildList
;
1139 oslProcessError osl_error
= osl_Process_E_None
;
1141 OSL_PRECOND(Process
, "osl_joinProcess: Invalid parameter");
1142 OSL_ASSERT(ChildListMutex
);
1144 if (Process
== nullptr || ChildListMutex
== nullptr)
1145 return osl_Process_E_Unknown
;
1147 osl_acquireMutex(ChildListMutex
);
1149 /* check if process is a child of ours */
1150 while (pChild
!= nullptr)
1152 if (pChild
== static_cast<oslProcessImpl
*>(Process
))
1155 pChild
= pChild
->m_pnext
;
1158 osl_releaseMutex(ChildListMutex
);
1160 if (pChild
!= nullptr)
1162 oslConditionResult cond_res
= osl_waitCondition(pChild
->m_terminated
, pTimeout
);
1164 if (cond_res
== osl_cond_result_timeout
)
1165 osl_error
= osl_Process_E_TimedOut
;
1166 else if (cond_res
!= osl_cond_result_ok
)
1167 osl_error
= osl_Process_E_Unknown
;
1169 else /* alien process; StatusThread will not be able
1170 to set the condition terminated */
1172 pid_t pid
= static_cast<oslProcessImpl
*>(Process
)->m_pid
;
1176 bool timeout
= false;
1177 struct timeval tend
;
1179 gettimeofday(&tend
, nullptr);
1181 tend
.tv_sec
+= pTimeout
->Seconds
;
1183 while (!is_process_dead(pid
) && !(timeout
= is_timeout(&tend
)))
1187 osl_error
= osl_Process_E_TimedOut
;
1191 while (!is_process_dead(pid
))
1198 oslProcessError SAL_CALL
osl_joinProcess(oslProcess Process
)
1200 return osl_joinProcessWithTimeout(Process
, nullptr);
1203 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */