return; // nothing to do
}
- auto dir = std::unique_ptr<DIR, decltype(&closedir)>(opendir(directory.c_str()), closedir);
- if (dir == nullptr) {
- int err = errno;
- string msg = directory + " is not accessible: " + stringerror(err);
- SLOG(g_log << Logger::Error << msg << std::endl,
- d_log->error(Logr::Error, err, "Directory is not accessible", "name", Logging::Loggable(directory)));
- throw ArgException(msg);
- }
-
std::vector<std::string> vec;
- struct dirent* ent = nullptr;
- while ((ent = readdir(dir.get())) != nullptr) { // NOLINT(concurrency-mt-unsafe): see Linux man page
- if (ent->d_name[0] == '.') {
- continue; // skip any dots
+ auto directoryError = pdns::visit_directory(directory, [this, &directory, &suffix, &vec]([[maybe_unused]] ino_t inodeNumber, const std::string_view& name) {
+ (void)this;
+ if (boost::starts_with(name, ".")) {
+ return true; // skip any dots
}
- if (boost::ends_with(ent->d_name, suffix)) {
+ if (boost::ends_with(name, suffix)) {
// build name
- string name = directory + "/" + ent->d_name; // NOLINT: Posix API
+ string fullName = directory + "/" + std::string(name);
// ensure it's readable file
struct stat statInfo
{
};
- if (stat(name.c_str(), &statInfo) != 0 || !S_ISREG(statInfo.st_mode)) {
- string msg = name + " is not a regular file";
+ if (stat(fullName.c_str(), &statInfo) != 0 || !S_ISREG(statInfo.st_mode)) {
+ string msg = fullName + " is not a regular file";
SLOG(g_log << Logger::Error << msg << std::endl,
- d_log->info(Logr::Error, "Unable to open non-regular file", "name", Logging::Loggable(name)));
+ d_log->info(Logr::Error, "Unable to open non-regular file", "name", Logging::Loggable(fullName)));
throw ArgException(msg);
}
- vec.emplace_back(name);
+ vec.emplace_back(fullName);
}
+ return true;
+ });
+
+ if (directoryError) {
+ int err = errno;
+ string msg = directory + " is not accessible: " + stringerror(err);
+ SLOG(g_log << Logger::Error << msg << std::endl,
+ d_log->error(Logr::Error, err, "Directory is not accessible", "name", Logging::Loggable(directory)));
+ throw ArgException(msg);
}
+
std::sort(vec.begin(), vec.end(), CIStringComparePOSIX());
extraConfigs.insert(extraConfigs.end(), vec.begin(), vec.end());
}
void BackendMakerClass::load_all()
{
// TODO: Implement this?
- auto dir = std::unique_ptr<DIR, decltype(&closedir)>(opendir(arg()["module-dir"].c_str()), closedir);
- if (!dir) {
- g_log<<Logger::Error<<"Unable to open module directory '"<<arg()["module-dir"]<<"'"<<endl;
- return;
- }
- struct dirent* entry = nullptr;
- // NOLINTNEXTLINE(concurrency-mt-unsafe): readdir is thread-safe nowadays and readdir_r is deprecated
- while ((entry = readdir(dir.get())) != nullptr) {
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay): this is what dirent is
- auto name = std::string_view(entry->d_name, strlen(entry->d_name));
+ auto directoryError = pdns::visit_directory(arg()["module-dir"], [this]([[maybe_unused]] ino_t inodeNumber, const std::string_view& name) {
if (boost::starts_with(name, "lib") &&
name.size() > 13 &&
boost::ends_with(name, "backend.so")) {
- load(entry->d_name);
+ load(std::string(name));
}
+ return true;
+ });
+ if (directoryError) {
+ g_log<<Logger::Error<<"Unable to open module directory '"<<arg()["module-dir"]<<"': "<<*directoryError<<endl;
}
}
}
std::vector<std::string> files;
- {
- auto dirHandle = std::unique_ptr<DIR, decltype(&closedir)>(opendir(dirname.c_str()), closedir);
- if (!dirHandle) {
- errlog("Error opening the included directory %s!", dirname.c_str());
- g_outputBuffer = "Error opening the included directory " + dirname + "!";
- return;
- }
-
- struct dirent* ent = nullptr;
- // NOLINTNEXTLINE(concurrency-mt-unsafe): readdir is thread-safe nowadays and readdir_r is deprecated
- while ((ent = readdir(dirHandle.get())) != nullptr) {
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay): this is what dirent is
- if (ent->d_name[0] == '.') {
- continue;
- }
-
- if (boost::ends_with(ent->d_name, ".conf")) {
- std::ostringstream namebuf;
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay): this is what dirent is
- namebuf << dirname << "/" << ent->d_name;
-
- if (stat(namebuf.str().c_str(), &st) != 0 || !S_ISREG(st.st_mode)) {
- continue;
- }
-
+ auto directoryError = pdns::visit_directory(dirname, [&dirname, &files]([[maybe_unused]] ino_t inodeNumber, const std::string_view& name) {
+ if (boost::starts_with(name, ".")) {
+ return true;
+ }
+ if (boost::ends_with(name, ".conf")) {
+ std::ostringstream namebuf;
+ namebuf << dirname << "/" << name;
+ struct stat fileStat
+ {
+ };
+ if (stat(namebuf.str().c_str(), &fileStat) == 0 && S_ISREG(fileStat.st_mode)) {
files.push_back(namebuf.str());
}
}
+ return true;
+ });
+
+ if (directoryError) {
+ errlog("Error opening included directory: %s!", *directoryError);
+ g_outputBuffer = "Error opening included directory: " + *directoryError + "!";
+ return;
}
std::sort(files.begin(), files.end());
static void cleanUpDomain(const DNSName& domain, const uint16_t& keep, const string& workdir) {
string dir = workdir + "/" + domain.toString();
vector<uint32_t> zoneVersions;
- {
- auto dirHandle = std::unique_ptr<DIR, decltype(&closedir)>(opendir(dir.c_str()), closedir);
- if (!dirHandle) {
- return;
- }
-
- struct dirent* entry = nullptr;
- // NOLINTNEXTLINE(concurrency-mt-unsafe): readdir is thread-safe nowadays and readdir_r is deprecated
- while ((entry = readdir(dirHandle.get())) != nullptr) {
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay): this is what dirent is
- if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
- continue;
+ auto directoryError = pdns::visit_directory(dir, [&zoneVersions]([[maybe_unused]] ino_t inodeNumber, const std::string_view& name) {
+ if (name != "." && name != "..") {
+ try {
+ auto version = pdns::checked_stoi<uint32_t>(std::string(name));
+ zoneVersions.push_back(version);
+ }
+ catch (...) {
}
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay): this is what dirent is
- zoneVersions.push_back(std::stoi(entry->d_name));
}
+ return true;
+ });
+
+ if (directoryError) {
+ return;
}
g_log<<Logger::Info<<"Found "<<zoneVersions.size()<<" versions of "<<domain<<", asked to keep "<<keep<<", ";
uint32_t getSerialFromDir(const std::string& dir)
{
uint32_t ret = 0;
- auto dirhdl = std::unique_ptr<DIR, decltype(&closedir)>(opendir(dir.c_str()), closedir);
- if (!dirhdl) {
- throw runtime_error("Could not open IXFR directory '" + dir + "': " + stringerror());
- }
-
- struct dirent* entry = nullptr;
- // NOLINTNEXTLINE(concurrency-mt-unsafe): readdir is thread-safe nowadays and readdir_r is deprecated
- while ((entry = readdir(dirhdl.get())) != nullptr) {
- uint32_t num = atoi(entry->d_name);
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay): this is what dirent is
- auto name = std::string_view(entry->d_name, strlen(entry->d_name));
- if (std::to_string(num) == name) {
- ret = max(num, ret);
+ auto directoryError = pdns::visit_directory(dir, [&ret]([[maybe_unused]] ino_t inodeNumber, const std::string_view& name) {
+ try {
+ auto version = pdns::checked_stoi<uint32_t>(std::string(name));
+ if (std::to_string(version) == name) {
+ ret = std::max(version, ret);
+ }
}
+ catch (...) {
+ }
+ return true;
+ });
+
+ if (directoryError) {
+ throw runtime_error("Could not open IXFR directory '" + dir + "': " + *directoryError);
}
return ret;
uint64_t getOpenFileDescriptors(const std::string&)
{
#ifdef __linux__
- auto dirHandle = std::unique_ptr<DIR, decltype(&closedir)>(opendir(("/proc/"+std::to_string(getpid())+"/fd/").c_str()), closedir);
- if (!dirHandle) {
- return 0;
- }
-
- int ret = 0;
- struct dirent* entry = nullptr;
- // NOLINTNEXTLINE(concurrency-mt-unsafe): readdir is thread-safe nowadays and readdir_r is deprecated
- while ((entry = readdir(dirHandle.get())) != nullptr) {
+ uint64_t nbFileDescriptors = 0;
+ const auto dirName = "/proc/" + std::to_string(getpid()) + "/fd/";
+ auto directoryError = pdns::visit_directory(dirName, [&nbFileDescriptors]([[maybe_unused]] ino_t inodeNumber, const std::string_view& name) {
uint32_t num;
try {
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay): this is what dirent is
- pdns::checked_stoi_into(num, entry->d_name);
+ pdns::checked_stoi_into(num, std::string(name));
+ if (std::to_string(num) == name) {
+ nbFileDescriptors++;
+ }
} catch (...) {
- continue; // was not a number.
- }
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay): this is what dirent is
- if (std::to_string(num) == entry->d_name) {
- ret++;
+ // was not a number.
}
+ return true;
+ });
+ if (directoryError) {
+ return 0U;
}
- return ret;
-
+ return nbFileDescriptors;
#elif defined(__OpenBSD__)
// FreeBSD also has this in libopenbsd, but I don't know if that's available always
return getdtablecount();
#else
- return 0;
+ return 0U;
#endif
}
#endif /* !HAVE_SODIUM_MEMCMP */
#endif /* !HAVE_CRYPTO_MEMCMP */
}
+
+namespace pdns
+{
+std::optional<std::string> visit_directory(const std::string& directory, const std::function<bool(ino_t inodeNumber, const std::string_view& name)>& visitor)
+{
+ auto dirHandle = std::unique_ptr<DIR, decltype(&closedir)>(opendir(directory.c_str()), closedir);
+ if (!dirHandle) {
+ auto err = errno;
+ return std::string("Error opening directory '" + directory + "': " + stringerror(err));
+ }
+
+ bool keepGoing = true;
+ struct dirent* ent = nullptr;
+ // NOLINTNEXTLINE(concurrency-mt-unsafe): readdir is thread-safe nowadays and readdir_r is deprecated
+ while (keepGoing && (ent = readdir(dirHandle.get())) != nullptr) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay: dirent API
+ auto name = std::string_view(ent->d_name, strlen(ent->d_name));
+ keepGoing = visitor(ent->d_ino, name);
+ }
+
+ return std::nullopt;
+}
+}
private:
int d_fd{-1};
};
+
+namespace pdns
+{
+[[nodiscard]] std::optional<std::string> visit_directory(const std::string& directory, const std::function<bool(ino_t inodeNumber, const std::string_view& name)>& visitor);
+}