Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sal / osl / unx / process.cxx
blob7d6936265c0b6aa29bf1e8cfbf279b2e0b64ca0b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
23 #include <cassert>
26 * ToDo:
27 * - cleanup of process status things
28 * - cleanup of process spawning
29 * - cleanup of resource transfer
32 #if defined(__sun)
33 // The procfs may only be used without LFS in 32bits.
34 # ifdef _FILE_OFFSET_BITS
35 # undef _FILE_OFFSET_BITS
36 # endif
37 #endif
39 #if defined(FREEBSD) || defined(NETBSD) || defined(DRAGONFLY)
40 #include <machine/param.h>
41 #endif
43 #include "system.hxx"
44 #include "unixerrnostring.hxx"
45 #if defined(__sun)
46 # include <sys/procfs.h>
47 #endif
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>
53 #include <osl/file.h>
54 #include <osl/file.hxx>
55 #include <osl/signal.h>
56 #include <rtl/alloc.h>
57 #include <sal/log.hxx>
59 #include <grp.h>
61 #include "createfilehandlefromfd.hxx"
62 #include "file_url.hxx"
63 #include "readwrite_helper.hxx"
64 #include "sockimpl.hxx"
65 #include "secimpl.hxx"
67 #define MAX_ARGS 255
68 #define MAX_ENVS 255
70 namespace
73 struct oslProcessImpl {
74 pid_t m_pid;
75 oslCondition m_terminated;
76 int m_status;
77 oslProcessImpl* m_pnext;
80 struct ProcessData
82 const char* m_pszArgs[MAX_ARGS + 1];
83 const char* m_pszDir;
84 char* m_pszEnv[MAX_ENVS + 1];
85 uid_t m_uid;
86 gid_t m_gid;
87 char* m_name;
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,
104 char *pszDirectory,
105 char *pszEnvironments[],
106 oslProcess *pProcess,
107 oslFileHandle *pInputWrite,
108 oslFileHandle *pOutputRead,
109 oslFileHandle *pErrorRead );
111 extern "C" {
113 static void ChildStatusProc(void *pData)
115 osl_setThreadName("osl_executeProcess");
117 pid_t pid = -1;
118 int status = 0;
119 int channel[2] = { -1, -1 };
120 ProcessData data;
121 ProcessData *pdata;
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)
133 #endif
134 if (socketpair(AF_UNIX, SOCK_STREAM, 0, channel) == -1)
136 status = errno;
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 )
146 status = errno;
147 assert(status != 0);
148 SAL_WARN("sal.osl", "executeProcess pipe(stdInput) errno " << status);
151 if ( status == 0 && data.m_pOutputRead && pipe( stdOutput ) == -1 )
153 status = errno;
154 assert(status != 0);
155 SAL_WARN("sal.osl", "executeProcess pipe(stdOutput) errno " << status);
158 if ( status == 0 && data.m_pErrorRead && pipe( stdError ) == -1 )
160 status = errno;
161 assert(status != 0);
162 SAL_WARN("sal.osl", "executeProcess pipe(stdError) errno " << status);
165 if ( (status == 0) && ((pid = fork()) == 0) )
167 /* Child */
168 int chstatus = 0;
169 int errno_copy;
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
182 unsetenv("HOME");
185 if (data.m_pszDir)
186 chstatus = chdir(data.m_pszDir);
188 if (chstatus == 0 && ((data.m_uid == uid_t(-1)) || ((data.m_uid == getuid()) && (data.m_gid == getgid()))))
190 int i;
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*/
197 else
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 */
240 errno_copy = errno;
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 )
247 close(channel[1]);
249 _exit(255);
251 else
252 { /* Parent */
253 int i = -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] );
261 if (pid > 0)
263 while ((i = read(channel[0], &status, sizeof(status))) < 0)
265 if (errno != EINTR)
266 break;
270 if (channel[0] != -1) close(channel[0]);
272 if ((pid > 0) && (i == 0))
274 pid_t child_pid;
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 );
301 if ( child_pid < 0)
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 */
309 child_pid = pid;
312 if ( child_pid > 0 )
314 oslProcessImpl* pChild;
316 osl_acquireMutex(ChildListMutex);
318 pChild = ChildList;
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);
329 else
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);
342 else
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 */
364 if (pid > 0)
366 pid_t child_pid;
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
396 OUString image;
397 if (ustrImageName == nullptr)
399 if (nArguments == 0)
401 return osl_Process_E_InvalidError;
403 image = OUString::unacquired(ustrArguments);
405 else
407 osl::FileBase::RC e = osl::FileBase::getSystemPathFromFileURL(
408 OUString::unacquired(&ustrImageName), image);
409 if (e != osl::FileBase::E_None)
411 SAL_INFO(
412 "sal.osl",
413 "getSystemPathFromFileURL("
414 << OUString::unacquired(&ustrImageName)
415 << ") failed with " << e);
416 return osl_Process_E_Unknown;
420 if ((Options & osl_Process_SEARCHPATH) != 0)
422 OUString path;
423 if (osl::detail::find_in_PATH(image, path))
425 image = path;
429 oslProcessError Error;
430 char* pszWorkDir=nullptr;
431 char** pArguments=nullptr;
432 char** pEnvironment=nullptr;
433 unsigned int idx;
435 char szImagePath[PATH_MAX] = "";
436 if (!image.isEmpty()
437 && (UnicodeToText(
438 szImagePath, SAL_N_ELEMENTS(szImagePath), image.getStr(),
439 image.getLength())
440 == 0))
442 int e = errno;
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)
453 SAL_INFO(
454 "sal.osl",
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,
503 pArguments,
504 Options,
505 Security,
506 pszWorkDir,
507 pEnvironment,
508 pProcess,
509 pInputWrite,
510 pOutputRead,
511 pErrorRead
514 if ( pArguments != nullptr )
516 for ( idx = 0 ; idx < nArguments ; ++idx )
518 if ( pArguments[idx] != nullptr )
520 free(pArguments[idx]);
523 free(pArguments);
526 if ( pEnvironment != nullptr )
528 for ( idx = 0 ; idx < nEnvironmentVars ; ++idx )
530 if ( pEnvironment[idx] != nullptr )
532 free(pEnvironment[idx]);
535 free(pEnvironment);
538 return Error;
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,
550 oslProcess *pProcess
553 return osl_executeProcess_WithRedirectedIO(
554 ustrImageName,
555 ustrArguments,
556 nArguments,
557 Options,
558 Security,
559 ustrWorkDir,
560 ustrEnvironment,
561 nEnvironmentVars,
562 pProcess,
563 nullptr,
564 nullptr,
565 nullptr
569 oslProcessError osl_psz_executeProcess(char *pszImageName,
570 char *pszArguments[],
571 oslProcessOption Options,
572 oslSecurity Security,
573 char *pszDirectory,
574 char *pszEnvironments[],
575 oslProcess *pProcess,
576 oslFileHandle *pInputWrite,
577 oslFileHandle *pOutputRead,
578 oslFileHandle *pErrorRead
581 int i;
582 ProcessData Data;
583 oslThread hThread;
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;
615 else
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;
624 else
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)
683 switch (errno)
685 case EPERM:
686 return osl_Process_E_NoPermission;
688 case ESRCH:
689 return osl_Process_E_NotFound;
691 default:
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);
712 pChild = ChildList;
714 /* check if it is one of our child processes */
715 while (pChild != nullptr)
717 if (Ident == static_cast<sal_uInt32>(pChild->m_pid))
718 break;
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);
742 else
743 pProcImpl->m_pnext = nullptr;
745 osl_releaseMutex(ChildListMutex);
747 else
748 pProcImpl = nullptr;
750 return pProcImpl;
753 void SAL_CALL osl_freeProcessHandle(oslProcess Process)
755 if (Process == nullptr)
756 return;
758 oslProcessImpl *pChild, *pPrev = nullptr;
760 OSL_ASSERT(ChildListMutex != nullptr);
762 if ( ChildListMutex == nullptr )
764 return;
767 osl_acquireMutex(ChildListMutex);
769 pChild = ChildList;
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;
778 else
779 ChildList = pChild->m_pnext;
781 break;
784 pPrev = pChild;
785 pChild = pChild->m_pnext;
788 osl_releaseMutex(ChildListMutex);
790 osl_destroyCondition(static_cast<oslProcessImpl*>(Process)->m_terminated);
792 free(Process);
795 #if defined(LINUX)
796 namespace {
798 struct osl_procStat
800 /* from 'stat' */
801 pid_t pid; /* pid */
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; /* ? */
840 /* from 'status' */
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)
862 int fd = 0;
863 bool bRet = false;
864 char name[PATH_MAX + 1];
865 snprintf(name, sizeof(name), "/proc/%u/stat", pid);
867 if ((fd = open(name,O_RDONLY)) >=0 )
869 char* tmp=nullptr;
870 char prstatbuf[512];
871 memset(prstatbuf,0,512);
872 bRet = safeRead(fd, prstatbuf, 511);
874 close(fd);
876 if (!bRet)
877 return false;
879 tmp = strrchr(prstatbuf, ')');
880 if(tmp)
882 *tmp = '\0';
884 memset(procstat->command, 0, sizeof(procstat->command));
886 sscanf(prstatbuf, "%d (%15c", &procstat->pid, procstat->command);
887 sscanf(tmp + 2,
888 "%c"
889 "%i %i %i %i %i"
890 "%lu %lu %lu %lu %lu"
891 "%lu %lu %lu %lu"
892 "%lu %li %li %li"
893 "%lu %lu %li %lu"
894 "%lu %lu %lu %lu %lu"
895 "%23s %23s %23s %23s"
896 "%lu %lu %lu",
897 &procstat->state,
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
908 else
910 bRet = false;
913 return bRet;
916 static bool osl_getProcStatus(pid_t pid, struct osl_procStat* procstat)
918 int fd = 0;
919 char name[PATH_MAX + 1];
920 bool bRet = false;
922 snprintf(name, sizeof(name), "/proc/%u/status", pid);
924 if ((fd = open(name,O_RDONLY)) >=0 )
926 char* tmp=nullptr;
927 char prstatusbuf[512];
928 memset(prstatusbuf,0,512);
929 bRet = safeRead(fd, prstatusbuf, 511);
931 close(fd);
933 if (!bRet)
934 return false;
936 tmp = strstr(prstatusbuf,"Uid:");
937 if(tmp)
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:");
945 if(tmp)
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:");
953 if(tmp)
955 sscanf(tmp,
956 "VmSize: %lu kB\n"
957 "VmLck: %lu kB\n"
958 "VmRSS: %lu kB\n"
959 "VmData: %lu kB\n"
960 "VmStk: %lu kB\n"
961 "VmExe: %lu kB\n"
962 "VmLib: %lu kB\n",
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:");
969 if(tmp)
971 sscanf(tmp, "SigPnd: %23s SigBlk: %23s SigIgn: %23s %*s %23s",
972 procstat->signal, procstat->blocked, procstat->sigignore, procstat->sigcatch
976 return bRet;
979 #endif
981 oslProcessError SAL_CALL osl_getProcessInfo(oslProcess Process, oslProcessData Fields, oslProcessInfo* pInfo)
983 pid_t pid;
985 if (Process == nullptr)
986 pid = getpid();
987 else
988 pid = static_cast<oslProcessImpl*>(Process)->m_pid;
990 if (! pInfo || (pInfo->Size != sizeof(oslProcessInfo)))
991 return osl_Process_E_Unknown;
993 pInfo->Fields = 0;
995 if (Fields & osl_Process_IDENTIFIER)
997 pInfo->Ident = pid;
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))
1014 #if defined(__sun)
1016 int fd;
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;
1044 close(fd);
1046 return (pInfo->Fields == Fields) ? osl_Process_E_None : osl_Process_E_Unknown;
1048 else
1049 close(fd);
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) )
1062 * mfe:
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)
1069 long clktck;
1070 unsigned long hz;
1071 unsigned long userseconds;
1072 unsigned long systemseconds;
1074 clktck = sysconf(_SC_CLK_TCK);
1075 if (clktck <= 0) {
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) )
1094 * mfe:
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;
1105 #endif
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
1125 a zombie. */
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))
1149 break;
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;
1170 if (pTimeout)
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)))
1180 sleep(1);
1182 if (timeout)
1183 osl_error = osl_Process_E_TimedOut;
1185 else /* infinite */
1187 while (!is_process_dead(pid))
1188 sleep(1);
1191 return osl_error;
1194 oslProcessError SAL_CALL osl_joinProcess(oslProcess Process)
1196 return osl_joinProcessWithTimeout(Process, nullptr);
1199 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */