/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
pid_t pid = -1; int status = 0; int channel[2] = { -1, -1 };
ProcessData data;
ProcessData *pdata; int stdOutput[2] = { -1, -1 }, stdInput[2] = { -1, -1 }, stdError[2] = { -1, -1 };
pdata = static_cast<ProcessData *>(pData);
/* make a copy of our data, because forking will only copy our local stack of the thread, so the process data will not be accessible
in our child process */
memcpy(&data, pData, sizeof(data));
if ( status == 0 && data.m_pOutputRead && pipe( stdOutput ) == -1 )
{
status = errno;
assert(status != 0);
SAL_WARN("sal.osl", "executeProcess pipe(stdOutput) errno " << status);
}
if ( status == 0 && data.m_pErrorRead && pipe( stdError ) == -1 )
{
status = errno;
assert(status != 0);
SAL_WARN("sal.osl", "executeProcess pipe(stdError) errno " << status);
}
if ( (status == 0) && ((pid = fork()) == 0) )
{ /* Child */ int chstatus = 0; int errno_copy;
if (channel[0] != -1) close(channel[0]);
if ((data.m_uid != uid_t(-1)) && ((data.m_uid != getuid()) || (data.m_gid != getgid())))
{
OSL_ASSERT(geteuid() == 0); /* must be root */
if (! INIT_GROUPS(data.m_name, data.m_gid) || (setuid(data.m_uid) != 0))
{ // ignore; can't do much about it here after fork
}
unsetenv("HOME");
}
if (data.m_pszDir)
chstatus = chdir(data.m_pszDir);
if (chstatus == 0 && ((data.m_uid == uid_t(-1)) || ((data.m_uid == getuid()) && (data.m_gid == getgid()))))
{ int i; for (i = 0; data.m_pszEnv[i] != nullptr; i++)
{ if (strchr(data.m_pszEnv[i], '=') == nullptr)
{
unsetenv(data.m_pszEnv[i]); /*TODO: check error return*/
} else
{
putenv(data.m_pszEnv[i]); /*TODO: check error return*/
}
}
/* Connect std IO to pipe ends */
/* Write end of stdInput not used in child process */ if (stdInput[1] != -1) close( stdInput[1] );
/* Read end of stdOutput not used in child process */ if (stdOutput[0] != -1) close( stdOutput[0] );
/* Read end of stdError not used in child process */ if (stdError[0] != -1) close( stdError[0] );
/* Redirect pipe ends to std IO */
if ( stdInput[0] != STDIN_FILENO )
{
dup2( stdInput[0], STDIN_FILENO ); if (stdInput[0] != -1) close( stdInput[0] );
}
if ( stdOutput[1] != STDOUT_FILENO )
{
dup2( stdOutput[1], STDOUT_FILENO ); if (stdOutput[1] != -1) close( stdOutput[1] );
}
if ( stdError[1] != STDERR_FILENO )
{
dup2( stdError[1], STDERR_FILENO ); if (stdError[1] != -1) close( stdError[1] );
}
// No need to check the return value of execv. If we return from // it, an error has occurred.
execv(data.m_pszArgs[0], const_cast<char **>(data.m_pszArgs));
}
/* if we reach here, something went wrong */
errno_copy = errno; if ( !safeWrite(channel[1], &errno_copy, sizeof(errno_copy)) )
{ // ignore; can't do much about it here after fork
}
if ( channel[1] != -1 )
close(channel[1]);
_exit(255);
} else
{ /* Parent */ int i = -1; if (channel[1] != -1) close(channel[1]);
/* Close unused pipe ends */ if (stdInput[0] != -1) close( stdInput[0] ); if (stdOutput[1] != -1) close( stdOutput[1] ); if (stdError[1] != -1) close( stdError[1] );
if (pid > 0)
{ while ((i = read(channel[0], &status, sizeof(status))) < 0)
{ if (errno != EINTR) break;
}
}
if (channel[0] != -1) close(channel[0]);
if ((pid > 0) && (i == 0))
{
pid_t child_pid;
osl_acquireMutex(ChildListMutex);
if ( pdata->m_pInputWrite )
*(pdata->m_pInputWrite) = osl::detail::createFileHandleFromFD( stdInput[1] );
if ( pdata->m_pOutputRead )
*(pdata->m_pOutputRead) = osl::detail::createFileHandleFromFD( stdOutput[0] );
if ( pdata->m_pErrorRead )
*(pdata->m_pErrorRead) = osl::detail::createFileHandleFromFD( stdError[0] );
osl_releaseMutex(ChildListMutex);
osl_setCondition(pdata->m_started);
do
{
child_pid = waitpid(pid, &status, 0);
} while ( 0 > child_pid && EINTR == errno );
if ( child_pid < 0)
{
SAL_WARN("sal.osl", "Failed to wait for child process: " << UnixErrnoString(errno));
/* We got another error than EINTR. Anyway we have to wake up the
waiting thread under any circumstances */
child_pid = pid;
}
if ( child_pid > 0 )
{
oslProcessImpl* pChild;
osl_acquireMutex(ChildListMutex);
pChild = ChildList;
/* check if it is one of our child processes */ while (pChild != nullptr)
{ if (pChild->m_pid == child_pid)
{ if (WIFEXITED(status))
pChild->m_status = WEXITSTATUS(status); elseif (WIFSIGNALED(status))
pChild->m_status = 128 + WTERMSIG(status); else
pChild->m_status = -1;
// coverity[lock_order : FALSE] - incorrect report of lock order error
osl_setCondition(pChild->m_terminated);
}
/* Close pipe ends */ if ( pdata->m_pInputWrite )
*pdata->m_pInputWrite = nullptr;
if ( pdata->m_pOutputRead )
*pdata->m_pOutputRead = nullptr;
if ( pdata->m_pErrorRead )
*pdata->m_pErrorRead = nullptr;
if (stdInput[1] != -1) close( stdInput[1] ); if (stdOutput[0] != -1) close( stdOutput[0] ); if (stdError[0] != -1) close( stdError[0] );
/* if pid > 0 then a process was created, even if it later failed e.g. bash searching for a command to execute, and we still
need to clean it up to avoid "defunct" processes */ if (pid > 0)
{
pid_t child_pid; do
{
child_pid = waitpid(pid, &status, 0);
} while ( 0 > child_pid && EINTR == errno );
}
void SAL_CALL osl_freeProcessHandle(oslProcess Process)
{ if (Process == nullptr) return;
oslProcessImpl *pChild, *pPrev = nullptr;
OSL_ASSERT(ChildListMutex != nullptr);
if ( ChildListMutex == nullptr )
{ return;
}
osl_acquireMutex(ChildListMutex);
pChild = ChildList;
/* remove process from child list */ while (pChild != nullptr)
{ if (pChild == static_cast<oslProcessImpl*>(Process))
{ if (pPrev != nullptr)
pPrev->m_pnext = pChild->m_pnext; else
ChildList = pChild->m_pnext;
struct osl_procStat
{ /* from 'stat' */
pid_t pid; /* pid */ char command[16]; /* 'argv[0]' */ /* mfe: it all right char comm[16] in kernel! */ char state; /* state (running, stopped, ...) */
pid_t ppid; /* parent pid */
pid_t pgrp; /* parent group */ int session; /* session ID */ int tty; /* no of tty */
pid_t tpgid; /* group of process owning the tty */ unsignedlong flags; /* flags dunno */ unsignedlong minflt; /* minor page faults */ unsignedlong cminflt; /* minor page faults with children */ unsignedlong majflt; /* major page faults */ unsignedlong cmajflt; /* major page faults with children */ unsignedlong utime; /* no of jiffies in user mode */ unsignedlong stime; /* no of jiffies in kernel mode */ unsignedlong cutime; /* no of jiffies in user mode with children */ unsignedlong cstime; /* no of jiffies in kernel mode with children */ unsignedlong priority; /* nice value + 15 (kernel scheduling prio)*/ long nice; /* nice value */ long timeout; /* no of jiffies of next process timeout */ long itrealvalue; /* no jiffies before next SIGALRM */ unsignedlong starttime; /* process started this no of jiffies after boot */ unsignedlong vsize; /* virtual memory size (in bytes) */ long rss; /* resident set size (in pages) */ unsignedlong rss_rlim; /* rss limit (in bytes) */ unsignedlong startcode; /* address above program text can run */ unsignedlong endcode; /* address below program text can run */ unsignedlong startstack; /* address of start of stack */ unsignedlong kstkesp; /* current value of 'esp' (stack pointer) */ unsignedlong kstkeip; /* current value of 'eip' (instruction pointer) */ /* mfe: Linux > 2.1.7x have more signals (88) */ char signal[24]; /* pending signals */ char blocked[24]; /* blocked signals */ char sigignore[24]; /* ignored signals */ char sigcatch[24]; /* caught signals */ unsignedlong wchan; /* 'channel' the process is waiting in */ unsignedlong nswap; /* ? */ unsignedlong cnswap; /* ? */
/* from 'status' */ int ruid; /* real uid */ int euid; /* effective uid */ int suid; /* saved uid */ int fuid; /* file access uid */ int rgid; /* real gid */ int egid; /* effective gid */ int sgid; /* saved gid */ int fgid; /* file access gid */ unsignedlong vm_size; /* like vsize but on kb */ unsignedlong vm_lock; /* locked pages in kb */ unsignedlong vm_rss; /* like rss but in kb */ unsignedlong vm_data; /* data size */ unsignedlong vm_stack; /* stack size */ unsignedlong vm_exe; /* executable size */ unsignedlong vm_lib; /* library size */
};
if ( (Fields & osl_Process_CPUTIMES) && osl_getProcStat(pid, &procstat) )
{ /* * mfe: * We calculate only time of the process proper. * Threads are processes, we do not consider their time here! * (For this, cutime and cstime should be used, it seems not * to work in 2.0.36)
*/
long clktck; unsignedlong hz; unsignedlong userseconds; unsignedlong systemseconds;
if ( (Fields & osl_Process_HEAPUSAGE) && osl_getProcStatus(pid, &procstat) )
{ /* * mfe: * vm_data (found in status) shows the size of the data segment * it a rough approximation of the core heap size
*/
pInfo->HeapUsage = procstat.vm_data*1024;
if (Process == nullptr || ChildListMutex == nullptr) return osl_Process_E_Unknown;
osl_acquireMutex(ChildListMutex);
/* check if process is a child of ours */ while (pChild != nullptr)
{ if (pChild == static_cast<oslProcessImpl*>(Process)) break;
pChild = pChild->m_pnext;
}
osl_releaseMutex(ChildListMutex);
if (pChild != nullptr)
{
oslConditionResult cond_res = osl_waitCondition(pChild->m_terminated, pTimeout);
if (cond_res == osl_cond_result_timeout)
osl_error = osl_Process_E_TimedOut; elseif (cond_res != osl_cond_result_ok)
osl_error = osl_Process_E_Unknown;
} else/* alien process; StatusThread will not be able
to set the condition terminated */
{
pid_t pid = static_cast<oslProcessImpl*>(Process)->m_pid;
if (pTimeout)
{ bool timeout = false; struct timeval tend;
gettimeofday(&tend, nullptr);
tend.tv_sec += pTimeout->Seconds;
while (!is_process_dead(pid) && !(timeout = is_timeout(&tend)))
sleep(1);
if (timeout)
osl_error = osl_Process_E_TimedOut;
} else/* infinite */
{ while (!is_process_dead(pid))
sleep(1);
}
} return osl_error;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.