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;
}
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) {
/* 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

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_and_warn(int fd, const char *pathname, uint32_t mask);
enum {
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)
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) {
log_error_errno(errno, "Failed to watch \"/run/systemd/ask-password\": %m");
r = inotify_add_watch_and_warn(m->ask_password_inotify_fd,
"/run/systemd/ask-password",
IN_CREATE|IN_DELETE|IN_MOVE);
if (r < 0) {
manager_close_ask_password(m);
return -errno;
return r;
}
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;
}
r = log_warning_errno(errno, "Failed to add watch on %s: %s", s->path, errno == ENOSPC ? "too many watches" : strerror_safe(r));
if (cut)
*cut = tmp;
goto fail;
} else {
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;
/* This second call to inotify_add_watch() should fail like the previous
* one and is done for logging the error in a comprehensive way. */
r = inotify_add_watch_and_warn(s->inotify_fd, s->path, flags);
if (r < 0) {
if (cut)
*cut = tmp;
goto fail;
}
/* 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)

View File

@ -225,9 +225,9 @@ static int run(int argc, char * argv[]) {
if (r < 0)
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)
return log_error_errno(errno, "Failed to watch /run/systemd/: %m");
return r;
state.run_systemd_wd = r;

View File

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