fs-util: introduce inotify_add_watch_and_warn() helper

The default message for ENOSPC is very misleading: it says that the disk is
filled, but in fact the inotify watch limit is the problem.

So let's introduce and use a wrapper that simply calls inotify_add_watch(2) and
which fixes the error message up in case ENOSPC is returned.
This commit is contained in:
Franck Bui 2019-09-17 11:16:52 +02:00
parent 5461cdebfa
commit 27c3112dcb
6 changed files with 49 additions and 29 deletions

View File

@ -660,6 +660,21 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
return r; return r;
} }
int inotify_add_watch_and_warn(int fd, const char *pathname, uint32_t mask) {
if (inotify_add_watch(fd, pathname, mask) < 0) {
const char *reason;
if (errno == ENOSPC)
reason = "inotify watch limit reached";
else
reason = strerror_safe(errno);
return log_error_errno(errno, "Failed to add a watch for %s: %s", pathname, reason);
}
return 0;
}
static bool unsafe_transition(const struct stat *a, const struct stat *b) { static bool unsafe_transition(const struct stat *a, const struct stat *b) {
/* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to /* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to
* privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files * privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files

View File

@ -72,6 +72,7 @@ union inotify_event_buffer {
}; };
int inotify_add_watch_fd(int fd, int what, uint32_t mask); int inotify_add_watch_fd(int fd, int what, uint32_t mask);
int inotify_add_watch_and_warn(int fd, const char *pathname, uint32_t mask);
enum { enum {
CHASE_PREFIX_ROOT = 1 << 0, /* The specified path will be prefixed by the specified root before beginning the iteration */ CHASE_PREFIX_ROOT = 1 << 0, /* The specified path will be prefixed by the specified root before beginning the iteration */

View File

@ -295,10 +295,12 @@ static int manager_check_ask_password(Manager *m) {
if (m->ask_password_inotify_fd < 0) if (m->ask_password_inotify_fd < 0)
return log_error_errno(errno, "Failed to create inotify object: %m"); return log_error_errno(errno, "Failed to create inotify object: %m");
if (inotify_add_watch(m->ask_password_inotify_fd, "/run/systemd/ask-password", IN_CREATE|IN_DELETE|IN_MOVE) < 0) { r = inotify_add_watch_and_warn(m->ask_password_inotify_fd,
log_error_errno(errno, "Failed to watch \"/run/systemd/ask-password\": %m"); "/run/systemd/ask-password",
IN_CREATE|IN_DELETE|IN_MOVE);
if (r < 0) {
manager_close_ask_password(m); manager_close_ask_password(m);
return -errno; return r;
} }
r = sd_event_add_io(m->event, &m->ask_password_event_source, r = sd_event_add_io(m->event, &m->ask_password_event_source,

View File

@ -89,24 +89,29 @@ int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler) {
break; break;
} }
r = log_warning_errno(errno, "Failed to add watch on %s: %s", s->path, errno == ENOSPC ? "too many watches" : strerror_safe(r)); /* This second call to inotify_add_watch() should fail like the previous
if (cut) * one and is done for logging the error in a comprehensive way. */
*cut = tmp; r = inotify_add_watch_and_warn(s->inotify_fd, s->path, flags);
goto fail; if (r < 0) {
} else { if (cut)
exists = true; *cut = tmp;
goto fail;
/* Path exists, we don't need to watch parent too closely. */
if (oldslash) {
char *cut2 = oldslash + (oldslash == s->path);
char tmp2 = *cut2;
*cut2 = '\0';
(void) inotify_add_watch(s->inotify_fd, s->path, IN_MOVE_SELF);
/* Error is ignored, the worst can happen is we get spurious events. */
*cut2 = tmp2;
} }
/* Hmm, we succeeded in adding the watch this time... let's continue. */
}
exists = true;
/* Path exists, we don't need to watch parent too closely. */
if (oldslash) {
char *cut2 = oldslash + (oldslash == s->path);
char tmp2 = *cut2;
*cut2 = '\0';
(void) inotify_add_watch(s->inotify_fd, s->path, IN_MOVE_SELF);
/* Error is ignored, the worst can happen is we get spurious events. */
*cut2 = tmp2;
} }
if (cut) if (cut)

View File

@ -225,9 +225,9 @@ static int run(int argc, char * argv[]) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to create notify event source: %m"); return log_error_errno(r, "Failed to create notify event source: %m");
r = inotify_add_watch(state.inotify_fd, "/run/systemd/", IN_CREATE); r = inotify_add_watch_and_warn(state.inotify_fd, "/run/systemd/", IN_CREATE);
if (r < 0) if (r < 0)
return log_error_errno(errno, "Failed to watch /run/systemd/: %m"); return r;
state.run_systemd_wd = r; state.run_systemd_wd = r;

View File

@ -11,7 +11,6 @@
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
#include <sys/inotify.h>
#include <sys/prctl.h> #include <sys/prctl.h>
#include <sys/signalfd.h> #include <sys/signalfd.h>
#include <sys/socket.h> #include <sys/socket.h>
@ -29,6 +28,7 @@
#include "exit-status.h" #include "exit-status.h"
#include "fd-util.h" #include "fd-util.h"
#include "fileio.h" #include "fileio.h"
#include "fs-util.h"
#include "hashmap.h" #include "hashmap.h"
#include "io-util.h" #include "io-util.h"
#include "macro.h" #include "macro.h"
@ -510,12 +510,9 @@ static int process_and_watch_password_files(void) {
if (notify < 0) if (notify < 0)
return log_error_errno(errno, "Failed to allocate directory watch: %m"); return log_error_errno(errno, "Failed to allocate directory watch: %m");
if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_CLOSE_WRITE|IN_MOVED_TO) < 0) { r = inotify_add_watch_and_warn(notify, "/run/systemd/ask-password", IN_CLOSE_WRITE|IN_MOVED_TO);
if (errno == ENOSPC) if (r < 0)
return log_error_errno(errno, "Failed to add /run/systemd/ask-password to directory watch: inotify watch limit reached"); return r;
else
return log_error_errno(errno, "Failed to add /run/systemd/ask-password to directory watch: %m");
}
assert_se(sigemptyset(&mask) >= 0); assert_se(sigemptyset(&mask) >= 0);
assert_se(sigset_add_many(&mask, SIGINT, SIGTERM, -1) >= 0); assert_se(sigset_add_many(&mask, SIGINT, SIGTERM, -1) >= 0);