Skip to content

Commit 64ce768

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 64ce768

3 files changed

Lines changed: 38 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: 21 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;
@@ -1036,6 +1037,7 @@ static void help(void) {
10361037
" -V --version Print version of the program\n"
10371038
" -d --daemon Detach and run in the background\n"
10381039
" -D --debug Enable debug output\n"
1040+
" -r --ready-notify=FD Notify readiness via file descriptor\n"
10391041
" -c --children-max=INT Set maximum number of workers\n"
10401042
" -e --exec-delay=SECONDS Seconds to wait before executing RUN=\n"
10411043
" -t --event-timeout=SECONDS Seconds to wait before terminating an event\n"
@@ -1048,6 +1050,7 @@ static int parse_argv(int argc, char *argv[]) {
10481050
static const struct option options[] = {
10491051
{ "daemon", no_argument, NULL, 'd' },
10501052
{ "debug", no_argument, NULL, 'D' },
1053+
{ "ready-notify", required_argument, NULL, 'r' },
10511054
{ "children-max", required_argument, NULL, 'c' },
10521055
{ "exec-delay", required_argument, NULL, 'e' },
10531056
{ "event-timeout", required_argument, NULL, 't' },
@@ -1104,6 +1107,11 @@ static int parse_argv(int argc, char *argv[]) {
11041107
return 0;
11051108
}
11061109
break;
1110+
case 'r':
1111+
r = safe_atou(optarg, &fd_ready);
1112+
if (r < 0)
1113+
log_warning("Invalid --ready-notify ignored: %s", optarg);
1114+
break;
11071115
case 'h':
11081116
help();
11091117
return 0;
@@ -1372,6 +1380,19 @@ int main(int argc, char *argv[]) {
13721380
goto exit;
13731381
}
13741382

1383+
if (fd_ready) {
1384+
char ready_string[] = "udevd ready\n";
1385+
size_t to_write = sizeof(ready_string) - 1;
1386+
do {
1387+
int r = write(fd_ready, ready_string, to_write);
1388+
if (r < 0) {
1389+
log_error_errno(errno, "failed to write to readiness fd: %m");
1390+
break;
1391+
}
1392+
to_write -= r;
1393+
} while (to_write > 0);
1394+
}
1395+
13751396
for (;;) {
13761397
static usec_t last_usec;
13771398
struct epoll_event ev[8];

0 commit comments

Comments
 (0)