fdbmonitor now deconfigures processes when the config file is deleted. Depending on the specified settings, running processes may or may not be killed in that case. If they are not killed, then they are rejoined with the config if it reappears.
In this implementation, the deletion or moving of a parent directory does not trigger an immediate reload of the configuration, but the change will be detected the next time the configuration is reloaded for other reasons.
This commit is contained in:
parent
7f72aa7de5
commit
9d83501800
|
@ -621,11 +621,12 @@ void load_conf(const char* confpath, uid_t &uid, gid_t &gid, sigset_t* mask, fdb
|
|||
ini.SetUnicode();
|
||||
|
||||
SI_Error err = ini.LoadFile(confpath);
|
||||
if (err<0) {
|
||||
bool loadedConf = err >= 0;
|
||||
if (!loadedConf) {
|
||||
log_msg(LOG_ERR, "Unable to load configuration file %s (SI_Error: %d, errno: %d)\n", confpath, err, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
if(loadedConf) {
|
||||
uid_t _uid;
|
||||
gid_t _gid;
|
||||
|
||||
|
@ -671,12 +672,13 @@ void load_conf(const char* confpath, uid_t &uid, gid_t &gid, sigset_t* mask, fdb
|
|||
|
||||
uid = _uid;
|
||||
gid = _gid;
|
||||
}
|
||||
|
||||
std::list<uint64_t> kill_ids;
|
||||
std::list<std::pair<uint64_t, Command*>> start_ids;
|
||||
|
||||
for (auto i : id_pid) {
|
||||
if (ini.GetSectionSize(id_command[i.first]->ssection.c_str()) == -1) {
|
||||
if (!loadedConf || ini.GetSectionSize(id_command[i.first]->ssection.c_str()) == -1) {
|
||||
/* Server on this port no longer configured; deconfigure it and kill it if required */
|
||||
log_msg(LOG_INFO, "Deconfigured %s\n", id_command[i.first]->ssection.c_str());
|
||||
|
||||
|
@ -717,6 +719,7 @@ void load_conf(const char* confpath, uid_t &uid, gid_t &gid, sigset_t* mask, fdb
|
|||
|
||||
/* We've handled deconfigured sections, now look for newly
|
||||
configured sections */
|
||||
if(loadedConf) {
|
||||
CSimpleIniA::TNamesDepend sections;
|
||||
ini.GetAllSections(sections);
|
||||
for (auto i : sections) {
|
||||
|
@ -750,6 +753,7 @@ void load_conf(const char* confpath, uid_t &uid, gid_t &gid, sigset_t* mask, fdb
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* cmd->pipes[pipe_idx] *must* be ready to read without blocking */
|
||||
|
@ -785,6 +789,48 @@ void read_child_output( Command* cmd, int pipe_idx, fdb_fd_set fds ) {
|
|||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
void watch_conf_dir( int kq, int* confd_fd, std::string confdir ) {
|
||||
struct kevent ev;
|
||||
std::string original = confdir;
|
||||
|
||||
while(true) {
|
||||
/* If already watching, drop it and close */
|
||||
if ( *confd_fd >= 0 ) {
|
||||
EV_SET( &ev, *confd_fd, EVFILT_VNODE, EV_DELETE, NOTE_WRITE, 0, NULL );
|
||||
kevent( kq, &ev, 1, NULL, 0, NULL );
|
||||
close( *confd_fd );
|
||||
}
|
||||
|
||||
confdir = original;
|
||||
std::string child = confdir;
|
||||
|
||||
/* Find the nearest existing ancestor */
|
||||
while( (*confd_fd = open( confdir.c_str(), O_EVTONLY )) < 0 && errno == ENOENT ) {
|
||||
child = confdir;
|
||||
confdir = parentDirectory(confdir);
|
||||
}
|
||||
|
||||
if ( *confd_fd >= 0 ) {
|
||||
EV_SET( &ev, *confd_fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE, 0, NULL );
|
||||
kevent( kq, &ev, 1, NULL, 0, NULL );
|
||||
|
||||
/* If our child appeared since we last tested it, start over from the beginning */
|
||||
if ( confdir != child && (access(child.c_str(), F_OK) == 0 || errno != ENOENT) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(confdir != original) {
|
||||
log_msg(LOG_INFO, "Watching parent directory of missing directory %s\n", child.c_str());
|
||||
}
|
||||
else {
|
||||
log_msg(LOG_INFO, "Watching conf dir %s\n", confdir.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void watch_conf_file( int kq, int* conff_fd, const char* confpath ) {
|
||||
struct kevent ev;
|
||||
|
||||
|
@ -805,12 +851,8 @@ void watch_conf_file( int kq, int* conff_fd, const char* confpath ) {
|
|||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
void fdbmon_stat(const char *path, struct stat *path_stat, bool is_link) {
|
||||
int result = is_link ? lstat(path, path_stat) : stat(path, path_stat);
|
||||
if(result) {
|
||||
perror(is_link ? "lstat" : "stat");
|
||||
exit(1);
|
||||
}
|
||||
int fdbmon_stat(const char *path, struct stat *path_stat, bool is_link) {
|
||||
return is_link ? lstat(path, path_stat) : stat(path, path_stat);
|
||||
}
|
||||
|
||||
std::unordered_map<int, std::unordered_set<std::string>> set_watches(std::string path, int ifd) {
|
||||
|
@ -821,20 +863,32 @@ std::unordered_map<int, std::unordered_set<std::string>> set_watches(std::string
|
|||
return additional_watch_wds;
|
||||
|
||||
int idx = 1;
|
||||
while(idx != std::string::npos) {
|
||||
bool exists = true;
|
||||
while(idx != std::string::npos && exists) {
|
||||
idx = path.find_first_of('/', idx+1);
|
||||
std::string subpath = path.substr(0, idx);
|
||||
|
||||
int level = 0;
|
||||
while(true) {
|
||||
if(level++ == 100) {
|
||||
int result = fdbmon_stat(subpath.c_str(), &path_stat, true);
|
||||
if(result != 0) {
|
||||
if(errno == ENOENT) {
|
||||
exists = false;
|
||||
}
|
||||
else {
|
||||
perror("lstat");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if(exists) {
|
||||
if(!S_ISLNK(path_stat.st_mode)) {
|
||||
break;
|
||||
}
|
||||
else if(level++ == 100) {
|
||||
log_msg(LOG_ERR, "Too many nested symlinks in path %s\n", path.c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fdbmon_stat(subpath.c_str(), &path_stat, true);
|
||||
if(!S_ISLNK(path_stat.st_mode)) {
|
||||
break;
|
||||
}
|
||||
|
||||
std::string parent = parentDirectory(subpath);
|
||||
|
@ -845,8 +899,21 @@ std::unordered_map<int, std::unordered_set<std::string>> set_watches(std::string
|
|||
exit(1);
|
||||
}
|
||||
|
||||
if(exists) {
|
||||
log_msg(LOG_INFO, "Watching parent directory of symlink %s (%d)\n", subpath.c_str(), wd);
|
||||
additional_watch_wds[wd].insert(subpath.substr(parent.size()+1));
|
||||
}
|
||||
else {
|
||||
/* If the subpath appeared since we last checked, we should resume traversing the path */
|
||||
int result = fdbmon_stat(subpath.c_str(), &path_stat, true);
|
||||
if(result == 0 || errno != ENOENT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
log_msg(LOG_INFO, "Watching parent directory of missing directory %s (%d)\n", subpath.c_str(), wd);
|
||||
additional_watch_wds[wd].insert(subpath.substr(parent.size()+1));
|
||||
break;
|
||||
}
|
||||
|
||||
char buf[PATH_MAX+1];
|
||||
ssize_t len = readlink(subpath.c_str(), buf, PATH_MAX);
|
||||
|
@ -1047,13 +1114,12 @@ int main(int argc, char** argv) {
|
|||
EV_SET( &ev, SIGCHLD, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
|
||||
kevent( kq, &ev, 1, NULL, 0, NULL );
|
||||
|
||||
int confd_fd = open(confdir.c_str(), O_EVTONLY);
|
||||
int confd_fd = -1;
|
||||
int conff_fd = -1;
|
||||
|
||||
// Watch the directory holding the configuration file
|
||||
EV_SET( &ev, confd_fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE, 0, NULL );
|
||||
kevent( kq, &ev, 1, NULL, 0, NULL );
|
||||
watch_conf_dir( kq, &confd_fd, confdir );
|
||||
|
||||
int conff_fd = -1;
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
|
@ -1097,18 +1163,29 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
conffile_wd = inotify_add_watch(ifd, confpath.c_str(), IN_CLOSE_WRITE);
|
||||
if (conffile_wd < 0) {
|
||||
if(errno != ENOENT) {
|
||||
perror("inotify_add_watch conf file");
|
||||
exit(1); // Deleting the conf file causes fdbmonitor to terminate
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
log_msg(LOG_INFO, "Conf file has been deleted %s\n", confpath.c_str());
|
||||
}
|
||||
} else {
|
||||
log_msg(LOG_INFO, "Watching config file %s\n", confpath.c_str());
|
||||
log_msg(LOG_INFO, "Watching conf file %s\n", confpath.c_str());
|
||||
}
|
||||
|
||||
confdir_wd = inotify_add_watch(ifd, confdir.c_str(), IN_CLOSE_WRITE | IN_MOVED_TO);
|
||||
if (confdir_wd < 0) {
|
||||
if(errno != ENOENT) {
|
||||
perror("inotify_add_watch conf dir");
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
reload_additional_watches = true;
|
||||
log_msg(LOG_INFO, "Conf dir has been deleted %s\n", confdir.c_str());
|
||||
}
|
||||
} else {
|
||||
log_msg(LOG_INFO, "Watching config dir %s (%d)\n", confdir.c_str(), confdir_wd);
|
||||
log_msg(LOG_INFO, "Watching conf dir %s (%d)\n", confdir.c_str(), confdir_wd);
|
||||
}
|
||||
|
||||
if(reload_additional_watches) {
|
||||
|
@ -1120,6 +1197,7 @@ int main(int argc, char** argv) {
|
|||
#elif defined(__APPLE__)
|
||||
load_conf( confpath.c_str(), uid, gid, &normal_mask, watched_fds, &maxfd );
|
||||
watch_conf_file( kq, &conff_fd, confpath.c_str() );
|
||||
watch_conf_dir( kq, &confd_fd, confdir );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1215,6 +1293,7 @@ int main(int argc, char** argv) {
|
|||
|
||||
/* select() could have returned because received an exit signal */
|
||||
if (exit_signal > 0) {
|
||||
char *redone_confpath;
|
||||
switch(exit_signal) {
|
||||
case SIGHUP:
|
||||
for(auto i : id_command) {
|
||||
|
|
Loading…
Reference in New Issue