diff options
Diffstat (limited to 'src/lib/log/interprocess/interprocess_sync_file.cc')
-rw-r--r-- | src/lib/log/interprocess/interprocess_sync_file.cc | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/src/lib/log/interprocess/interprocess_sync_file.cc b/src/lib/log/interprocess/interprocess_sync_file.cc new file mode 100644 index 0000000..ed6a5b7 --- /dev/null +++ b/src/lib/log/interprocess/interprocess_sync_file.cc @@ -0,0 +1,132 @@ +// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// This file requires LOCKFILE_DIR to be defined. It points to the default +// directory where lockfile will be created. + +#include <config.h> + +#include <log/interprocess/interprocess_sync_file.h> + +#include <string> +#include <cerrno> +#include <cstring> +#include <sstream> +#include <iostream> + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> + +namespace isc { +namespace log { +namespace interprocess { + +InterprocessSyncFile::~InterprocessSyncFile() { + if (fd_ != -1) { + // This will also release any applied locks. + close(fd_); + // The lockfile will continue to exist, and we must not delete + // it. + } +} + +bool +InterprocessSyncFile::do_lock(int cmd, short l_type) { + // Open lock file only when necessary (i.e., here). This is so that + // if a default InterprocessSync object is replaced with another + // implementation, it doesn't attempt any opens. + if (fd_ == -1) { + std::string lockfile_path = LOCKFILE_DIR; + + const char* const env = getenv("KEA_LOCKFILE_DIR"); + if (env != NULL) { + lockfile_path = env; + } + + lockfile_path += "/" + task_name_ + "_lockfile"; + + // Open the lockfile in the constructor so it doesn't do the access + // checks every time a message is logged. + const mode_t mode = umask(S_IXUSR | S_IXGRP | S_IXOTH); // 0111 + fd_ = open(lockfile_path.c_str(), O_CREAT | O_RDWR, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); // 0660 + umask(mode); + + if (fd_ == -1) { + std::stringstream tmp; + + // We failed to create a lockfile. This means that the logging + // system is unusable. We need to report the issue using plain + // print to stderr. + tmp << "Unable to use interprocess sync lockfile (" + << std::strerror(errno) << "): " << lockfile_path; + std::cerr << tmp.str() << std::endl; + + // And then throw exception as usual. + isc_throw(InterprocessSyncFileError, tmp.str()); + } + } + + struct flock lock; + + memset(&lock, 0, sizeof (lock)); + lock.l_type = l_type; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 1; + + return (fcntl(fd_, cmd, &lock) == 0); +} + +bool +InterprocessSyncFile::lock() { + if (is_locked_) { + return (true); + } + + if (do_lock(F_SETLKW, F_WRLCK)) { + is_locked_ = true; + return (true); + } + + return (false); +} + +bool +InterprocessSyncFile::tryLock() { + if (is_locked_) { + return (true); + } + + if (do_lock(F_SETLK, F_WRLCK)) { + is_locked_ = true; + return (true); + } + + return (false); +} + +bool +InterprocessSyncFile::unlock() { + if (!is_locked_) { + return (true); + } + + if (do_lock(F_SETLKW, F_UNLCK)) { + is_locked_ = false; + return (true); + } + + return (false); +} + +} // namespace interprocess +} // namespace log +} // namespace isc |