mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
- with the 'cwd' optimization switch it is possible to select the
preferred behaviour for the cwd() function.
A value of 0 causes cwd() to return the physical directory,
which is what getcwd() and `pwd -P` return.
Until now, this was always the standard behaviour.
With a value of 1, cwd() instead returns the logical directory,
which what $PWD contains and `pwd -L` returns.
If any of the sanity checks fail (eg, PWD points to something other
than ".", etc), a warning is emitted and the physical cwd() is
returned instead.
Apart from the optical difference in the output, this additional
control helps workaround file systems with whitespace or other
characters in the directory that normally cause OpenFOAM to balk.
Using a cleaner symlink elsewhere should skirt this issue.
Eg,
cd $HOME
ln -s "/mounted volume/user/workdir" workdir
cd workdir
# start working with OpenFOAM
1722 lines
38 KiB
C
1722 lines
38 KiB
C
/*---------------------------------------------------------------------------*\
|
|
========= |
|
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
|
\\ / O peration |
|
|
\\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation
|
|
\\/ M anipulation | Copyright (C) 2016-2018 OpenCFD Ltd.
|
|
-------------------------------------------------------------------------------
|
|
License
|
|
This file is part of OpenFOAM.
|
|
|
|
OpenFOAM is free software: you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
Description
|
|
POSIX versions of the functions declared in OSspecific.H
|
|
|
|
\*---------------------------------------------------------------------------*/
|
|
|
|
#ifdef solarisGcc
|
|
#define _SYS_VNODE_H
|
|
#endif
|
|
|
|
#include "OSspecific.H"
|
|
#include "POSIX.H"
|
|
#include "foamVersion.H"
|
|
#include "fileName.H"
|
|
#include "fileStat.H"
|
|
#include "timer.H"
|
|
#include "IFstream.H"
|
|
#include "DynamicList.H"
|
|
#include "CStringList.H"
|
|
#include "SubList.H"
|
|
#include "IOstreams.H"
|
|
#include "Pstream.H"
|
|
|
|
#include <fstream>
|
|
#include <cstdlib>
|
|
#include <cctype>
|
|
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <dirent.h>
|
|
#include <pwd.h>
|
|
#include <errno.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/socket.h>
|
|
#include <netdb.h>
|
|
#include <netinet/in.h>
|
|
#include <dlfcn.h>
|
|
|
|
#ifdef darwin
|
|
#include <mach-o/dyld.h>
|
|
#else
|
|
#include <link.h>
|
|
#endif
|
|
|
|
|
|
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
|
|
|
namespace Foam
|
|
{
|
|
defineTypeNameAndDebug(POSIX, 0);
|
|
}
|
|
|
|
static bool cwdPreference_(Foam::debug::optimisationSwitch("cwd", 0));
|
|
|
|
|
|
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
|
|
|
// Like fileName "/" global operator, but retain any invalid characters
|
|
static inline Foam::fileName fileNameConcat
|
|
(
|
|
const std::string& a,
|
|
const std::string& b
|
|
)
|
|
{
|
|
if (a.size())
|
|
{
|
|
if (b.size())
|
|
{
|
|
// Two non-empty strings: can concatenate
|
|
return Foam::fileName((a + '/' + b), false);
|
|
}
|
|
|
|
return Foam::fileName(a, false);
|
|
}
|
|
|
|
// Or, if the first string is empty
|
|
|
|
if (b.size())
|
|
{
|
|
return Foam::fileName(b, false);
|
|
}
|
|
|
|
// Both strings are empty
|
|
return Foam::fileName();
|
|
}
|
|
|
|
|
|
// After a fork in system(), before the exec() do the following
|
|
// - close stdin when executing in background (daemon-like)
|
|
// - redirect stdout to stderr when infoDetailLevel == 0
|
|
static inline void redirects(const bool bg)
|
|
{
|
|
if (bg)
|
|
{
|
|
// Close stdin(0) - unchecked return value
|
|
(void) ::close(STDIN_FILENO);
|
|
}
|
|
|
|
// Redirect stdout(1) to stderr(2) '1>&2'
|
|
if (Foam::infoDetailLevel == 0)
|
|
{
|
|
// This is correct. 1>&2 means dup2(2, 1);
|
|
(void) ::dup2(STDERR_FILENO, STDOUT_FILENO);
|
|
}
|
|
}
|
|
|
|
|
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
|
|
pid_t Foam::pid()
|
|
{
|
|
return ::getpid();
|
|
}
|
|
|
|
|
|
pid_t Foam::ppid()
|
|
{
|
|
return ::getppid();
|
|
}
|
|
|
|
|
|
pid_t Foam::pgid()
|
|
{
|
|
return ::getpgrp();
|
|
}
|
|
|
|
|
|
bool Foam::env(const std::string& envName)
|
|
{
|
|
// An empty envName => always false
|
|
return !envName.empty() && ::getenv(envName.c_str()) != nullptr;
|
|
}
|
|
|
|
|
|
Foam::string Foam::getEnv(const std::string& envName)
|
|
{
|
|
// Ignore an empty envName => always ""
|
|
char* env = envName.empty() ? nullptr : ::getenv(envName.c_str());
|
|
|
|
if (env)
|
|
{
|
|
return string(env);
|
|
}
|
|
|
|
// Return null-constructed string rather than string::null
|
|
// to avoid cyclic dependencies in the construction of globals
|
|
return string();
|
|
}
|
|
|
|
|
|
bool Foam::setEnv
|
|
(
|
|
const word& envName,
|
|
const std::string& value,
|
|
const bool overwrite
|
|
)
|
|
{
|
|
// Ignore an empty envName => always false
|
|
return
|
|
(
|
|
!envName.empty()
|
|
&& ::setenv(envName.c_str(), value.c_str(), overwrite) == 0
|
|
);
|
|
}
|
|
|
|
|
|
Foam::string Foam::hostName(bool full)
|
|
{
|
|
char buf[128];
|
|
::gethostname(buf, sizeof(buf));
|
|
|
|
// implementation as per hostname from net-tools
|
|
if (full)
|
|
{
|
|
struct hostent *hp = ::gethostbyname(buf);
|
|
if (hp)
|
|
{
|
|
return hp->h_name;
|
|
}
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
|
|
Foam::string Foam::domainName()
|
|
{
|
|
char buf[128];
|
|
::gethostname(buf, sizeof(buf));
|
|
|
|
// implementation as per hostname from net-tools
|
|
struct hostent *hp = ::gethostbyname(buf);
|
|
if (hp)
|
|
{
|
|
char *p = ::strchr(hp->h_name, '.');
|
|
if (p)
|
|
{
|
|
++p;
|
|
return p;
|
|
}
|
|
}
|
|
|
|
return string::null;
|
|
}
|
|
|
|
|
|
Foam::string Foam::userName()
|
|
{
|
|
struct passwd* pw = ::getpwuid(::getuid());
|
|
if (pw != nullptr)
|
|
{
|
|
return pw->pw_name;
|
|
}
|
|
|
|
return string();
|
|
}
|
|
|
|
|
|
bool Foam::isAdministrator()
|
|
{
|
|
return (::geteuid() == 0);
|
|
}
|
|
|
|
|
|
Foam::fileName Foam::home()
|
|
{
|
|
char* env = ::getenv("HOME");
|
|
if (env)
|
|
{
|
|
return fileName(env);
|
|
}
|
|
|
|
struct passwd* pw = ::getpwuid(::getuid());
|
|
if (pw)
|
|
{
|
|
return pw->pw_dir;
|
|
}
|
|
|
|
return fileName();
|
|
}
|
|
|
|
|
|
Foam::fileName Foam::home(const std::string& userName)
|
|
{
|
|
// An empty userName => same as home()
|
|
if (userName.empty())
|
|
{
|
|
return Foam::home();
|
|
}
|
|
|
|
struct passwd* pw = ::getpwnam(userName.c_str());
|
|
if (pw)
|
|
{
|
|
return pw->pw_dir;
|
|
}
|
|
|
|
return fileName();
|
|
}
|
|
|
|
|
|
namespace Foam
|
|
{
|
|
|
|
//- The physical current working directory path name (pwd -P).
|
|
static Foam::fileName cwd_P()
|
|
{
|
|
label pathLengthLimit = POSIX::pathLengthChunk;
|
|
List<char> path(pathLengthLimit);
|
|
|
|
// Resize path if getcwd fails with an ERANGE error
|
|
while (pathLengthLimit == path.size())
|
|
{
|
|
if (::getcwd(path.data(), path.size()))
|
|
{
|
|
return path.data();
|
|
}
|
|
else if (errno == ERANGE)
|
|
{
|
|
// Increment path length up to the pathLengthMax limit
|
|
if
|
|
(
|
|
(pathLengthLimit += POSIX::pathLengthChunk)
|
|
>= POSIX::pathLengthMax
|
|
)
|
|
{
|
|
FatalErrorInFunction
|
|
<< "Attempt to increase path length beyond limit of "
|
|
<< POSIX::pathLengthMax
|
|
<< exit(FatalError);
|
|
}
|
|
|
|
path.resize(pathLengthLimit);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
FatalErrorInFunction
|
|
<< "Couldn't get the current working directory"
|
|
<< exit(FatalError);
|
|
|
|
return fileName();
|
|
}
|
|
|
|
|
|
//- The logical current working directory path name.
|
|
// From the PWD environment, same as pwd -L.
|
|
static Foam::fileName cwd_L()
|
|
{
|
|
const char* env = ::getenv("PWD");
|
|
|
|
// Basic check
|
|
if (!env || env[0] != '/')
|
|
{
|
|
WarningInFunction
|
|
<< "PWD is invalid - reverting to physical description"
|
|
<< nl;
|
|
|
|
return cwd_P();
|
|
}
|
|
|
|
fileName dir(env);
|
|
|
|
// Check for "/."
|
|
for
|
|
(
|
|
std::string::size_type pos = 0;
|
|
std::string::npos != (pos = dir.find("/.", pos));
|
|
/*nil*/
|
|
)
|
|
{
|
|
pos += 2;
|
|
|
|
if
|
|
(
|
|
// Ends in "/." or has "/./"
|
|
!dir[pos] || dir[pos] == '/'
|
|
|
|
// Ends in "/.." or has "/../"
|
|
|| (dir[pos] == '.' && (!dir[pos+1] || dir[pos+1] == '/'))
|
|
)
|
|
{
|
|
WarningInFunction
|
|
<< "PWD contains /. or /.. - reverting to physical description"
|
|
<< nl;
|
|
|
|
return cwd_P();
|
|
}
|
|
}
|
|
|
|
// Finally, verify that PWD actually corresponds to the "." directory
|
|
if (!fileStat(dir, true).sameINode(fileStat(".", true)))
|
|
{
|
|
WarningInFunction
|
|
<< "PWD is not the cwd() - reverting to physical description"
|
|
<< nl;
|
|
|
|
return cwd_P();
|
|
}
|
|
|
|
|
|
return fileName(dir);
|
|
}
|
|
|
|
} // End namespace Foam
|
|
|
|
|
|
Foam::fileName Foam::cwd()
|
|
{
|
|
return cwd(cwdPreference_);
|
|
}
|
|
|
|
|
|
Foam::fileName Foam::cwd(bool logical)
|
|
{
|
|
if (logical)
|
|
{
|
|
return cwd_L();
|
|
}
|
|
|
|
return cwd_P();
|
|
}
|
|
|
|
|
|
bool Foam::chDir(const fileName& dir)
|
|
{
|
|
// Ignore an empty dir name => always false
|
|
return !dir.empty() && ::chdir(dir.c_str()) == 0;
|
|
}
|
|
|
|
|
|
bool Foam::mkDir(const fileName& pathName, mode_t mode)
|
|
{
|
|
if (POSIX::debug)
|
|
{
|
|
Pout<< FUNCTION_NAME << " : pathName:" << pathName << " mode:" << mode
|
|
<< endl;
|
|
if ((POSIX::debug & 2) && !Pstream::master())
|
|
{
|
|
error::printStack(Pout);
|
|
}
|
|
}
|
|
|
|
// empty names are meaningless
|
|
if (pathName.empty())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Construct path directory if does not exist
|
|
if (::mkdir(pathName.c_str(), mode) == 0)
|
|
{
|
|
// Directory made OK so return true
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
switch (errno)
|
|
{
|
|
case EPERM:
|
|
{
|
|
FatalErrorInFunction
|
|
<< "The filesystem containing " << pathName
|
|
<< " does not support the creation of directories."
|
|
<< exit(FatalError);
|
|
|
|
return false;
|
|
}
|
|
|
|
case EEXIST:
|
|
{
|
|
// Directory already exists so simply return true
|
|
return true;
|
|
}
|
|
|
|
case EFAULT:
|
|
{
|
|
FatalErrorInFunction
|
|
<< "" << pathName
|
|
<< " points outside your accessible address space."
|
|
<< exit(FatalError);
|
|
|
|
return false;
|
|
}
|
|
|
|
case EACCES:
|
|
{
|
|
FatalErrorInFunction
|
|
<< "The parent directory does not allow write "
|
|
"permission to the process,"<< nl
|
|
<< "or one of the directories in " << pathName
|
|
<< " did not allow search (execute) permission."
|
|
<< exit(FatalError);
|
|
|
|
return false;
|
|
}
|
|
|
|
case ENAMETOOLONG:
|
|
{
|
|
FatalErrorInFunction
|
|
<< "" << pathName << " is too long."
|
|
<< exit(FatalError);
|
|
|
|
return false;
|
|
}
|
|
|
|
case ENOENT:
|
|
{
|
|
// Part of the path does not exist so try to create it
|
|
if (pathName.path().size() && mkDir(pathName.path(), mode))
|
|
{
|
|
return mkDir(pathName, mode);
|
|
}
|
|
else
|
|
{
|
|
FatalErrorInFunction
|
|
<< "Couldn't create directory " << pathName
|
|
<< exit(FatalError);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
case ENOTDIR:
|
|
{
|
|
FatalErrorInFunction
|
|
<< "A component used as a directory in " << pathName
|
|
<< " is not, in fact, a directory."
|
|
<< exit(FatalError);
|
|
|
|
return false;
|
|
}
|
|
|
|
case ENOMEM:
|
|
{
|
|
FatalErrorInFunction
|
|
<< "Insufficient kernel memory was available to make "
|
|
"directory " << pathName << '.'
|
|
<< exit(FatalError);
|
|
|
|
return false;
|
|
}
|
|
|
|
case EROFS:
|
|
{
|
|
FatalErrorInFunction
|
|
<< "" << pathName
|
|
<< " refers to a file on a read-only filesystem."
|
|
<< exit(FatalError);
|
|
|
|
return false;
|
|
}
|
|
|
|
case ELOOP:
|
|
{
|
|
FatalErrorInFunction
|
|
<< "Too many symbolic links were encountered in resolving "
|
|
<< pathName << '.'
|
|
<< exit(FatalError);
|
|
|
|
return false;
|
|
}
|
|
|
|
case ENOSPC:
|
|
{
|
|
FatalErrorInFunction
|
|
<< "The device containing " << pathName
|
|
<< " has no room for the new directory or "
|
|
<< "the user's disk quota is exhausted."
|
|
<< exit(FatalError);
|
|
|
|
return false;
|
|
}
|
|
|
|
default:
|
|
{
|
|
FatalErrorInFunction
|
|
<< "Couldn't create directory " << pathName
|
|
<< exit(FatalError);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool Foam::chMod(const fileName& name, const mode_t m)
|
|
{
|
|
if (POSIX::debug)
|
|
{
|
|
Pout<< FUNCTION_NAME << " : name:" << name << endl;
|
|
if ((POSIX::debug & 2) && !Pstream::master())
|
|
{
|
|
error::printStack(Pout);
|
|
}
|
|
}
|
|
|
|
// Ignore an empty name => always false
|
|
return !name.empty() && ::chmod(name.c_str(), m) == 0;
|
|
}
|
|
|
|
|
|
mode_t Foam::mode(const fileName& name, const bool followLink)
|
|
{
|
|
if (POSIX::debug)
|
|
{
|
|
Pout<< FUNCTION_NAME << " : name:" << name << endl;
|
|
if ((POSIX::debug & 2) && !Pstream::master())
|
|
{
|
|
error::printStack(Pout);
|
|
}
|
|
}
|
|
|
|
// Ignore an empty name => always 0
|
|
if (!name.empty())
|
|
{
|
|
fileStat fileStatus(name, followLink);
|
|
if (fileStatus.isValid())
|
|
{
|
|
return fileStatus.status().st_mode;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
Foam::fileName::Type Foam::type(const fileName& name, const bool followLink)
|
|
{
|
|
// Ignore an empty name => always UNDEFINED
|
|
if (name.empty())
|
|
{
|
|
return fileName::UNDEFINED;
|
|
}
|
|
|
|
if (POSIX::debug)
|
|
{
|
|
Pout<< FUNCTION_NAME << " : name:" << name << endl;
|
|
}
|
|
|
|
mode_t m = mode(name, followLink);
|
|
|
|
if (S_ISREG(m))
|
|
{
|
|
return fileName::FILE;
|
|
}
|
|
else if (S_ISLNK(m))
|
|
{
|
|
return fileName::LINK;
|
|
}
|
|
else if (S_ISDIR(m))
|
|
{
|
|
return fileName::DIRECTORY;
|
|
}
|
|
|
|
return fileName::UNDEFINED;
|
|
}
|
|
|
|
|
|
bool Foam::exists
|
|
(
|
|
const fileName& name,
|
|
const bool checkGzip,
|
|
const bool followLink
|
|
)
|
|
{
|
|
if (POSIX::debug)
|
|
{
|
|
Pout<< FUNCTION_NAME << " : name:" << name << " checkGzip:" << checkGzip
|
|
<< endl;
|
|
if ((POSIX::debug & 2) && !Pstream::master())
|
|
{
|
|
error::printStack(Pout);
|
|
}
|
|
}
|
|
|
|
// Ignore an empty name => always false
|
|
return
|
|
(
|
|
!name.empty()
|
|
&& (mode(name, followLink) || isFile(name, checkGzip, followLink))
|
|
);
|
|
}
|
|
|
|
|
|
bool Foam::isDir(const fileName& name, const bool followLink)
|
|
{
|
|
if (POSIX::debug)
|
|
{
|
|
Pout<< FUNCTION_NAME << " : name:" << name << endl;
|
|
if ((POSIX::debug & 2) && !Pstream::master())
|
|
{
|
|
error::printStack(Pout);
|
|
}
|
|
}
|
|
|
|
// Ignore an empty name => always false
|
|
return !name.empty() && S_ISDIR(mode(name, followLink));
|
|
}
|
|
|
|
|
|
bool Foam::isFile
|
|
(
|
|
const fileName& name,
|
|
const bool checkGzip,
|
|
const bool followLink
|
|
)
|
|
{
|
|
if (POSIX::debug)
|
|
{
|
|
Pout<< FUNCTION_NAME << " : name:" << name << " checkGzip:" << checkGzip
|
|
<< endl;
|
|
if ((POSIX::debug & 2) && !Pstream::master())
|
|
{
|
|
error::printStack(Pout);
|
|
}
|
|
}
|
|
|
|
// Ignore an empty name => always false
|
|
return
|
|
(
|
|
!name.empty()
|
|
&& (
|
|
S_ISREG(mode(name, followLink))
|
|
|| (checkGzip && S_ISREG(mode(name + ".gz", followLink)))
|
|
)
|
|
);
|
|
}
|
|
|
|
|
|
off_t Foam::fileSize(const fileName& name, const bool followLink)
|
|
{
|
|
if (POSIX::debug)
|
|
{
|
|
Pout<< FUNCTION_NAME << " : name:" << name << endl;
|
|
if ((POSIX::debug & 2) && !Pstream::master())
|
|
{
|
|
error::printStack(Pout);
|
|
}
|
|
}
|
|
|
|
// Ignore an empty name
|
|
if (!name.empty())
|
|
{
|
|
fileStat fileStatus(name, followLink);
|
|
if (fileStatus.isValid())
|
|
{
|
|
return fileStatus.status().st_size;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
time_t Foam::lastModified(const fileName& name, const bool followLink)
|
|
{
|
|
if (POSIX::debug)
|
|
{
|
|
Pout<< FUNCTION_NAME << " : name:" << name << endl;
|
|
if ((POSIX::debug & 2) && !Pstream::master())
|
|
{
|
|
error::printStack(Pout);
|
|
}
|
|
}
|
|
|
|
// Ignore an empty name
|
|
return name.empty() ? 0 : fileStat(name, followLink).modTime();
|
|
}
|
|
|
|
|
|
double Foam::highResLastModified(const fileName& name, const bool followLink)
|
|
{
|
|
if (POSIX::debug)
|
|
{
|
|
Pout<< FUNCTION_NAME << " : name:" << name << endl;
|
|
if ((POSIX::debug & 2) && !Pstream::master())
|
|
{
|
|
error::printStack(Pout);
|
|
}
|
|
}
|
|
|
|
// Ignore an empty name
|
|
return name.empty() ? 0 : fileStat(name, followLink).dmodTime();
|
|
}
|
|
|
|
|
|
Foam::fileNameList Foam::readDir
|
|
(
|
|
const fileName& directory,
|
|
const fileName::Type type,
|
|
const bool filtergz,
|
|
const bool followLink
|
|
)
|
|
{
|
|
// Initial filename list size and the increment when resizing the list
|
|
static const int maxNnames = 100;
|
|
|
|
// Basic sanity: cannot strip '.gz' from directory names
|
|
const bool stripgz = filtergz && (type != fileName::DIRECTORY);
|
|
const word extgz("gz");
|
|
|
|
fileNameList dirEntries;
|
|
|
|
// Open directory and set the structure pointer
|
|
// Do not attempt to open an empty directory name
|
|
DIR *source;
|
|
if
|
|
(
|
|
directory.empty()
|
|
|| (source = ::opendir(directory.c_str())) == nullptr
|
|
)
|
|
{
|
|
if (POSIX::debug)
|
|
{
|
|
InfoInFunction
|
|
<< "cannot open directory " << directory << endl;
|
|
}
|
|
|
|
return dirEntries;
|
|
}
|
|
|
|
if (POSIX::debug)
|
|
{
|
|
// InfoInFunction
|
|
Pout<< FUNCTION_NAME << " : reading directory " << directory << endl;
|
|
if ((POSIX::debug & 2) && !Pstream::master())
|
|
{
|
|
error::printStack(Pout);
|
|
}
|
|
}
|
|
|
|
label nFailed = 0; // Entries with invalid characters
|
|
label nEntries = 0; // Number of selected entries
|
|
dirEntries.setSize(maxNnames);
|
|
|
|
// Read and parse all the entries in the directory
|
|
for (struct dirent *list; (list = ::readdir(source)) != nullptr; /*nil*/)
|
|
{
|
|
const std::string item(list->d_name);
|
|
|
|
// Ignore files/directories beginning with "."
|
|
// These are the ".", ".." directories and any hidden files/dirs
|
|
if (item.empty() || item[0] == '.')
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Validate filename without spaces, quotes, etc in the name.
|
|
// No duplicate slashes to strip - dirent will not have them anyhow.
|
|
|
|
const fileName name(fileName::validate(item));
|
|
if (name != item)
|
|
{
|
|
++nFailed;
|
|
}
|
|
else if
|
|
(
|
|
(type == fileName::DIRECTORY)
|
|
|| (type == fileName::FILE && !fileName::isBackup(name))
|
|
)
|
|
{
|
|
if ((directory/name).type(followLink) == type)
|
|
{
|
|
if (nEntries >= dirEntries.size())
|
|
{
|
|
dirEntries.setSize(dirEntries.size() + maxNnames);
|
|
}
|
|
|
|
if (stripgz && name.hasExt(extgz))
|
|
{
|
|
dirEntries[nEntries++] = name.lessExt();
|
|
}
|
|
else
|
|
{
|
|
dirEntries[nEntries++] = name;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
::closedir(source);
|
|
|
|
// Finalize the length of the entries list
|
|
dirEntries.setSize(nEntries);
|
|
|
|
if (nFailed && POSIX::debug)
|
|
{
|
|
std::cerr
|
|
<< "Foam::readDir() : reading directory " << directory << nl
|
|
<< nFailed << " entries with invalid characters in their name"
|
|
<< std::endl;
|
|
}
|
|
|
|
return dirEntries;
|
|
}
|
|
|
|
|
|
bool Foam::cp(const fileName& src, const fileName& dest, const bool followLink)
|
|
{
|
|
if (POSIX::debug)
|
|
{
|
|
Pout<< FUNCTION_NAME << " : src:" << src << " dest:" << dest << endl;
|
|
if ((POSIX::debug & 2) && !Pstream::master())
|
|
{
|
|
error::printStack(Pout);
|
|
}
|
|
}
|
|
|
|
// Make sure source exists - this also handles an empty source name
|
|
if (!exists(src))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const fileName::Type srcType = src.type(followLink);
|
|
|
|
fileName destFile(dest);
|
|
|
|
// Check type of source file.
|
|
if (srcType == fileName::FILE)
|
|
{
|
|
// If dest is a directory, create the destination file name.
|
|
if (destFile.type() == fileName::DIRECTORY)
|
|
{
|
|
destFile /= src.name();
|
|
}
|
|
|
|
// Make sure the destination directory exists.
|
|
if (!isDir(destFile.path()) && !mkDir(destFile.path()))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Open and check streams.
|
|
std::ifstream srcStream(src);
|
|
if (!srcStream)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
std::ofstream destStream(destFile);
|
|
if (!destStream)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Copy character data.
|
|
char ch;
|
|
while (srcStream.get(ch))
|
|
{
|
|
destStream.put(ch);
|
|
}
|
|
|
|
// Final check.
|
|
if (!srcStream.eof() || !destStream)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else if (srcType == fileName::LINK)
|
|
{
|
|
// If dest is a directory, create the destination file name.
|
|
if (destFile.type() == fileName::DIRECTORY)
|
|
{
|
|
destFile /= src.name();
|
|
}
|
|
|
|
// Make sure the destination directory exists.
|
|
if (!isDir(destFile.path()) && !mkDir(destFile.path()))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ln(src, destFile);
|
|
}
|
|
else if (srcType == fileName::DIRECTORY)
|
|
{
|
|
// If dest is a directory, create the destination file name.
|
|
if (destFile.type() == fileName::DIRECTORY)
|
|
{
|
|
destFile /= src.components().last();
|
|
}
|
|
|
|
// Make sure the destination directory exists.
|
|
if (!isDir(destFile) && !mkDir(destFile))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
char* realSrcPath = realpath(src.c_str(), nullptr);
|
|
char* realDestPath = realpath(destFile.c_str(), nullptr);
|
|
const bool samePath = strcmp(realSrcPath, realDestPath) == 0;
|
|
|
|
if (POSIX::debug && samePath)
|
|
{
|
|
InfoInFunction
|
|
<< "Attempt to copy " << realSrcPath << " to itself" << endl;
|
|
}
|
|
|
|
if (realSrcPath)
|
|
{
|
|
free(realSrcPath);
|
|
}
|
|
|
|
if (realDestPath)
|
|
{
|
|
free(realDestPath);
|
|
}
|
|
|
|
// Do not copy over self when src is actually a link to dest
|
|
if (samePath)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Copy files
|
|
fileNameList files = readDir(src, fileName::FILE, false, followLink);
|
|
for (const fileName& item : files)
|
|
{
|
|
if (POSIX::debug)
|
|
{
|
|
InfoInFunction
|
|
<< "Copying : " << src/item
|
|
<< " to " << destFile/item << endl;
|
|
}
|
|
|
|
// File to file.
|
|
cp(src/item, destFile/item, followLink);
|
|
}
|
|
|
|
// Copy sub directories.
|
|
fileNameList dirs = readDir
|
|
(
|
|
src,
|
|
fileName::DIRECTORY,
|
|
false,
|
|
followLink
|
|
);
|
|
|
|
for (const fileName& item : dirs)
|
|
{
|
|
if (POSIX::debug)
|
|
{
|
|
InfoInFunction
|
|
<< "Copying : " << src/item
|
|
<< " to " << destFile << endl;
|
|
}
|
|
|
|
// Dir to Dir.
|
|
cp(src/item, destFile, followLink);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool Foam::ln(const fileName& src, const fileName& dst)
|
|
{
|
|
if (POSIX::debug)
|
|
{
|
|
//InfoInFunction
|
|
Pout<< FUNCTION_NAME
|
|
<< " : Create softlink from : " << src << " to " << dst << endl;
|
|
if ((POSIX::debug & 2) && !Pstream::master())
|
|
{
|
|
error::printStack(Pout);
|
|
}
|
|
}
|
|
|
|
if (src.empty())
|
|
{
|
|
WarningInFunction
|
|
<< "source name is empty: not linking." << endl;
|
|
return false;
|
|
}
|
|
|
|
if (dst.empty())
|
|
{
|
|
WarningInFunction
|
|
<< "destination name is empty: not linking." << endl;
|
|
return false;
|
|
}
|
|
|
|
if (exists(dst))
|
|
{
|
|
WarningInFunction
|
|
<< "destination " << dst << " already exists. Not linking."
|
|
<< endl;
|
|
return false;
|
|
}
|
|
|
|
if (src.isAbsolute() && !exists(src))
|
|
{
|
|
WarningInFunction
|
|
<< "source " << src << " does not exist." << endl;
|
|
return false;
|
|
}
|
|
|
|
if (::symlink(src.c_str(), dst.c_str()) == 0)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
WarningInFunction
|
|
<< "symlink from " << src << " to " << dst << " failed." << endl;
|
|
return false;
|
|
}
|
|
|
|
|
|
bool Foam::mv(const fileName& src, const fileName& dst, const bool followLink)
|
|
{
|
|
if (POSIX::debug)
|
|
{
|
|
//InfoInFunction
|
|
Pout<< FUNCTION_NAME << " : Move : " << src << " to " << dst << endl;
|
|
if ((POSIX::debug & 2) && !Pstream::master())
|
|
{
|
|
error::printStack(Pout);
|
|
}
|
|
}
|
|
|
|
// Ignore an empty names => always false
|
|
if (src.empty() || dst.empty())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if
|
|
(
|
|
dst.type() == fileName::DIRECTORY
|
|
&& src.type(followLink) != fileName::DIRECTORY
|
|
)
|
|
{
|
|
const fileName dstName(dst/src.name());
|
|
|
|
return ::rename(src.c_str(), dstName.c_str()) == 0;
|
|
}
|
|
else
|
|
{
|
|
return ::rename(src.c_str(), dst.c_str()) == 0;
|
|
}
|
|
}
|
|
|
|
|
|
bool Foam::mvBak(const fileName& src, const std::string& ext)
|
|
{
|
|
if (POSIX::debug)
|
|
{
|
|
//InfoInFunction
|
|
Pout<< FUNCTION_NAME
|
|
<< " : moving : " << src << " to extension " << ext << endl;
|
|
if ((POSIX::debug & 2) && !Pstream::master())
|
|
{
|
|
error::printStack(Pout);
|
|
}
|
|
}
|
|
|
|
// Ignore an empty name or extension => always false
|
|
if (src.empty() || ext.empty())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (exists(src, false))
|
|
{
|
|
const int maxIndex = 99;
|
|
char index[3];
|
|
|
|
for (int n = 0; n <= maxIndex; ++n)
|
|
{
|
|
fileName dstName(src + "." + ext);
|
|
if (n)
|
|
{
|
|
::sprintf(index, "%02d", n);
|
|
dstName += index;
|
|
}
|
|
|
|
// avoid overwriting existing files, except for the last
|
|
// possible index where we have no choice
|
|
if (!exists(dstName, false) || n == maxIndex)
|
|
{
|
|
return ::rename(src.c_str(), dstName.c_str()) == 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// fallthrough: nothing to do
|
|
return false;
|
|
}
|
|
|
|
|
|
bool Foam::rm(const fileName& file)
|
|
{
|
|
if (POSIX::debug)
|
|
{
|
|
//InfoInFunction
|
|
Pout<< FUNCTION_NAME << " : Removing : " << file << endl;
|
|
if ((POSIX::debug & 2) && !Pstream::master())
|
|
{
|
|
error::printStack(Pout);
|
|
}
|
|
}
|
|
|
|
// Ignore an empty name => always false
|
|
if (file.empty())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Try returning plain file name; if not there, try with .gz
|
|
if (::remove(file.c_str()) == 0)
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return ::remove(string(file + ".gz").c_str()) == 0;
|
|
}
|
|
}
|
|
|
|
|
|
bool Foam::rmDir(const fileName& directory, const bool silent)
|
|
{
|
|
// Open directory and set the structure pointer
|
|
// Do not attempt to open an empty directory name
|
|
DIR *source;
|
|
if
|
|
(
|
|
directory.empty()
|
|
|| (source = ::opendir(directory.c_str())) == nullptr
|
|
)
|
|
{
|
|
if (!silent)
|
|
{
|
|
WarningInFunction
|
|
<< "cannot open directory " << directory << endl;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
if (POSIX::debug)
|
|
{
|
|
//InfoInFunction
|
|
Pout<< FUNCTION_NAME << " : removing directory " << directory << endl;
|
|
if ((POSIX::debug & 2) && !Pstream::master())
|
|
{
|
|
error::printStack(Pout);
|
|
}
|
|
}
|
|
|
|
// Process each directory entry, counting any errors encountered
|
|
label nErrors = 0;
|
|
for (struct dirent *list; (list = ::readdir(source)) != nullptr; /*nil*/)
|
|
{
|
|
const std::string item(list->d_name);
|
|
|
|
// Ignore "." and ".." directories
|
|
if (item.empty() || item == "." || item == "..")
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Allow invalid characters (spaces, quotes, etc),
|
|
// otherwise we cannot subdirs with these types of names.
|
|
// -> const fileName path = directory/name; <-
|
|
|
|
const fileName path(fileNameConcat(directory, item));
|
|
|
|
if (path.type(false) == fileName::DIRECTORY)
|
|
{
|
|
if (!rmDir(path, true)) // Only report errors at the top-level
|
|
{
|
|
++nErrors;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!rm(path))
|
|
{
|
|
++nErrors;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nErrors)
|
|
{
|
|
if (!silent)
|
|
{
|
|
WarningInFunction
|
|
<< "failed to remove directory " << directory << nl
|
|
<< "could not remove " << nErrors << " sub-entries" << endl;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!rm(directory))
|
|
{
|
|
++nErrors;
|
|
if (!silent)
|
|
{
|
|
WarningInFunction
|
|
<< "failed to remove directory " << directory << endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
// clean up
|
|
::closedir(source);
|
|
return !nErrors;
|
|
}
|
|
|
|
|
|
unsigned int Foam::sleep(const unsigned int sec)
|
|
{
|
|
return ::sleep(sec);
|
|
}
|
|
|
|
|
|
void Foam::fdClose(const int fd)
|
|
{
|
|
if (close(fd) != 0)
|
|
{
|
|
FatalErrorInFunction
|
|
<< "close error on " << fd << endl
|
|
<< abort(FatalError);
|
|
}
|
|
}
|
|
|
|
|
|
bool Foam::ping
|
|
(
|
|
const std::string& destName,
|
|
const label destPort,
|
|
const label timeOut
|
|
)
|
|
{
|
|
struct hostent *hostPtr;
|
|
volatile int sockfd;
|
|
struct sockaddr_in destAddr; // will hold the destination addr
|
|
u_int addr;
|
|
|
|
if ((hostPtr = ::gethostbyname(destName.c_str())) == nullptr)
|
|
{
|
|
FatalErrorInFunction
|
|
<< "gethostbyname error " << h_errno << " for host " << destName
|
|
<< abort(FatalError);
|
|
}
|
|
|
|
// Get first of the SLL of addresses
|
|
addr = (reinterpret_cast<struct in_addr*>(*(hostPtr->h_addr_list)))->s_addr;
|
|
|
|
// Allocate socket
|
|
sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
|
|
if (sockfd < 0)
|
|
{
|
|
FatalErrorInFunction
|
|
<< "socket error"
|
|
<< abort(FatalError);
|
|
}
|
|
|
|
// Fill sockaddr_in structure with dest address and port
|
|
memset(reinterpret_cast<char *>(&destAddr), '\0', sizeof(destAddr));
|
|
destAddr.sin_family = AF_INET;
|
|
destAddr.sin_port = htons(ushort(destPort));
|
|
destAddr.sin_addr.s_addr = addr;
|
|
|
|
|
|
timer myTimer(timeOut);
|
|
|
|
if (timedOut(myTimer))
|
|
{
|
|
// Setjmp from timer jumps back to here
|
|
fdClose(sockfd);
|
|
return false;
|
|
}
|
|
|
|
if
|
|
(
|
|
::connect
|
|
(
|
|
sockfd,
|
|
reinterpret_cast<struct sockaddr*>(&destAddr),
|
|
sizeof(struct sockaddr)
|
|
) != 0
|
|
)
|
|
{
|
|
// Connection refused. Check if network was actually used or not.
|
|
|
|
int connectErr = errno;
|
|
|
|
fdClose(sockfd);
|
|
|
|
if (connectErr == ECONNREFUSED)
|
|
{
|
|
return true;
|
|
}
|
|
//perror("connect");
|
|
|
|
return false;
|
|
}
|
|
|
|
fdClose(sockfd);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool Foam::ping(const std::string& host, const label timeOut)
|
|
{
|
|
return ping(host, 222, timeOut) || ping(host, 22, timeOut);
|
|
}
|
|
|
|
|
|
namespace Foam
|
|
{
|
|
//! \cond fileScope
|
|
static int waitpid(const pid_t pid)
|
|
{
|
|
// child status, return code from the exec etc.
|
|
int status = 0;
|
|
|
|
// in parent - blocking wait
|
|
// modest treatment of signals (in child)
|
|
// treat 'stopped' like exit (suspend/continue)
|
|
|
|
while (true)
|
|
{
|
|
pid_t wpid = ::waitpid(pid, &status, WUNTRACED);
|
|
|
|
if (wpid == -1)
|
|
{
|
|
FatalErrorInFunction
|
|
<< "some error occurred in child"
|
|
<< exit(FatalError);
|
|
break;
|
|
}
|
|
|
|
if (WIFEXITED(status))
|
|
{
|
|
// child exited, get its return status
|
|
return WEXITSTATUS(status);
|
|
}
|
|
|
|
if (WIFSIGNALED(status))
|
|
{
|
|
// child terminated by some signal
|
|
return WTERMSIG(status);
|
|
}
|
|
|
|
if (WIFSTOPPED(status))
|
|
{
|
|
// child stopped by some signal
|
|
return WSTOPSIG(status);
|
|
}
|
|
|
|
FatalErrorInFunction
|
|
<< "programming error, status from waitpid() not handled: "
|
|
<< status
|
|
<< exit(FatalError);
|
|
}
|
|
|
|
return -1; // should not happen
|
|
}
|
|
//! \endcond
|
|
}
|
|
|
|
|
|
int Foam::system(const std::string& command, const bool bg)
|
|
{
|
|
if (command.empty())
|
|
{
|
|
// Treat an empty command as a successful no-op.
|
|
// From 'man sh' POSIX (man sh):
|
|
// "If the command_string operand is an empty string,
|
|
// sh shall exit with a zero exit status."
|
|
return 0;
|
|
}
|
|
|
|
const pid_t child_pid = ::vfork(); // NB: vfork, not fork!
|
|
|
|
if (child_pid == -1)
|
|
{
|
|
FatalErrorInFunction
|
|
<< "vfork() failed for system command " << command
|
|
<< exit(FatalError);
|
|
|
|
return -1; // fallback error value
|
|
}
|
|
else if (child_pid == 0)
|
|
{
|
|
// In child
|
|
|
|
// Close or redirect file descriptors
|
|
redirects(bg);
|
|
|
|
// execl uses the current environ
|
|
(void) ::execl
|
|
(
|
|
"/bin/sh", // Path of the shell
|
|
"sh", // Command-name (name for the shell)
|
|
"-c", // Read commands from command_string operand
|
|
command.c_str(), // Command string
|
|
reinterpret_cast<char*>(0)
|
|
);
|
|
|
|
// Obviously failed, since exec should not return
|
|
FatalErrorInFunction
|
|
<< "exec failed: " << command
|
|
<< exit(FatalError);
|
|
|
|
return -1; // fallback error value
|
|
}
|
|
|
|
|
|
// In parent
|
|
// - started as background process, or blocking wait for the child
|
|
|
|
return (bg ? 0 : waitpid(child_pid));
|
|
}
|
|
|
|
|
|
int Foam::system(const CStringList& command, const bool bg)
|
|
{
|
|
if (command.empty())
|
|
{
|
|
// 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.
|
|
|
|
const pid_t child_pid = ::vfork();
|
|
|
|
if (child_pid == -1)
|
|
{
|
|
FatalErrorInFunction
|
|
<< "vfork() failed for system command " << command[0]
|
|
<< exit(FatalError);
|
|
|
|
return -1; // fallback error value
|
|
}
|
|
else if (child_pid == 0)
|
|
{
|
|
// In child
|
|
|
|
// Close or redirect file descriptors
|
|
redirects(bg);
|
|
|
|
// execvp searches the path, uses the current environ
|
|
(void) ::execvp(command[0], command.strings());
|
|
|
|
// Obviously failed, since exec should not return
|
|
FatalErrorInFunction
|
|
<< "exec(" << command[0] << ", ...) failed"
|
|
<< exit(FatalError);
|
|
|
|
return -1; // fallback error value
|
|
}
|
|
|
|
|
|
// In parent
|
|
// - started as background process, or blocking wait for the child
|
|
|
|
return (bg ? 0 : waitpid(child_pid));
|
|
}
|
|
|
|
|
|
int Foam::system(const Foam::UList<Foam::string>& command, const bool bg)
|
|
{
|
|
if (command.empty())
|
|
{
|
|
// Treat an empty command as a successful no-op.
|
|
return 0;
|
|
}
|
|
|
|
// Make a deep copy as C-strings
|
|
const CStringList cmd(command);
|
|
return Foam::system(cmd, bg);
|
|
}
|
|
|
|
|
|
void* Foam::dlOpen(const fileName& lib, const bool check)
|
|
{
|
|
if (POSIX::debug)
|
|
{
|
|
std::cout<< "dlOpen(const fileName&)"
|
|
<< " : dlopen of " << lib << std::endl;
|
|
}
|
|
void* handle = ::dlopen(lib.c_str(), RTLD_LAZY|RTLD_GLOBAL);
|
|
|
|
#ifdef darwin
|
|
// Re-try "libXX.so" as "libXX.dylib"
|
|
if (!handle && lib.hasExt("so"))
|
|
{
|
|
const fileName dylib(lib.lessExt().ext("dylib"));
|
|
handle = ::dlopen(dylib.c_str(), RTLD_LAZY|RTLD_GLOBAL);
|
|
}
|
|
#endif
|
|
|
|
if (!handle && check)
|
|
{
|
|
WarningInFunction
|
|
<< "dlopen error : " << ::dlerror()
|
|
<< endl;
|
|
}
|
|
|
|
if (POSIX::debug)
|
|
{
|
|
std::cout
|
|
<< "dlOpen(const fileName&)"
|
|
<< " : dlopen of " << lib
|
|
<< " handle " << handle << std::endl;
|
|
}
|
|
|
|
return handle;
|
|
}
|
|
|
|
|
|
bool Foam::dlClose(void* handle)
|
|
{
|
|
if (POSIX::debug)
|
|
{
|
|
std::cout
|
|
<< "dlClose(void*)"
|
|
<< " : dlclose of handle " << handle << std::endl;
|
|
}
|
|
return ::dlclose(handle) == 0;
|
|
}
|
|
|
|
|
|
void* Foam::dlSym(void* handle, const std::string& symbol)
|
|
{
|
|
if (POSIX::debug)
|
|
{
|
|
std::cout
|
|
<< "dlSym(void*, const std::string&)"
|
|
<< " : dlsym of " << symbol << std::endl;
|
|
}
|
|
// clear any old errors - see manpage dlopen
|
|
(void) ::dlerror();
|
|
|
|
// get address of symbol
|
|
void* fun = ::dlsym(handle, symbol.c_str());
|
|
|
|
// find error (if any)
|
|
char *error = ::dlerror();
|
|
|
|
if (error)
|
|
{
|
|
WarningInFunction
|
|
<< "Cannot lookup symbol " << symbol << " : " << error
|
|
<< endl;
|
|
}
|
|
|
|
return fun;
|
|
}
|
|
|
|
|
|
bool Foam::dlSymFound(void* handle, const std::string& symbol)
|
|
{
|
|
if (handle && !symbol.empty())
|
|
{
|
|
if (POSIX::debug)
|
|
{
|
|
std::cout
|
|
<< "dlSymFound(void*, const std::string&)"
|
|
<< " : dlsym of " << symbol << std::endl;
|
|
}
|
|
|
|
// clear any old errors - see manpage dlopen
|
|
(void) ::dlerror();
|
|
|
|
// get address of symbol
|
|
(void) ::dlsym(handle, symbol.c_str());
|
|
|
|
// symbol can be found if there was no error
|
|
return !::dlerror();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
#ifndef darwin
|
|
static int collectLibsCallback
|
|
(
|
|
struct dl_phdr_info *info,
|
|
size_t size,
|
|
void *data
|
|
)
|
|
{
|
|
Foam::DynamicList<Foam::fileName>* ptr =
|
|
reinterpret_cast<Foam::DynamicList<Foam::fileName>*>(data);
|
|
ptr->append(info->dlpi_name);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
Foam::fileNameList Foam::dlLoaded()
|
|
{
|
|
DynamicList<fileName> libs;
|
|
#ifdef darwin
|
|
for (uint32_t i=0; i < _dyld_image_count(); ++i)
|
|
{
|
|
libs.append(_dyld_get_image_name(i));
|
|
}
|
|
#else
|
|
dl_iterate_phdr(collectLibsCallback, &libs);
|
|
#endif
|
|
|
|
if (POSIX::debug)
|
|
{
|
|
std::cout
|
|
<< "dlLoaded()"
|
|
<< " : determined loaded libraries :" << libs.size() << std::endl;
|
|
}
|
|
return libs;
|
|
}
|
|
|
|
|
|
// ************************************************************************* //
|