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>
44 #include "unixerrnostring.hxx"
46 # include <sys/procfs.h>
48 #include <osl/diagnose.h>
49 #include <osl/mutex.h>
50 #include <osl/process.h>
51 #include <osl/conditn.h>
52 #include <osl/thread.h>
54 #include <osl/file.hxx>
55 #include <osl/signal.h>
56 #include <rtl/alloc.h>
57 #include <sal/log.hxx>
61 #include "createfilehandlefromfd.hxx"
62 #include "file_url.hxx"
63 #include "readwrite_helper.hxx"
64 #include "sockimpl.hxx"
65 #include "secimpl.hxx"
73 struct oslProcessImpl
{
75 oslCondition m_terminated
;
77 oslProcessImpl
* m_pnext
;
82 const char* m_pszArgs
[MAX_ARGS
+ 1];
84 char* m_pszEnv
[MAX_ENVS
+ 1];
88 oslCondition m_started
;
89 oslProcessImpl
* m_pProcImpl
;
90 oslFileHandle
*m_pInputWrite
;
91 oslFileHandle
*m_pOutputRead
;
92 oslFileHandle
*m_pErrorRead
;
95 oslProcessImpl
* ChildList
;
96 oslMutex ChildListMutex
;
98 } //Anonymous namespace
100 static oslProcessError
osl_psz_executeProcess(char *pszImageName
,
101 char *pszArguments
[],
102 oslProcessOption Options
,
103 oslSecurity Security
,
105 char *pszEnvironments
[],
106 oslProcess
*pProcess
,
107 oslFileHandle
*pInputWrite
,
108 oslFileHandle
*pOutputRead
,
109 oslFileHandle
*pErrorRead
);
113 static void ChildStatusProc(void *pData
)
115 osl_setThreadName("osl_executeProcess");
119 int channel
[2] = { -1, -1 };
122 int stdOutput
[2] = { -1, -1 }, stdInput
[2] = { -1, -1 }, stdError
[2] = { -1, -1 };
124 pdata
= static_cast<ProcessData
*>(pData
);
126 /* make a copy of our data, because forking will only copy
127 our local stack of the thread, so the process data will not be accessible
128 in our child process */
129 memcpy(&data
, pData
, sizeof(data
));
131 #ifdef NO_CHILD_PROCESSES
132 #define fork() (errno = EINVAL, -1)
134 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, channel
) == -1)
137 SAL_WARN("sal.osl", "executeProcess socketpair() errno " << status
);
140 (void) fcntl(channel
[0], F_SETFD
, FD_CLOEXEC
);
141 (void) fcntl(channel
[1], F_SETFD
, FD_CLOEXEC
);
143 /* Create redirected IO pipes */
144 if ( status
== 0 && data
.m_pInputWrite
&& pipe( stdInput
) == -1 )
148 SAL_WARN("sal.osl", "executeProcess pipe(stdInput) errno " << status
);
151 if ( status
== 0 && data
.m_pOutputRead
&& pipe( stdOutput
) == -1 )
155 SAL_WARN("sal.osl", "executeProcess pipe(stdOutput) errno " << status
);
158 if ( status
== 0 && data
.m_pErrorRead
&& pipe( stdError
) == -1 )
162 SAL_WARN("sal.osl", "executeProcess pipe(stdError) errno " << status
);
165 if ( (status
== 0) && ((pid
= fork()) == 0) )
171 if (channel
[0] != -1) close(channel
[0]);
173 if ((data
.m_uid
!= uid_t(-1)) && ((data
.m_uid
!= getuid()) || (data
.m_gid
!= getgid())))
175 OSL_ASSERT(geteuid() == 0); /* must be root */
177 if (! INIT_GROUPS(data
.m_name
, data
.m_gid
) || (setuid(data
.m_uid
) != 0))
179 // ignore; can't do much about it here after fork
186 chstatus
= chdir(data
.m_pszDir
);
188 if (chstatus
== 0 && ((data
.m_uid
== uid_t(-1)) || ((data
.m_uid
== getuid()) && (data
.m_gid
== getgid()))))
191 for (i
= 0; data
.m_pszEnv
[i
] != nullptr; i
++)
193 if (strchr(data
.m_pszEnv
[i
], '=') == nullptr)
195 unsetenv(data
.m_pszEnv
[i
]); /*TODO: check error return*/
199 putenv(data
.m_pszEnv
[i
]); /*TODO: check error return*/
203 /* Connect std IO to pipe ends */
205 /* Write end of stdInput not used in child process */
206 if (stdInput
[1] != -1) close( stdInput
[1] );
208 /* Read end of stdOutput not used in child process */
209 if (stdOutput
[0] != -1) close( stdOutput
[0] );
211 /* Read end of stdError not used in child process */
212 if (stdError
[0] != -1) close( stdError
[0] );
214 /* Redirect pipe ends to std IO */
216 if ( stdInput
[0] != STDIN_FILENO
)
218 dup2( stdInput
[0], STDIN_FILENO
);
219 if (stdInput
[0] != -1) close( stdInput
[0] );
222 if ( stdOutput
[1] != STDOUT_FILENO
)
224 dup2( stdOutput
[1], STDOUT_FILENO
);
225 if (stdOutput
[1] != -1) close( stdOutput
[1] );
228 if ( stdError
[1] != STDERR_FILENO
)
230 dup2( stdError
[1], STDERR_FILENO
);
231 if (stdError
[1] != -1) close( stdError
[1] );
234 // No need to check the return value of execv. If we return from
235 // it, an error has occurred.
236 execv(data
.m_pszArgs
[0], const_cast<char **>(data
.m_pszArgs
));
239 /* if we reach here, something went wrong */
241 if ( !safeWrite(channel
[1], &errno_copy
, sizeof(errno_copy
)) )
243 // ignore; can't do much about it here after fork
246 if ( channel
[1] != -1 )
254 if (channel
[1] != -1) close(channel
[1]);
256 /* Close unused pipe ends */
257 if (stdInput
[0] != -1) close( stdInput
[0] );
258 if (stdOutput
[1] != -1) close( stdOutput
[1] );
259 if (stdError
[1] != -1) close( stdError
[1] );
263 while ((i
= read(channel
[0], &status
, sizeof(status
))) < 0)
270 if (channel
[0] != -1) close(channel
[0]);
272 if ((pid
> 0) && (i
== 0))
275 osl_acquireMutex(ChildListMutex
);
277 pdata
->m_pProcImpl
->m_pid
= pid
;
278 pdata
->m_pProcImpl
->m_pnext
= ChildList
;
279 ChildList
= pdata
->m_pProcImpl
;
281 /* Store used pipe ends in data structure */
283 if ( pdata
->m_pInputWrite
)
284 *(pdata
->m_pInputWrite
) = osl::detail::createFileHandleFromFD( stdInput
[1] );
286 if ( pdata
->m_pOutputRead
)
287 *(pdata
->m_pOutputRead
) = osl::detail::createFileHandleFromFD( stdOutput
[0] );
289 if ( pdata
->m_pErrorRead
)
290 *(pdata
->m_pErrorRead
) = osl::detail::createFileHandleFromFD( stdError
[0] );
292 osl_releaseMutex(ChildListMutex
);
294 osl_setCondition(pdata
->m_started
);
298 child_pid
= waitpid(pid
, &status
, 0);
299 } while ( 0 > child_pid
&& EINTR
== errno
);
303 SAL_WARN("sal.osl", "Failed to wait for child process: " << UnixErrnoString(errno
));
306 We got another error than EINTR. Anyway we have to wake up the
307 waiting thread under any circumstances */
314 oslProcessImpl
* pChild
;
316 osl_acquireMutex(ChildListMutex
);
320 /* check if it is one of our child processes */
321 while (pChild
!= nullptr)
323 if (pChild
->m_pid
== child_pid
)
325 if (WIFEXITED(status
))
326 pChild
->m_status
= WEXITSTATUS(status
);
327 else if (WIFSIGNALED(status
))
328 pChild
->m_status
= 128 + WTERMSIG(status
);
330 pChild
->m_status
= -1;
332 // coverity[lock_order : FALSE] - incorrect report of lock order error
333 osl_setCondition(pChild
->m_terminated
);
336 pChild
= pChild
->m_pnext
;
339 osl_releaseMutex(ChildListMutex
);
344 SAL_WARN("sal.osl", "ChildStatusProc : starting '" << data
.m_pszArgs
[0] << "' failed");
345 SAL_WARN("sal.osl", "Failed to launch child process, child reports " << UnixErrnoString(status
));
347 /* Close pipe ends */
348 if ( pdata
->m_pInputWrite
)
349 *pdata
->m_pInputWrite
= nullptr;
351 if ( pdata
->m_pOutputRead
)
352 *pdata
->m_pOutputRead
= nullptr;
354 if ( pdata
->m_pErrorRead
)
355 *pdata
->m_pErrorRead
= nullptr;
357 if (stdInput
[1] != -1) close( stdInput
[1] );
358 if (stdOutput
[0] != -1) close( stdOutput
[0] );
359 if (stdError
[0] != -1) close( stdError
[0] );
361 /* if pid > 0 then a process was created, even if it later failed
362 e.g. bash searching for a command to execute, and we still
363 need to clean it up to avoid "defunct" processes */
369 child_pid
= waitpid(pid
, &status
, 0);
370 } while ( 0 > child_pid
&& EINTR
== errno
);
373 /* notify (and unblock) parent thread */
374 osl_setCondition(pdata
->m_started
);
381 oslProcessError SAL_CALL
osl_executeProcess_WithRedirectedIO(
382 rtl_uString
*ustrImageName
,
383 rtl_uString
*ustrArguments
[],
384 sal_uInt32 nArguments
,
385 oslProcessOption Options
,
386 oslSecurity Security
,
387 rtl_uString
*ustrWorkDir
,
388 rtl_uString
*ustrEnvironment
[],
389 sal_uInt32 nEnvironmentVars
,
390 oslProcess
*pProcess
,
391 oslFileHandle
*pInputWrite
,
392 oslFileHandle
*pOutputRead
,
393 oslFileHandle
*pErrorRead
397 if (ustrImageName
== nullptr)
401 return osl_Process_E_InvalidError
;
403 image
= OUString::unacquired(ustrArguments
);
407 osl::FileBase::RC e
= osl::FileBase::getSystemPathFromFileURL(
408 OUString::unacquired(&ustrImageName
), image
);
409 if (e
!= osl::FileBase::E_None
)
413 "getSystemPathFromFileURL("
414 << OUString::unacquired(&ustrImageName
)
415 << ") failed with " << e
);
416 return osl_Process_E_Unknown
;
420 if ((Options
& osl_Process_SEARCHPATH
) != 0)
423 if (osl::detail::find_in_PATH(image
, path
))
429 oslProcessError Error
;
430 char* pszWorkDir
=nullptr;
431 char** pArguments
=nullptr;
432 char** pEnvironment
=nullptr;
435 char szImagePath
[PATH_MAX
] = "";
438 szImagePath
, SAL_N_ELEMENTS(szImagePath
), image
.getStr(),
443 SAL_INFO("sal.osl", "UnicodeToText(" << image
<< ") failed with " << e
);
444 return osl_Process_E_Unknown
;
447 char szWorkDir
[PATH_MAX
] = "";
448 if ( ustrWorkDir
!= nullptr && ustrWorkDir
->length
)
450 oslFileError e
= FileURLToPath( szWorkDir
, PATH_MAX
, ustrWorkDir
);
451 if (e
!= osl_File_E_None
)
455 "FileURLToPath(" << OUString::unacquired(&ustrWorkDir
)
456 << ") failed with " << e
);
457 return osl_Process_E_Unknown
;
459 pszWorkDir
= szWorkDir
;
462 if ( pArguments
== nullptr && nArguments
> 0 )
464 pArguments
= static_cast<char**>(malloc( ( nArguments
+ 2 ) * sizeof(char*) ));
467 for ( idx
= 0 ; idx
< nArguments
; ++idx
)
469 rtl_String
* strArg
=nullptr;
471 rtl_uString2String( &strArg
,
472 rtl_uString_getStr(ustrArguments
[idx
]),
473 rtl_uString_getLength(ustrArguments
[idx
]),
474 osl_getThreadTextEncoding(),
475 OUSTRING_TO_OSTRING_CVTFLAGS
);
477 pArguments
[idx
]=strdup(rtl_string_getStr(strArg
));
478 rtl_string_release(strArg
);
479 pArguments
[idx
+1]=nullptr;
482 for ( idx
= 0 ; idx
< nEnvironmentVars
; ++idx
)
484 rtl_String
* strEnv
=nullptr;
486 if ( pEnvironment
== nullptr )
488 pEnvironment
= static_cast<char**>(malloc( ( nEnvironmentVars
+ 2 ) * sizeof(char*) ));
491 rtl_uString2String( &strEnv
,
492 rtl_uString_getStr(ustrEnvironment
[idx
]),
493 rtl_uString_getLength(ustrEnvironment
[idx
]),
494 osl_getThreadTextEncoding(),
495 OUSTRING_TO_OSTRING_CVTFLAGS
);
497 pEnvironment
[idx
]=strdup(rtl_string_getStr(strEnv
));
498 rtl_string_release(strEnv
);
499 pEnvironment
[idx
+1]=nullptr;
502 Error
= osl_psz_executeProcess(szImagePath
,
514 if ( pArguments
!= nullptr )
516 for ( idx
= 0 ; idx
< nArguments
; ++idx
)
518 if ( pArguments
[idx
] != nullptr )
520 free(pArguments
[idx
]);
526 if ( pEnvironment
!= nullptr )
528 for ( idx
= 0 ; idx
< nEnvironmentVars
; ++idx
)
530 if ( pEnvironment
[idx
] != nullptr )
532 free(pEnvironment
[idx
]);
541 oslProcessError SAL_CALL
osl_executeProcess(
542 rtl_uString
*ustrImageName
,
543 rtl_uString
*ustrArguments
[],
544 sal_uInt32 nArguments
,
545 oslProcessOption Options
,
546 oslSecurity Security
,
547 rtl_uString
*ustrWorkDir
,
548 rtl_uString
*ustrEnvironment
[],
549 sal_uInt32 nEnvironmentVars
,
553 return osl_executeProcess_WithRedirectedIO(
569 oslProcessError
osl_psz_executeProcess(char *pszImageName
,
570 char *pszArguments
[],
571 oslProcessOption Options
,
572 oslSecurity Security
,
574 char *pszEnvironments
[],
575 oslProcess
*pProcess
,
576 oslFileHandle
*pInputWrite
,
577 oslFileHandle
*pOutputRead
,
578 oslFileHandle
*pErrorRead
585 memset(&Data
,0,sizeof(ProcessData
));
586 Data
.m_pInputWrite
= pInputWrite
;
587 Data
.m_pOutputRead
= pOutputRead
;
588 Data
.m_pErrorRead
= pErrorRead
;
590 OSL_ASSERT(pszImageName
!= nullptr);
592 if ( pszImageName
== nullptr )
594 return osl_Process_E_NotFound
;
597 Data
.m_pszArgs
[0] = strdup(pszImageName
);
598 Data
.m_pszArgs
[1] = nullptr;
600 if ( pszArguments
!= nullptr )
602 for (i
= 0; ((i
+ 2) < MAX_ARGS
) && (pszArguments
[i
] != nullptr); i
++)
603 Data
.m_pszArgs
[i
+1] = strdup(pszArguments
[i
]);
604 Data
.m_pszArgs
[i
+2] = nullptr;
607 Data
.m_pszDir
= (pszDirectory
!= nullptr) ? strdup(pszDirectory
) : nullptr;
609 if (pszEnvironments
!= nullptr)
611 for (i
= 0; ((i
+ 1) < MAX_ENVS
) && (pszEnvironments
[i
] != nullptr); i
++)
612 Data
.m_pszEnv
[i
] = strdup(pszEnvironments
[i
]);
613 Data
.m_pszEnv
[i
+1] = nullptr;
616 Data
.m_pszEnv
[0] = nullptr;
618 if (Security
!= nullptr)
620 Data
.m_uid
= static_cast<oslSecurityImpl
*>(Security
)->m_pPasswd
.pw_uid
;
621 Data
.m_gid
= static_cast<oslSecurityImpl
*>(Security
)->m_pPasswd
.pw_gid
;
622 Data
.m_name
= static_cast<oslSecurityImpl
*>(Security
)->m_pPasswd
.pw_name
;
625 Data
.m_uid
= uid_t(-1);
627 Data
.m_pProcImpl
= static_cast<oslProcessImpl
*>(malloc(sizeof(oslProcessImpl
)));
628 Data
.m_pProcImpl
->m_pid
= 0;
629 Data
.m_pProcImpl
->m_terminated
= osl_createCondition();
630 Data
.m_pProcImpl
->m_pnext
= nullptr;
632 if (ChildListMutex
== nullptr)
633 ChildListMutex
= osl_createMutex();
635 Data
.m_started
= osl_createCondition();
637 hThread
= osl_createThread(ChildStatusProc
, &Data
);
639 if (hThread
!= nullptr)
641 osl_waitCondition(Data
.m_started
, nullptr);
643 osl_destroyCondition(Data
.m_started
);
645 for (i
= 0; Data
.m_pszArgs
[i
] != nullptr; i
++)
646 free(const_cast<char *>(Data
.m_pszArgs
[i
]));
648 for (i
= 0; Data
.m_pszEnv
[i
] != nullptr; i
++)
649 free(Data
.m_pszEnv
[i
]);
651 if ( Data
.m_pszDir
!= nullptr )
653 free(const_cast<char *>(Data
.m_pszDir
));
656 osl_destroyThread(hThread
);
658 if (Data
.m_pProcImpl
->m_pid
!= 0)
660 assert(hThread
!= nullptr);
662 *pProcess
= Data
.m_pProcImpl
;
664 if (Options
& osl_Process_WAIT
)
665 osl_joinProcess(*pProcess
);
667 return osl_Process_E_None
;
670 osl_destroyCondition(Data
.m_pProcImpl
->m_terminated
);
671 free(Data
.m_pProcImpl
);
673 return osl_Process_E_Unknown
;
676 oslProcessError SAL_CALL
osl_terminateProcess(oslProcess Process
)
678 if (Process
== nullptr)
679 return osl_Process_E_Unknown
;
681 if (kill(static_cast<oslProcessImpl
*>(Process
)->m_pid
, SIGKILL
) != 0)
686 return osl_Process_E_NoPermission
;
689 return osl_Process_E_NotFound
;
692 return osl_Process_E_Unknown
;
696 return osl_Process_E_None
;
699 oslProcess SAL_CALL
osl_getProcess(oslProcessIdentifier Ident
)
701 oslProcessImpl
*pProcImpl
;
703 if (kill(Ident
, 0) != -1)
705 oslProcessImpl
* pChild
;
707 if (ChildListMutex
== nullptr)
708 ChildListMutex
= osl_createMutex();
710 osl_acquireMutex(ChildListMutex
);
714 /* check if it is one of our child processes */
715 while (pChild
!= nullptr)
717 if (Ident
== static_cast<sal_uInt32
>(pChild
->m_pid
))
720 pChild
= pChild
->m_pnext
;
723 pProcImpl
= static_cast<oslProcessImpl
*>(malloc(sizeof(oslProcessImpl
)));
724 pProcImpl
->m_pid
= Ident
;
725 pProcImpl
->m_terminated
= osl_createCondition();
727 if (pChild
!= nullptr)
729 /* process is a child so insert into list */
730 pProcImpl
->m_pnext
= pChild
->m_pnext
;
731 pChild
->m_pnext
= pProcImpl
;
733 pProcImpl
->m_status
= pChild
->m_status
;
735 // coverity[lock_order : FALSE] - incorrect report of lock order error
736 if (osl_checkCondition(pChild
->m_terminated
))
738 // coverity[lock_order : FALSE] - incorrect report of lock order error
739 osl_setCondition(pProcImpl
->m_terminated
);
743 pProcImpl
->m_pnext
= nullptr;
745 osl_releaseMutex(ChildListMutex
);
753 void SAL_CALL
osl_freeProcessHandle(oslProcess Process
)
755 if (Process
== nullptr)
758 oslProcessImpl
*pChild
, *pPrev
= nullptr;
760 OSL_ASSERT(ChildListMutex
!= nullptr);
762 if ( ChildListMutex
== nullptr )
767 osl_acquireMutex(ChildListMutex
);
771 /* remove process from child list */
772 while (pChild
!= nullptr)
774 if (pChild
== static_cast<oslProcessImpl
*>(Process
))
776 if (pPrev
!= nullptr)
777 pPrev
->m_pnext
= pChild
->m_pnext
;
779 ChildList
= pChild
->m_pnext
;
785 pChild
= pChild
->m_pnext
;
788 osl_releaseMutex(ChildListMutex
);
790 osl_destroyCondition(static_cast<oslProcessImpl
*>(Process
)->m_terminated
);
802 char command
[16]; /* 'argv[0]' */ /* mfe: it all right char comm[16] in kernel! */
803 char state
; /* state (running, stopped, ...) */
804 pid_t ppid
; /* parent pid */
805 pid_t pgrp
; /* parent group */
806 int session
; /* session ID */
807 int tty
; /* no of tty */
808 pid_t tpgid
; /* group of process owning the tty */
809 unsigned long flags
; /* flags dunno */
810 unsigned long minflt
; /* minor page faults */
811 unsigned long cminflt
; /* minor page faults with children */
812 unsigned long majflt
; /* major page faults */
813 unsigned long cmajflt
; /* major page faults with children */
814 unsigned long utime
; /* no of jiffies in user mode */
815 unsigned long stime
; /* no of jiffies in kernel mode */
816 unsigned long cutime
; /* no of jiffies in user mode with children */
817 unsigned long cstime
; /* no of jiffies in kernel mode with children */
818 unsigned long priority
; /* nice value + 15 (kernel scheduling prio)*/
819 long nice
; /* nice value */
820 long timeout
; /* no of jiffies of next process timeout */
821 long itrealvalue
; /* no jiffies before next SIGALRM */
822 unsigned long starttime
; /* process started this no of jiffies after boot */
823 unsigned long vsize
; /* virtual memory size (in bytes) */
824 long rss
; /* resident set size (in pages) */
825 unsigned long rss_rlim
; /* rss limit (in bytes) */
826 unsigned long startcode
; /* address above program text can run */
827 unsigned long endcode
; /* address below program text can run */
828 unsigned long startstack
; /* address of start of stack */
829 unsigned long kstkesp
; /* current value of 'esp' (stack pointer) */
830 unsigned long kstkeip
; /* current value of 'eip' (instruction pointer) */
831 /* mfe: Linux > 2.1.7x have more signals (88) */
832 char signal
[24]; /* pending signals */
833 char blocked
[24]; /* blocked signals */
834 char sigignore
[24]; /* ignored signals */
835 char sigcatch
[24]; /* caught signals */
836 unsigned long wchan
; /* 'channel' the process is waiting in */
837 unsigned long nswap
; /* ? */
838 unsigned long cnswap
; /* ? */
841 int ruid
; /* real uid */
842 int euid
; /* effective uid */
843 int suid
; /* saved uid */
844 int fuid
; /* file access uid */
845 int rgid
; /* real gid */
846 int egid
; /* effective gid */
847 int sgid
; /* saved gid */
848 int fgid
; /* file access gid */
849 unsigned long vm_size
; /* like vsize but on kb */
850 unsigned long vm_lock
; /* locked pages in kb */
851 unsigned long vm_rss
; /* like rss but in kb */
852 unsigned long vm_data
; /* data size */
853 unsigned long vm_stack
; /* stack size */
854 unsigned long vm_exe
; /* executable size */
855 unsigned long vm_lib
; /* library size */
860 static bool osl_getProcStat(pid_t pid
, struct osl_procStat
* procstat
)
864 char name
[PATH_MAX
+ 1];
865 snprintf(name
, sizeof(name
), "/proc/%u/stat", pid
);
867 if ((fd
= open(name
,O_RDONLY
)) >=0 )
871 memset(prstatbuf
,0,512);
872 bRet
= safeRead(fd
, prstatbuf
, 511);
879 tmp
= strrchr(prstatbuf
, ')');
884 memset(procstat
->command
, 0, sizeof(procstat
->command
));
886 sscanf(prstatbuf
, "%d (%15c", &procstat
->pid
, procstat
->command
);
890 "%lu %lu %lu %lu %lu"
894 "%lu %lu %lu %lu %lu"
895 "%23s %23s %23s %23s"
898 &procstat
->ppid
, &procstat
->pgrp
, &procstat
->session
, &procstat
->tty
, &procstat
->tpgid
,
899 &procstat
->flags
, &procstat
->minflt
, &procstat
->cminflt
, &procstat
->majflt
, &procstat
->cmajflt
,
900 &procstat
->utime
, &procstat
->stime
, &procstat
->cutime
, &procstat
->cstime
,
901 &procstat
->priority
, &procstat
->nice
, &procstat
->timeout
, &procstat
->itrealvalue
,
902 &procstat
->starttime
, &procstat
->vsize
, &procstat
->rss
, &procstat
->rss_rlim
,
903 &procstat
->startcode
, &procstat
->endcode
, &procstat
->startstack
, &procstat
->kstkesp
, &procstat
->kstkeip
,
904 procstat
->signal
, procstat
->blocked
, procstat
->sigignore
, procstat
->sigcatch
,
905 &procstat
->wchan
, &procstat
->nswap
, &procstat
->cnswap
916 static bool osl_getProcStatus(pid_t pid
, struct osl_procStat
* procstat
)
919 char name
[PATH_MAX
+ 1];
922 snprintf(name
, sizeof(name
), "/proc/%u/status", pid
);
924 if ((fd
= open(name
,O_RDONLY
)) >=0 )
927 char prstatusbuf
[512];
928 memset(prstatusbuf
,0,512);
929 bRet
= safeRead(fd
, prstatusbuf
, 511);
936 tmp
= strstr(prstatusbuf
,"Uid:");
939 sscanf(tmp
,"Uid:\t%d\t%d\t%d\t%d",
940 &procstat
->ruid
, &procstat
->euid
, &procstat
->suid
, &procstat
->fuid
944 tmp
= strstr(prstatusbuf
,"Gid:");
947 sscanf(tmp
,"Gid:\t%d\t%d\t%d\t%d",
948 &procstat
->rgid
, &procstat
->egid
, &procstat
->sgid
, &procstat
->fgid
952 tmp
= strstr(prstatusbuf
,"VmSize:");
963 &procstat
->vm_size
, &procstat
->vm_lock
, &procstat
->vm_rss
, &procstat
->vm_data
,
964 &procstat
->vm_stack
, &procstat
->vm_exe
, &procstat
->vm_lib
968 tmp
= strstr(prstatusbuf
,"SigPnd:");
971 sscanf(tmp
, "SigPnd: %23s SigBlk: %23s SigIgn: %23s %*s %23s",
972 procstat
->signal
, procstat
->blocked
, procstat
->sigignore
, procstat
->sigcatch
981 oslProcessError SAL_CALL
osl_getProcessInfo(oslProcess Process
, oslProcessData Fields
, oslProcessInfo
* pInfo
)
985 if (Process
== nullptr)
988 pid
= static_cast<oslProcessImpl
*>(Process
)->m_pid
;
990 if (! pInfo
|| (pInfo
->Size
!= sizeof(oslProcessInfo
)))
991 return osl_Process_E_Unknown
;
995 if (Fields
& osl_Process_IDENTIFIER
)
998 pInfo
->Fields
|= osl_Process_IDENTIFIER
;
1001 if (Fields
& osl_Process_EXITCODE
)
1003 if ((Process
!= nullptr) &&
1004 osl_checkCondition(static_cast<oslProcessImpl
*>(Process
)->m_terminated
))
1006 pInfo
->Code
= static_cast<oslProcessImpl
*>(Process
)->m_status
;
1007 pInfo
->Fields
|= osl_Process_EXITCODE
;
1011 if (Fields
& (osl_Process_HEAPUSAGE
| osl_Process_CPUTIMES
))
1017 char name
[PATH_MAX
+ 1];
1019 snprintf(name
, sizeof(name
), "/proc/%ld", (long)pid
);
1021 if ((fd
= open(name
, O_RDONLY
)) >= 0)
1023 prstatus_t prstatus
;
1025 if (ioctl(fd
, PIOCSTATUS
, &prstatus
) >= 0)
1027 if (Fields
& osl_Process_CPUTIMES
)
1029 pInfo
->UserTime
.Seconds
= prstatus
.pr_utime
.tv_sec
;
1030 pInfo
->UserTime
.Nanosec
= prstatus
.pr_utime
.tv_nsec
;
1031 pInfo
->SystemTime
.Seconds
= prstatus
.pr_stime
.tv_sec
;
1032 pInfo
->SystemTime
.Nanosec
= prstatus
.pr_stime
.tv_nsec
;
1034 pInfo
->Fields
|= osl_Process_CPUTIMES
;
1037 if (Fields
& osl_Process_HEAPUSAGE
)
1039 pInfo
->HeapUsage
= prstatus
.pr_brksize
;
1041 pInfo
->Fields
|= osl_Process_HEAPUSAGE
;
1046 return (pInfo
->Fields
== Fields
) ? osl_Process_E_None
: osl_Process_E_Unknown
;
1052 #elif defined(LINUX)
1054 if ( (Fields
& osl_Process_CPUTIMES
) || (Fields
& osl_Process_HEAPUSAGE
) )
1056 struct osl_procStat procstat
;
1057 memset(&procstat
,0,sizeof(procstat
));
1059 if ( (Fields
& osl_Process_CPUTIMES
) && osl_getProcStat(pid
, &procstat
) )
1063 * We calculate only time of the process proper.
1064 * Threads are processes, we do not consider their time here!
1065 * (For this, cutime and cstime should be used, it seems not
1066 * to work in 2.0.36)
1071 unsigned long userseconds
;
1072 unsigned long systemseconds
;
1074 clktck
= sysconf(_SC_CLK_TCK
);
1076 return osl_Process_E_Unknown
;
1078 hz
= static_cast<unsigned long>(clktck
);
1080 userseconds
= procstat
.utime
/hz
;
1081 systemseconds
= procstat
.stime
/hz
;
1083 pInfo
->UserTime
.Seconds
= userseconds
;
1084 pInfo
->UserTime
.Nanosec
= procstat
.utime
- (userseconds
* hz
);
1085 pInfo
->SystemTime
.Seconds
= systemseconds
;
1086 pInfo
->SystemTime
.Nanosec
= procstat
.stime
- (systemseconds
* hz
);
1088 pInfo
->Fields
|= osl_Process_CPUTIMES
;
1091 if ( (Fields
& osl_Process_HEAPUSAGE
) && osl_getProcStatus(pid
, &procstat
) )
1095 * vm_data (found in status) shows the size of the data segment
1096 * it a rough approximation of the core heap size
1098 pInfo
->HeapUsage
= procstat
.vm_data
*1024;
1100 pInfo
->Fields
|= osl_Process_HEAPUSAGE
;
1104 return (pInfo
->Fields
== Fields
) ? osl_Process_E_None
: osl_Process_E_Unknown
;
1109 return (pInfo
->Fields
== Fields
) ? osl_Process_E_None
: osl_Process_E_Unknown
;
1112 /** Helper function for osl_joinProcessWithTimeout
1115 static bool is_timeout(const struct timeval
* tend
)
1117 struct timeval tcurrent
;
1118 gettimeofday(&tcurrent
, nullptr);
1119 return (tcurrent
.tv_sec
>= tend
->tv_sec
);
1122 /* kill(pid, 0) is useful for checking if a
1123 process is still alive, but remember that
1124 kill even returns 0 if the process is already
1127 static bool is_process_dead(pid_t pid
)
1129 return ((kill(pid
, 0) == -1) && (ESRCH
== errno
));
1132 oslProcessError SAL_CALL
osl_joinProcessWithTimeout(oslProcess Process
, const TimeValue
* pTimeout
)
1134 oslProcessImpl
* pChild
= ChildList
;
1135 oslProcessError osl_error
= osl_Process_E_None
;
1137 OSL_PRECOND(Process
, "osl_joinProcess: Invalid parameter");
1138 OSL_ASSERT(ChildListMutex
);
1140 if (Process
== nullptr || ChildListMutex
== nullptr)
1141 return osl_Process_E_Unknown
;
1143 osl_acquireMutex(ChildListMutex
);
1145 /* check if process is a child of ours */
1146 while (pChild
!= nullptr)
1148 if (pChild
== static_cast<oslProcessImpl
*>(Process
))
1151 pChild
= pChild
->m_pnext
;
1154 osl_releaseMutex(ChildListMutex
);
1156 if (pChild
!= nullptr)
1158 oslConditionResult cond_res
= osl_waitCondition(pChild
->m_terminated
, pTimeout
);
1160 if (cond_res
== osl_cond_result_timeout
)
1161 osl_error
= osl_Process_E_TimedOut
;
1162 else if (cond_res
!= osl_cond_result_ok
)
1163 osl_error
= osl_Process_E_Unknown
;
1165 else /* alien process; StatusThread will not be able
1166 to set the condition terminated */
1168 pid_t pid
= static_cast<oslProcessImpl
*>(Process
)->m_pid
;
1172 bool timeout
= false;
1173 struct timeval tend
;
1175 gettimeofday(&tend
, nullptr);
1177 tend
.tv_sec
+= pTimeout
->Seconds
;
1179 while (!is_process_dead(pid
) && !(timeout
= is_timeout(&tend
)))
1183 osl_error
= osl_Process_E_TimedOut
;
1187 while (!is_process_dead(pid
))
1194 oslProcessError SAL_CALL
osl_joinProcess(oslProcess Process
)
1196 return osl_joinProcessWithTimeout(Process
, nullptr);
1199 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */