Skip to content

Commit

Permalink
sd-event: add sd_event_add_inotify_fd() call
Browse files Browse the repository at this point in the history
sd_event_add_inotify_fd() is like sd_event_add_inotify(), but takes an
fd to an inode instead of a path, and is hence a ton nicer.
  • Loading branch information
poettering committed Nov 9, 2021
1 parent 53baf2e commit e67d738
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 16 deletions.
4 changes: 3 additions & 1 deletion man/rules/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,9 @@ manpages = [
''],
['sd_event_add_inotify',
'3',
['sd_event_inotify_handler_t', 'sd_event_source_get_inotify_mask'],
['sd_event_add_inotify_fd',
'sd_event_inotify_handler_t',
'sd_event_source_get_inotify_mask'],
''],
['sd_event_add_io',
'3',
Expand Down
29 changes: 29 additions & 0 deletions man/sd_event_add_inotify.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

<refnamediv>
<refname>sd_event_add_inotify</refname>
<refname>sd_event_add_inotify_fd</refname>
<refname>sd_event_source_get_inotify_mask</refname>
<refname>sd_event_inotify_handler_t</refname>

Expand Down Expand Up @@ -46,6 +47,16 @@
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>

<funcprototype>
<funcdef>int <function>sd_event_add_inotify_fd</function></funcdef>
<paramdef>sd_event *<parameter>event</parameter></paramdef>
<paramdef>sd_event_source **<parameter>source</parameter></paramdef>
<paramdef>int <parameter>fd</parameter></paramdef>
<paramdef>uint32_t <parameter>mask</parameter></paramdef>
<paramdef>sd_event_inotify_handler_t <parameter>handler</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>

<funcprototype>
<funcdef>int <function>sd_event_source_get_inotify_mask</function></funcdef>
<paramdef>sd_event_source *<parameter>source</parameter></paramdef>
Expand All @@ -71,6 +82,11 @@
<citerefentry project='man-pages'><refentrytitle>inotify</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
further information.</para>

<para><function>sd_event_add_inotify_fd()</function> is identical to
<function>sd_event_add_inotify()</function>, except that it takes a file descriptor to an inode (possibly
an <constant>O_PATH</constant> one, but any other will do too) instead of a path in the file
system.</para>

<para>If multiple event sources are installed for the same inode the backing inotify watch descriptor is
automatically shared. The mask parameter may contain any flag defined by the inotify API, with the exception of
<constant>IN_MASK_ADD</constant>.</para>
Expand Down Expand Up @@ -157,6 +173,19 @@
<listitem><para>The passed event source is not an inotify process event source.</para></listitem>
</varlistentry>

<varlistentry>
<term><constant>-EBADF</constant></term>

<listitem><para>The passed file descriptor is not valid.</para></listitem>
</varlistentry>

<varlistentry>
<term><constant>-ENOSYS</constant></term>

<listitem><para><function>sd_event_add_inotify_fd()</function> was called without
<filename>/proc/</filename> mounted.</para></listitem>
</varlistentry>

</variablelist>
</refsect2>
</refsect1>
Expand Down
1 change: 1 addition & 0 deletions src/libsystemd/libsystemd.sym
Original file line number Diff line number Diff line change
Expand Up @@ -766,4 +766,5 @@ global:
LIBSYSTEMD_250 {
global:
sd_device_get_diskseq;
sd_event_add_inotify_fd;
} LIBSYSTEMD_249;
75 changes: 60 additions & 15 deletions src/libsystemd/sd-event/sd-event.c
Original file line number Diff line number Diff line change
Expand Up @@ -1989,24 +1989,25 @@ static int inotify_exit_callback(sd_event_source *s, const struct inotify_event
return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata));
}

_public_ int sd_event_add_inotify(
static int event_add_inotify_fd_internal(
sd_event *e,
sd_event_source **ret,
const char *path,
int fd,
bool donate,
uint32_t mask,
sd_event_inotify_handler_t callback,
void *userdata) {

_cleanup_close_ int donated_fd = donate ? fd : -1;
_cleanup_(source_freep) sd_event_source *s = NULL;
struct inotify_data *inotify_data = NULL;
struct inode_data *inode_data = NULL;
_cleanup_close_ int fd = -1;
_cleanup_(source_freep) sd_event_source *s = NULL;
struct stat st;
int r;

assert_return(e, -EINVAL);
assert_return(e = event_resolve(e), -ENOPKG);
assert_return(path, -EINVAL);
assert_return(fd >= 0, -EBADF);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);

Expand All @@ -2019,12 +2020,6 @@ _public_ int sd_event_add_inotify(
if (mask & IN_MASK_ADD)
return -EINVAL;

fd = open(path, O_PATH|O_CLOEXEC|
(mask & IN_ONLYDIR ? O_DIRECTORY : 0)|
(mask & IN_DONT_FOLLOW ? O_NOFOLLOW : 0));
if (fd < 0)
return -errno;

if (fstat(fd, &st) < 0)
return -errno;

Expand All @@ -2044,14 +2039,24 @@ _public_ int sd_event_add_inotify(

r = event_make_inode_data(e, inotify_data, st.st_dev, st.st_ino, &inode_data);
if (r < 0) {
event_free_inotify_data(e, inotify_data);
event_gc_inotify_data(e, inotify_data);
return r;
}

/* Keep the O_PATH fd around until the first iteration of the loop, so that we can still change the priority of
* the event source, until then, for which we need the original inode. */
if (inode_data->fd < 0) {
inode_data->fd = TAKE_FD(fd);
if (donated_fd >= 0)
inode_data->fd = TAKE_FD(donated_fd);
else {
inode_data->fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
if (inode_data->fd < 0) {
r = -errno;
event_gc_inode_data(e, inode_data);
return r;
}
}

LIST_PREPEND(to_close, e->inode_data_to_close, inode_data);
}

Expand All @@ -2064,15 +2069,55 @@ _public_ int sd_event_add_inotify(
if (r < 0)
return r;

(void) sd_event_source_set_description(s, path);

if (ret)
*ret = s;
TAKE_PTR(s);

return 0;
}

_public_ int sd_event_add_inotify_fd(
sd_event *e,
sd_event_source **ret,
int fd,
uint32_t mask,
sd_event_inotify_handler_t callback,
void *userdata) {

return event_add_inotify_fd_internal(e, ret, fd, /* donate= */ false, mask, callback, userdata);
}

_public_ int sd_event_add_inotify(
sd_event *e,
sd_event_source **ret,
const char *path,
uint32_t mask,
sd_event_inotify_handler_t callback,
void *userdata) {

sd_event_source *s;
int fd, r;

assert_return(path, -EINVAL);

fd = open(path, O_PATH|O_CLOEXEC|
(mask & IN_ONLYDIR ? O_DIRECTORY : 0)|
(mask & IN_DONT_FOLLOW ? O_NOFOLLOW : 0));
if (fd < 0)
return -errno;

r = event_add_inotify_fd_internal(e, &s, fd, /* donate= */ true, mask, callback, userdata);
if (r < 0)
return r;

(void) sd_event_source_set_description(s, path);

if (ret)
*ret = s;

return r;
}

static sd_event_source* event_source_free(sd_event_source *s) {
if (!s)
return NULL;
Expand Down
1 change: 1 addition & 0 deletions src/systemd/sd-event.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ int sd_event_add_signal(sd_event *e, sd_event_source **s, int sig, sd_event_sign
int sd_event_add_child(sd_event *e, sd_event_source **s, pid_t pid, int options, sd_event_child_handler_t callback, void *userdata);
int sd_event_add_child_pidfd(sd_event *e, sd_event_source **s, int pidfd, int options, sd_event_child_handler_t callback, void *userdata);
int sd_event_add_inotify(sd_event *e, sd_event_source **s, const char *path, uint32_t mask, sd_event_inotify_handler_t callback, void *userdata);
int sd_event_add_inotify_fd(sd_event *e, sd_event_source **s, int fd, uint32_t mask, sd_event_inotify_handler_t callback, void *userdata);
int sd_event_add_defer(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata);
int sd_event_add_post(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata);
int sd_event_add_exit(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata);
Expand Down

0 comments on commit e67d738

Please sign in to comment.