Skip to content

Commit eafa551

Browse files
committed
udevd: add support for S6/dinit-compatible readiness notification
Add support for signalling readiness (complete initialization) by sending a message via a file descriptor, provided by the parent process (such as a service manager). The mechanism is described here: https://skarnet.org/software/s6/notifywhenup.html
1 parent aa49f5c commit eafa551

3 files changed

Lines changed: 40 additions & 1 deletion

File tree

man/udevd.8

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ udevd \- Device event managing daemon
2525
.PP
2626
udevd
2727
.HP \w'\fB/sbin/udevd\fR\ 'u
28-
\fB/sbin/udevd\fR [\fB\-\-daemon\fR] [\fB\-\-debug\fR] [\fB\-\-children\-max=\fR] [\fB\-\-exec\-delay=\fR] [\fB\-\-event\-timeout=\fR] [\fB\-\-resolve\-names=early|late|never\fR] [\fB\-\-version\fR] [\fB\-\-help\fR]
28+
\fB/sbin/udevd\fR [\fB\-\-daemon\fR] [\fB\-\-debug\fR] [\fB\-\-ready\-notify=\fR] [\fB\-\-children\-max=\fR] [\fB\-\-exec\-delay=\fR] [\fB\-\-event\-timeout=\fR] [\fB\-\-resolve\-names=early|late|never\fR] [\fB\-\-version\fR] [\fB\-\-help\fR]
2929
.SH "DESCRIPTION"
3030
.PP
3131
\fBudevd\fR
@@ -47,6 +47,11 @@ Detach and run in the background\&.
4747
Print debug messages to standard error\&.
4848
.RE
4949
.PP
50+
\fB\-r\fR, \fB\-\-ready\-notify=\fR
51+
.RS 4
52+
Issue (S6/dinit compatible) readiness notification via a file descriptor\&. A short message followed by a newline character will be sent via the specified file descriptor (inherited from the parent process) when initialization is complete\&.
53+
.RE
54+
.PP
5055
\fB\-c\fR, \fB\-\-children\-max=\fR
5156
.RS 4
5257
Limit the number of events executed in parallel\&.

man/udevd.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
<command>/sbin/udevd</command>
3535
<arg><option>--daemon</option></arg>
3636
<arg><option>--debug</option></arg>
37+
<arg><option>--ready-notify=</option></arg>
3738
<arg><option>--children-max=</option></arg>
3839
<arg><option>--exec-delay=</option></arg>
3940
<arg><option>--event-timeout=</option></arg>
@@ -75,6 +76,16 @@
7576
</listitem>
7677
</varlistentry>
7778

79+
<varlistentry>
80+
<term><option>-r</option>, <option>--ready-notify=</option></term>
81+
<listitem>
82+
<para>Issue (S6/dinit compatible) readiness notification via a
83+
file descriptor. A short message followed by a newline character
84+
will be sent via the specified file descriptor (inherited from
85+
the parent process) when initialization is complete.</para>
86+
</listitem>
87+
</varlistentry>
88+
7889
<varlistentry>
7990
<term><option>-c</option>, <option>--children-max=</option></term>
8091
<listitem>

src/udev/udevd.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ static int worker_watch[2] = { -1, -1 };
6262
static int fd_signal = -1;
6363
static int fd_ep = -1;
6464
static int fd_inotify = -1;
65+
static int fd_ready = -1;
6566
static bool stop_exec_queue;
6667
static bool reload;
6768
static bool arg_debug = false;
@@ -76,6 +77,7 @@ static UDEV_LIST(event_list);
7677
Hashmap *workers;
7778
static struct udev_list properties_list;
7879
static bool udev_exit;
80+
static char udevd_ready_string[] = "udevd ready\n";
7981

8082
enum event_state {
8183
EVENT_UNDEF,
@@ -1036,6 +1038,7 @@ static void help(void) {
10361038
" -V --version Print version of the program\n"
10371039
" -d --daemon Detach and run in the background\n"
10381040
" -D --debug Enable debug output\n"
1041+
" -r --ready-notify=FD Notify readiness via file descriptor\n"
10391042
" -c --children-max=INT Set maximum number of workers\n"
10401043
" -e --exec-delay=SECONDS Seconds to wait before executing RUN=\n"
10411044
" -t --event-timeout=SECONDS Seconds to wait before terminating an event\n"
@@ -1048,6 +1051,7 @@ static int parse_argv(int argc, char *argv[]) {
10481051
static const struct option options[] = {
10491052
{ "daemon", no_argument, NULL, 'd' },
10501053
{ "debug", no_argument, NULL, 'D' },
1054+
{ "ready-notify", required_argument, NULL, 'r' },
10511055
{ "children-max", required_argument, NULL, 'c' },
10521056
{ "exec-delay", required_argument, NULL, 'e' },
10531057
{ "event-timeout", required_argument, NULL, 't' },
@@ -1104,6 +1108,11 @@ static int parse_argv(int argc, char *argv[]) {
11041108
return 0;
11051109
}
11061110
break;
1111+
case 'r':
1112+
r = safe_atou(optarg, &fd_ready);
1113+
if (r < 0)
1114+
log_warning("Invalid --ready-notify ignored: %s", optarg);
1115+
break;
11071116
case 'h':
11081117
help();
11091118
return 0;
@@ -1372,6 +1381,20 @@ int main(int argc, char *argv[]) {
13721381
goto exit;
13731382
}
13741383

1384+
if (fd_ready) {
1385+
size_t to_write = sizeof(udevd_ready_string) - 1;
1386+
char *wptr = udevd_ready_string;
1387+
do {
1388+
int r = write(fd_ready, wptr, to_write);
1389+
if (r < 0) {
1390+
log_error_errno(errno, "failed to write to readiness fd: %m");
1391+
break;
1392+
}
1393+
to_write -= r;
1394+
wptr += r;
1395+
} while (to_write > 0);
1396+
}
1397+
13751398
for (;;) {
13761399
static usec_t last_usec;
13771400
struct epoll_event ev[8];

0 commit comments

Comments
 (0)