in source/util/EnvUtils.cpp [51:151]
int EnvUtils::AppendCwdToPath()
{
// Use a vector of char as buffer for path to current working directory.
//
// Maximum number of characters in absolute path is filesystem dependent.
//
// The getcwd function takes a buffer and length and returns the current
// working directory or NULL if the length of the buffer is insufficient
// to store the current working directory.
//
// As a result, we initialize the buffer with the maximum length of a
// relative pathname (_PC_PATH_MAX) and then repeatedly resize the buffer
// in the event that getcwd is unable to fit the current working directory
// in the buffer passed as input.
std::vector<char> cwd;
long path_max = pathconf(".", _PC_PATH_MAX);
if (path_max < 1)
{
cwd.resize(PATH_MAX + 1, '\0'); // Fallback to hardcoded PATH_MAX.
}
else
{
cwd.resize(path_max + 1, '\0');
}
// Limit the number of times we resize the buffer to avoid infinite loop.
static constexpr const int maxCountResizes = 3;
char *pcwd = nullptr;
int countResizes = 0;
while (!pcwd)
{
pcwd = os->getcwd(cwd.data(), cwd.size() - 1); // Leave room for terminating null.
if (!pcwd)
{
if (errno == ERANGE)
{
if (countResizes++ < maxCountResizes)
{
cwd.resize(cwd.size() * 2, '\0');
}
else
{
LOGM_ERROR(
TAG,
"Current working directory requires more than %d bytes. Skip update to %s environment "
"variable.",
cwd.size(),
PATH_ENVIRONMENT);
return ENAMETOOLONG;
}
}
else
{
auto errnum = errno != 0 ? errno : 1;
LOGM_ERROR(TAG, "Unable to get current working directory errno: %d msg: %s", errnum, strerror(errnum));
return errnum;
}
}
}
// Append standard paths used by device client based on current working directory.
std::ostringstream oss;
if (const char *path = os->getenv(PATH_ENVIRONMENT))
{
oss << path;
}
if (oss.tellp())
{
oss << PATH_ENVIRONMENT_SEPARATOR;
}
// Copy of default config directory with trailing separator removed.
std::string defaultConfigDir = Config::ExpandDefaultConfigDir(true);
// Default config directory.
oss << defaultConfigDir;
// Jobs subdirectory of default config directory.
oss << PATH_ENVIRONMENT_SEPARATOR << defaultConfigDir << PATH_DIRECTORY_SEPARATOR << JOBS_DIRECTORY_NAME;
// Current working directory.
oss << PATH_ENVIRONMENT_SEPARATOR << cwd.data();
// Jobs subdirectory of current working directory.
oss << PATH_ENVIRONMENT_SEPARATOR << cwd.data() << PATH_DIRECTORY_SEPARATOR << JOBS_DIRECTORY_NAME;
// Overwrite path environment variable.
const std::string &newpath = oss.str();
if (os->setenv(PATH_ENVIRONMENT, newpath.c_str(), 1) != 0)
{
auto errnum = errno != 0 ? errno : 1;
LOGM_ERROR(
TAG,
"Unable to overwrite %s environment variable errno: %d msg: %s",
PATH_ENVIRONMENT,
errnum,
strerror(errnum));
return errnum;
}
LOGM_DEBUG(TAG, "Updated %s environment variable to: %s", PATH_ENVIRONMENT, newpath.c_str());
return 0;
}