ENH: provide system() command with CStringList

- allows (for example) splitting a user string on whitespace and
  passing this to system as a list of arguments, thus bypassing any
  implicit use of 'sh'.

- system() with optional background, for spawning processes.
This commit is contained in:
Mark Olesen
2017-11-22 10:48:55 +01:00
parent a881204946
commit 4023158497
2 changed files with 119 additions and 10 deletions

View File

@ -1406,7 +1406,11 @@ static int waitpid(const pid_t pid)
}
int Foam::system(const std::string& command)
int Foam::system
(
const std::string& command,
const bool background
)
{
if (command.empty())
{
@ -1446,12 +1450,24 @@ int Foam::system(const std::string& command)
}
// in parent - blocking wait
// In parent:
if (background)
{
// Started as background process
return 0;
}
// blocking wait for the child
return waitpid(child_pid);
}
int Foam::system(const Foam::UList<Foam::string>& command)
int Foam::system
(
const CStringList& command,
const bool background
)
{
const int argc = command.size();
@ -1478,7 +1494,70 @@ int Foam::system(const Foam::UList<Foam::string>& command)
if (child_pid == 0)
{
// in child:
// In child:
// Need command and arguments separately.
// args is a nullptr-terminated list of c-strings
// execvp uses the current environ
(void) ::execvp(command[0], command.strings(1));
// obviously failed, since exec should not return at all
FatalErrorInFunction
<< "exec(" << command[0] << ", ...) failed"
<< exit(FatalError);
}
// In parent:
if (background)
{
// Started as background process
return 0;
}
// blocking wait for the child
return waitpid(child_pid);
}
int Foam::system
(
const Foam::UList<Foam::string>& command,
const bool background
)
{
// In the future simply call the CStringList version:
//
// const CStringList cmd(command);
// return Foam::system(cmd, background);
const int argc = command.size();
if (!argc)
{
// Treat an empty command as a successful no-op.
// For consistency with POSIX (man sh) behaviour for (sh -c command),
// which is what is mostly being replicated here.
return 0;
}
// NB: use vfork, not fork!
// vfork behaves more like a thread and avoids copy-on-write problems
// triggered by fork.
// The normal system() command has a fork buried in it that causes
// issues with infiniband and openmpi etc.
pid_t child_pid = ::vfork();
if (child_pid == -1)
{
FatalErrorInFunction
<< "vfork() failed for system command " << command[0]
<< exit(FatalError);
}
if (child_pid == 0)
{
// In child:
// Need command and arguments separately.
// args is a nullptr-terminated list of c-strings
@ -1498,7 +1577,15 @@ int Foam::system(const Foam::UList<Foam::string>& command)
}
// in parent - blocking wait
// In parent:
if (background)
{
// Started as background process
return 0;
}
// blocking wait for the child
return waitpid(child_pid);
}

View File

@ -46,6 +46,10 @@ SourceFiles
namespace Foam
{
// Forward declarations
class CStringList;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//- Return the PID of this process
@ -206,14 +210,32 @@ bool ping(const std::string& host, const label timeOut=10);
// Uses vfork/execl internally.
// Where possible, use the list version instead.
//
// Treats an empty command as a successful no-op.
int system(const std::string& command);
// \param background return immediately to parent process instead of waiting
// for the child. Can be used (with moderation) to create background
// processes.
//
// \note treats an empty command as a successful no-op.
int system(const std::string& command, const bool background=false);
//- Execute the specified command with arguments.
// Uses vfork/execvp internally
//
// Treats an empty command as a successful no-op.
int system(const UList<string>& command);
// \param background return immediately to parent process instead of waiting
// for the child. Can be used (with moderation) to create background
// processes.
//
// \note treats an empty command as a successful no-op.
int system(const UList<string>& command, const bool background=false);
//- Execute the specified command with arguments.
// Uses vfork/execvp internally
//
// \param background return immediately to parent process instead of waiting
// for the child. Can be used (with moderation) to create background
// processes.
//
// \note treats an empty command as a successful no-op.
int system(const CStringList& command, const bool background=false);
//- Open a shared library and return handle to library.
// Print error message if library cannot be loaded (suppress with check=true)