Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enh(ProcessRunner): does not detect launch errors #4482 #4483

Merged
merged 12 commits into from
Jul 29, 2024
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,9 @@ jobs:
class CppUnit::TestCaller<class ICMPClientTest>.testBigPing,
class CppUnit::TestCaller<class ICMPSocketTest>.testMTU,
class CppUnit::TestCaller<class HTTPSClientSessionTest>.testProxy,
class CppUnit::TestCaller<class HTTPSStreamFactoryTest>.testProxy
class CppUnit::TestCaller<class HTTPSStreamFactoryTest>.testProxy,
class CppUnit::TestCaller<class FileTest>.testExists,
class CppUnit::TestCaller<class ProcessRunnerTest>.testProcessRunner
steps:
- uses: actions/checkout@v4
- run: cmake -S. -Bcmake-build -DENABLE_NETSSL_WIN=ON -DENABLE_NETSSL=OFF -DENABLE_CRYPTO=OFF -DENABLE_JWT=OFF -DENABLE_DATA=ON -DENABLE_DATA_ODBC=ON -DENABLE_DATA_MYSQL=OFF -DENABLE_DATA_POSTGRESQL=OFF -DENABLE_TESTS=ON
Expand Down
7 changes: 6 additions & 1 deletion Foundation/include/Poco/Any.h
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,9 @@ class Any
template <typename ValueType>
friend ValueType* AnyCast(Any*);

template <typename ValueType>
friend const ValueType* AnyCast(const Any*);

template <typename ValueType>
friend ValueType* UnsafeAnyCast(Any*);

Expand Down Expand Up @@ -426,7 +429,9 @@ const ValueType* AnyCast(const Any* operand)
/// const MyType* pTmp = AnyCast<MyType>(pAny).
/// Returns nullptr if the types don't match.
{
return AnyCast<ValueType>(const_cast<Any*>(operand));
return operand && operand->type() == typeid(ValueType)
? &static_cast<const Any::Holder<ValueType>*>(operand->content())->_held
: nullptr;
}


Expand Down
1 change: 1 addition & 0 deletions Foundation/include/Poco/Exception.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ POCO_DECLARE_EXCEPTION(Foundation_API, CreateFileException, FileException)
POCO_DECLARE_EXCEPTION(Foundation_API, OpenFileException, FileException)
POCO_DECLARE_EXCEPTION(Foundation_API, WriteFileException, FileException)
POCO_DECLARE_EXCEPTION(Foundation_API, ReadFileException, FileException)
POCO_DECLARE_EXCEPTION(Foundation_API, ExecuteFileException, FileException)
POCO_DECLARE_EXCEPTION(Foundation_API, FileNotReadyException, FileException)
POCO_DECLARE_EXCEPTION(Foundation_API, DirectoryNotEmptyException, FileException)
POCO_DECLARE_EXCEPTION(Foundation_API, UnknownURISchemeException, RuntimeException)
Expand Down
19 changes: 17 additions & 2 deletions Foundation/include/Poco/File.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class Foundation_API File: private FileImpl
/// use the forward slash ("/") as directory separator.
{
public:
typedef FileSizeImpl FileSize;
using FileSize = FileSizeImpl;

enum LinkType
/// Type of link for linkTo().
Expand Down Expand Up @@ -84,7 +84,7 @@ class Foundation_API File: private FileImpl
File(const File& file);
/// Copy constructor.

virtual ~File();
~File() override;
/// Destroys the file.

File& operator = (const File& file);
Expand All @@ -105,9 +105,24 @@ class Foundation_API File: private FileImpl
const std::string& path() const;
/// Returns the path.

std::string absolutePath() const;
/// Returns absolute path.
/// Attempts to find the existing file
/// using curent work directory and the PATH
/// environment variable.
/// If the file doesn't exist, returns empty string.

bool exists() const;
/// Returns true iff the file exists.

bool existsAnywhere() const;
/// If the file path is relative, searches
/// for the file in the current working directory
/// and the environment paths.
/// If the file path is absolute, the
/// functionality is identical to the
/// exists() call.

bool canRead() const;
/// Returns true iff the file is readable.

Expand Down
6 changes: 4 additions & 2 deletions Foundation/include/Poco/File_UNIX.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@


#include "Poco/Foundation.h"
#include "Poco/Timestamp.h"


namespace Poco {
Expand All @@ -32,18 +33,19 @@ class FileImpl
OPT_FAIL_ON_OVERWRITE_IMPL = 0x01
};

typedef UInt64 FileSizeImpl;
using FileSizeImpl = UInt64;

FileImpl();
FileImpl(const std::string& path);
virtual ~FileImpl();
void swapImpl(FileImpl& file);
void setPathImpl(const std::string& path);
const std::string& getPathImpl() const;
std::string getExecutablePathImpl() const;
bool existsImpl() const;
bool canReadImpl() const;
bool canWriteImpl() const;
bool canExecuteImpl() const;
bool canExecuteImpl(const std::string& absolutePath) const;
bool isFileImpl() const;
bool isDirectoryImpl() const;
bool isLinkImpl() const;
Expand Down
7 changes: 4 additions & 3 deletions Foundation/include/Poco/File_VX.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@


#include "Poco/Foundation.h"

#include "Poco/Timestamp.h"

namespace Poco {

Expand All @@ -32,18 +32,19 @@ class FileImpl
OPT_FAIL_ON_OVERWRITE_IMPL = 0x01
};

typedef UInt64 FileSizeImpl;
using FileSizeImpl = UInt64;

FileImpl();
FileImpl(const std::string& path);
virtual ~FileImpl();
void swapImpl(FileImpl& file);
void setPathImpl(const std::string& path);
const std::string& getPathImpl() const;
std::string getExecutablePathImpl() const;
bool existsImpl() const;
bool canReadImpl() const;
bool canWriteImpl() const;
bool canExecuteImpl() const;
bool canExecuteImpl(const std::string& absolutePath) const;
bool isFileImpl() const;
bool isDirectoryImpl() const;
bool isLinkImpl() const;
Expand Down
5 changes: 3 additions & 2 deletions Foundation/include/Poco/File_WIN32U.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,19 @@ class Foundation_API FileImpl
OPT_FAIL_ON_OVERWRITE_IMPL = 0x01
};

typedef UInt64 FileSizeImpl;
using FileSizeImpl = UInt64;

FileImpl();
FileImpl(const std::string& path);
virtual ~FileImpl();
void swapImpl(FileImpl& file);
void setPathImpl(const std::string& path);
const std::string& getPathImpl() const;
std::string getExecutablePathImpl() const;
bool existsImpl() const;
bool canReadImpl() const;
bool canWriteImpl() const;
bool canExecuteImpl() const;
bool canExecuteImpl(const std::string& absolutePath) const;
bool isFileImpl() const;
bool isDirectoryImpl() const;
bool isLinkImpl() const;
Expand Down
2 changes: 1 addition & 1 deletion Foundation/include/Poco/Path.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class Foundation_API Path
PATH_GUESS /// Guess the style by examining the path
};

typedef std::vector<std::string> StringVec;
using StringVec = std::vector<std::string>;

Path();
/// Creates an empty relative path.
Expand Down
34 changes: 33 additions & 1 deletion Foundation/include/Poco/ProcessRunner.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ class Foundation_API ProcessRunner: public Poco::Runnable
int runCount() const;
/// Returns the number of times the process has been executed.

const std::string& error() const;
/// Returns the error message.

private:
static const Poco::ProcessHandle::PID INVALID_PID = -1;
Expand All @@ -141,10 +143,23 @@ class Foundation_API ProcessRunner: public Poco::Runnable
/// Process initialization completion is indicated by new pid in
/// the pid file. If pid file is not specified, there is no waiting.

void checkTimeout(const Poco::Stopwatch& sw, const std::string& msg);
void checkError();
/// If timeout is exceeded, throws TimeoutException with `msg`
/// message.

void checkTimeout(const std::string& msg);
/// If timeout is exceeded, throws TimeoutException with `msg`
/// message.

void checkStatus(const std::string& msg, bool tOut = true);
/// If there were andy errors during process start/stop,
/// throws RuntimeException with the error message;
/// otherwise, if tOut is true and timeout is exceeded, throws
/// TimeoutException with `msg` message.

void setError(const std::string& msg);
/// Sets the error message.

Poco::Thread _t;
std::string _cmd;
Args _args;
Expand All @@ -156,6 +171,9 @@ class Foundation_API ProcessRunner: public Poco::Runnable
std::atomic<bool> _started;
std::atomic<int> _rc;
std::atomic<int> _runCount;
Stopwatch _sw;
std::string _error;
mutable Poco::FastMutex _mutex;
};


Expand Down Expand Up @@ -193,6 +211,20 @@ inline int ProcessRunner::runCount() const
}


inline void ProcessRunner::setError(const std::string& msg)
{
_error = Poco::format("ProcessRunner(%s): %s", cmdLine(), msg);
}


inline const std::string& ProcessRunner::error() const
{
Poco::FastMutex::ScopedLock l(_mutex);

return _error;
}


} // namespace Poco


Expand Down
1 change: 1 addition & 0 deletions Foundation/src/Exception.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ POCO_IMPLEMENT_EXCEPTION(CreateFileException, FileException, "Cannot create file
POCO_IMPLEMENT_EXCEPTION(OpenFileException, FileException, "Cannot open file")
POCO_IMPLEMENT_EXCEPTION(WriteFileException, FileException, "Cannot write file")
POCO_IMPLEMENT_EXCEPTION(ReadFileException, FileException, "Cannot read file")
POCO_IMPLEMENT_EXCEPTION(ExecuteFileException, FileException, "Cannot execute file")
POCO_IMPLEMENT_EXCEPTION(FileNotReadyException, FileException, "File not ready")
POCO_IMPLEMENT_EXCEPTION(DirectoryNotEmptyException, FileException, "Directory not empty")
POCO_IMPLEMENT_EXCEPTION(UnknownURISchemeException, RuntimeException, "Unknown URI scheme")
Expand Down
76 changes: 75 additions & 1 deletion Foundation/src/File.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include "Poco/File.h"
#include "Poco/Path.h"
#include "Poco/DirectoryIterator.h"
#include "Poco/Environment.h"
#include "Poco/StringTokenizer.h"


#if defined(POCO_OS_FAMILY_WINDOWS)
Expand Down Expand Up @@ -95,12 +97,77 @@ void File::swap(File& file) noexcept
}


std::string File::absolutePath() const
{
std::string ret;

if (Path(path()).isAbsolute())
// TODO: Should this return empty string if file does not exists to be consistent
// with the function documentation?
ret = getPathImpl();
else
{
Path curPath(Path::current());
curPath.append(path());
if (File(curPath).exists())
ret = curPath.toString();
else
{
const std::string envPath = Environment::get("PATH", "");
const std::string pathSeparator(1, Path::pathSeparator());
if (!envPath.empty())
{
const StringTokenizer st(envPath, pathSeparator,
StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);

for (const auto& p: st)
{
try
{
std::string fileName(p);
if (p.size() && p.back() != Path::separator())
fileName.append(1, Path::separator());
fileName.append(path());
if (File(fileName).exists())
{
ret = fileName;
break;
}
}
catch (const Poco::PathSyntaxException&)
{
// shield against bad PATH environment entries
}
}
}
}
}

return ret;
}


bool File::exists() const
{
if (path().empty()) return false;
return existsImpl();
}


bool File::existsAnywhere() const
{
if (path().empty()) return false;

if (Path(path()).isAbsolute())
return existsImpl();

if (File(absolutePath()).exists())
return true;

return false;
}


bool File::canRead() const
{
return canReadImpl();
Expand All @@ -115,7 +182,14 @@ bool File::canWrite() const

bool File::canExecute() const
{
return canExecuteImpl();
// Resolve (platform-specific) executable path and absolute path from relative.
const auto execPath { getExecutablePathImpl() };
const auto absPath { File(execPath).absolutePath() };
if (absPath.empty() || !File(absPath).exists())
{
return false;
}
return canExecuteImpl(absPath);
}


Expand Down
13 changes: 10 additions & 3 deletions Foundation/src/File_UNIX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "Poco/Buffer.h"
#include "Poco/Exception.h"
#include "Poco/Error.h"
#include "Poco/Path.h"
#include <algorithm>
#include <sys/stat.h>
#include <sys/types.h>
Expand Down Expand Up @@ -80,6 +81,12 @@ void FileImpl::setPathImpl(const std::string& path)
}


std::string FileImpl::getExecutablePathImpl() const
{
return _path;
}


bool FileImpl::existsImpl() const
{
poco_assert (!_path.empty());
Expand Down Expand Up @@ -127,12 +134,12 @@ bool FileImpl::canWriteImpl() const
}


bool FileImpl::canExecuteImpl() const
bool FileImpl::canExecuteImpl(const std::string& absolutePath) const
{
poco_assert (!_path.empty());
poco_assert (!absolutePath.empty());

struct stat st;
if (stat(_path.c_str(), &st) == 0)
if (stat(absolutePath.c_str(), &st) == 0)
{
if (st.st_uid == geteuid() || geteuid() == 0)
return (st.st_mode & S_IXUSR) != 0;
Expand Down
Loading
Loading