/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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 .
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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef USE_RANDOM
#include
#if INT_MAX != 2147483647
#error "INT_MAX != 2147483647"
#error "The random number generator may not work!"
#endif
#endif
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(POSIX, 0);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
pid_t Foam::pid()
{
return ::getpid();
}
pid_t Foam::ppid()
{
return ::getppid();
}
pid_t Foam::pgid()
{
return ::getpgrp();
}
bool Foam::env(const word& envName)
{
return ::getenv(envName.c_str()) != NULL;
}
Foam::string Foam::getEnv(const word& envName)
{
char* env = ::getenv(envName.c_str());
if (env)
{
return string(env);
}
else
{
// 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
)
{
return 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 != NULL)
{
return pw->pw_name;
}
else
{
return string::null;
}
}
bool Foam::isAdministrator()
{
return (::geteuid() == 0);
}
Foam::fileName Foam::home()
{
char* env = ::getenv("HOME");
if (env != NULL)
{
return fileName(env);
}
else
{
struct passwd* pw = ::getpwuid(getuid());
if (pw != NULL)
{
return pw->pw_dir;
}
else
{
return fileName::null;
}
}
}
Foam::fileName Foam::home(const string& userName)
{
struct passwd* pw;
if (userName.size())
{
pw = ::getpwnam(userName.c_str());
}
else
{
char* env = ::getenv("HOME");
if (env != NULL)
{
return fileName(env);
}
pw = ::getpwuid(::getuid());
}
if (pw != NULL)
{
return pw->pw_dir;
}
else
{
return fileName::null;
}
}
Foam::fileName Foam::cwd()
{
label pathLengthLimit = POSIX::pathLengthChunk;
List 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 upto the pathLengthMax limit
if
(
(pathLengthLimit += POSIX::pathLengthChunk)
>= POSIX::pathLengthMax
)
{
FatalErrorInFunction
<< "Attempt to increase path length beyond limit of "
<< POSIX::pathLengthMax
<< exit(FatalError);
}
path.setSize(pathLengthLimit);
}
else
{
break;
}
}
FatalErrorInFunction
<< "Couldn't get the current working directory"
<< exit(FatalError);
return fileName::null;
}
bool Foam::chDir(const fileName& dir)
{
return ::chdir(dir.c_str()) == 0;
}
Foam::fileNameList Foam::findEtcFiles
(
const fileName& name,
bool mandatory,
bool findFirst
)
{
fileNameList results;
// Search for user files in
// * ~/.OpenFOAM/VERSION
// * ~/.OpenFOAM
//
fileName searchDir = home()/".OpenFOAM";
if (isDir(searchDir))
{
fileName fullName = searchDir/FOAMversion/name;
if (isFile(fullName))
{
results.append(fullName);
if (findFirst)
{
return results;
}
}
fullName = searchDir/name;
if (isFile(fullName))
{
results.append(fullName);
if (findFirst)
{
return results;
}
}
}
// Search for group (site) files in
// * $WM_PROJECT_SITE/VERSION
// * $WM_PROJECT_SITE
//
searchDir = getEnv("WM_PROJECT_SITE");
if (searchDir.size())
{
if (isDir(searchDir))
{
fileName fullName = searchDir/FOAMversion/name;
if (isFile(fullName))
{
results.append(fullName);
if (findFirst)
{
return results;
}
}
fullName = searchDir/name;
if (isFile(fullName))
{
results.append(fullName);
if (findFirst)
{
return results;
}
}
}
}
else
{
// OR search for group (site) files in
// * $WM_PROJECT_INST_DIR/site/VERSION
// * $WM_PROJECT_INST_DIR/site
//
searchDir = getEnv("WM_PROJECT_INST_DIR");
if (isDir(searchDir))
{
fileName fullName = searchDir/"site"/FOAMversion/name;
if (isFile(fullName))
{
results.append(fullName);
if (findFirst)
{
return results;
}
}
fullName = searchDir/"site"/name;
if (isFile(fullName))
{
results.append(fullName);
if (findFirst)
{
return results;
}
}
}
}
// Search for other (shipped) files in
// * $WM_PROJECT_DIR/etc
//
searchDir = getEnv("WM_PROJECT_DIR");
if (isDir(searchDir))
{
fileName fullName = searchDir/"etc"/name;
if (isFile(fullName))
{
results.append(fullName);
if (findFirst)
{
return results;
}
}
}
// Not found
if (results.empty())
{
// Abort if the file is mandatory, otherwise return null
if (mandatory)
{
std::cerr
<< "--> FOAM FATAL ERROR in Foam::findEtcFiles() :"
" could not find mandatory file\n '"
<< name.c_str() << "'\n\n" << std::endl;
::exit(1);
}
}
// Return list of matching paths or empty list if none found
return results;
}
Foam::fileName Foam::findEtcFile(const fileName& name, bool mandatory)
{
fileNameList results(findEtcFiles(name, mandatory, true));
if (results.size())
{
return results[0];
}
else
{
return fileName();
}
}
bool Foam::mkDir(const fileName& pathName, mode_t mode)
{
// empty names are meaningless
if (pathName.empty())
{
return false;
}
// Construct instance 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)
{
return ::chmod(name.c_str(), m) == 0;
}
mode_t Foam::mode(const fileName& name)
{
fileStat fileStatus(name);
if (fileStatus.isValid())
{
return fileStatus.status().st_mode;
}
else
{
return 0;
}
}
Foam::fileName::Type Foam::type(const fileName& name)
{
mode_t m = mode(name);
if (S_ISREG(m))
{
return fileName::FILE;
}
else if (S_ISDIR(m))
{
return fileName::DIRECTORY;
}
else
{
return fileName::UNDEFINED;
}
}
bool Foam::exists(const fileName& name, const bool checkGzip)
{
return mode(name) || isFile(name, checkGzip);
}
bool Foam::isDir(const fileName& name)
{
return S_ISDIR(mode(name));
}
bool Foam::isFile(const fileName& name, const bool checkGzip)
{
return S_ISREG(mode(name)) || (checkGzip && S_ISREG(mode(name + ".gz")));
}
off_t Foam::fileSize(const fileName& name)
{
fileStat fileStatus(name);
if (fileStatus.isValid())
{
return fileStatus.status().st_size;
}
else
{
return -1;
}
}
time_t Foam::lastModified(const fileName& name)
{
fileStat fileStatus(name);
if (fileStatus.isValid())
{
return fileStatus.status().st_mtime;
}
else
{
return 0;
}
}
Foam::fileNameList Foam::readDir
(
const fileName& directory,
const fileName::Type type,
const bool filtergz
)
{
// Initial filename list size
// also used as increment if initial size found to be insufficient
static const int maxNnames = 100;
if (POSIX::debug)
{
InfoInFunction
<< "reading directory " << directory << endl;
}
// Setup empty string list MAXTVALUES long
fileNameList dirEntries(maxNnames);
// Pointers to the directory entries
DIR *source;
struct dirent *list;
// Temporary variables and counters
label nEntries = 0;
// Attempt to open directory and set the structure pointer
if ((source = ::opendir(directory.c_str())) == NULL)
{
dirEntries.setSize(0);
if (POSIX::debug)
{
InfoInFunction
<< "cannot open directory " << directory << endl;
}
}
else
{
// Read and parse all the entries in the directory
while ((list = ::readdir(source)) != NULL)
{
fileName fName(list->d_name);
// ignore files begining with ., i.e. '.', '..' and '.*'
if (fName.size() && fName[0] != '.')
{
word fExt = fName.ext();
if
(
(type == fileName::DIRECTORY)
||
(
type == fileName::FILE
&& fName[fName.size()-1] != '~'
&& fExt != "bak"
&& fExt != "BAK"
&& fExt != "old"
&& fExt != "save"
)
)
{
if ((directory/fName).type() == type)
{
if (nEntries >= dirEntries.size())
{
dirEntries.setSize(dirEntries.size() + maxNnames);
}
if (filtergz && fExt == "gz")
{
dirEntries[nEntries++] = fName.lessExt();
}
else
{
dirEntries[nEntries++] = fName;
}
}
}
}
}
// Reset the length of the entries list
dirEntries.setSize(nEntries);
::closedir(source);
}
return dirEntries;
}
bool Foam::cp(const fileName& src, const fileName& dest)
{
// Make sure source exists.
if (!exists(src))
{
return false;
}
fileName destFile(dest);
// Check type of source file.
if (src.type() == fileName::FILE)
{
// If dest is a directory, create the destination file name.
if (destFile.type() == fileName::DIRECTORY)
{
destFile = 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.c_str());
if (!srcStream)
{
return false;
}
std::ofstream destStream(destFile.c_str());
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 (src.type() == fileName::DIRECTORY)
{
// If dest is a directory, create the destination file name.
if (destFile.type() == fileName::DIRECTORY)
{
destFile = destFile/src.component(src.components().size() -1);
}
// Make sure the destination directory exists.
if (!isDir(destFile) && !mkDir(destFile))
{
return false;
}
// Copy files
fileNameList contents = readDir(src, fileName::FILE, false);
forAll(contents, i)
{
if (POSIX::debug)
{
InfoInFunction
<< "Copying : " << src/contents[i]
<< " to " << destFile/contents[i] << endl;
}
// File to file.
cp(src/contents[i], destFile/contents[i]);
}
// Copy sub directories.
fileNameList subdirs = readDir(src, fileName::DIRECTORY);
forAll(subdirs, i)
{
if (POSIX::debug)
{
InfoInFunction
<< "Copying : " << src/subdirs[i]
<< " to " << destFile << endl;
}
// Dir to Dir.
cp(src/subdirs[i], destFile);
}
}
return true;
}
bool Foam::ln(const fileName& src, const fileName& dst)
{
if (POSIX::debug)
{
InfoInFunction
<< "Create softlink from : " << src << " to " << dst
<< endl;
}
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;
}
else
{
WarningInFunction
<< "symlink from " << src << " to " << dst << " failed." << endl;
return false;
}
}
bool Foam::mv(const fileName& src, const fileName& dst)
{
if (POSIX::debug)
{
InfoInFunction
<< "Move : " << src << " to " << dst << endl;
}
if
(
dst.type() == fileName::DIRECTORY
&& src.type() != 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
<< "mvBak : " << src << " to extension " << ext << endl;
}
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;
}
}
}
// fall-through: nothing to do
return false;
}
bool Foam::rm(const fileName& file)
{
if (POSIX::debug)
{
InfoInFunction
<< "Removing : " << file << endl;
}
// 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)
{
if (POSIX::debug)
{
InfoInFunction
<< "removing directory " << directory << endl;
}
// Pointers to the directory entries
DIR *source;
struct dirent *list;
// Attempt to open directory and set the structure pointer
if ((source = ::opendir(directory.c_str())) == NULL)
{
WarningInFunction
<< "cannot open directory " << directory << endl;
return false;
}
else
{
// Read and parse all the entries in the directory
while ((list = ::readdir(source)) != NULL)
{
fileName fName(list->d_name);
if (fName != "." && fName != "..")
{
fileName path = directory/fName;
if (path.type() == fileName::DIRECTORY)
{
if (!rmDir(path))
{
WarningInFunction
<< "failed to remove directory " << fName
<< " while removing directory " << directory
<< endl;
::closedir(source);
return false;
}
}
else
{
if (!rm(path))
{
WarningInFunction
<< "failed to remove file " << fName
<< " while removing directory " << directory
<< endl;
::closedir(source);
return false;
}
}
}
}
if (!rm(directory))
{
WarningInFunction
<< "failed to remove directory " << directory << endl;
::closedir(source);
return false;
}
::closedir(source);
return true;
}
}
unsigned int Foam::sleep(const unsigned int s)
{
return ::sleep(s);
}
void Foam::fdClose(const int fd)
{
if (close(fd) != 0)
{
FatalErrorInFunction
<< "close error on " << fd << endl
<< abort(FatalError);
}
}
bool Foam::ping
(
const 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())) == NULL)
{
FatalErrorInFunction
<< "gethostbyname error " << h_errno << " for host " << destName
<< abort(FatalError);
}
// Get first of the SLL of addresses
addr = (reinterpret_cast(*(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(&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(&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 string& hostname, const label timeOut)
{
return ping(hostname, 222, timeOut) || ping(hostname, 22, timeOut);
}
int Foam::system(const std::string& command)
{
return ::system(command.c_str());
}
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);
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();
}
else
{
return false;
}
}
static int collectLibsCallback
(
struct dl_phdr_info *info,
size_t size,
void *data
)
{
Foam::DynamicList* ptr =
reinterpret_cast*>(data);
ptr->append(info->dlpi_name);
return 0;
}
Foam::fileNameList Foam::dlLoaded()
{
DynamicList libs;
dl_iterate_phdr(collectLibsCallback, &libs);
if (POSIX::debug)
{
std::cout
<< "dlLoaded()"
<< " : determined loaded libraries :" << libs.size() << std::endl;
}
return libs;
}
void Foam::osRandomSeed(const label seed)
{
#ifdef USE_RANDOM
srandom((unsigned int)seed);
#else
srand48(seed);
#endif
}
Foam::label Foam::osRandomInteger()
{
#ifdef USE_RANDOM
return random();
#else
return lrand48();
#endif
}
Foam::scalar Foam::osRandomDouble()
{
#ifdef USE_RANDOM
return (scalar)random()/INT_MAX;
#else
return drand48();
#endif
}
// ************************************************************************* //