diff --git a/man/udevd.8 b/man/udevd.8
index e5008d44b..dc5528373 100644
--- a/man/udevd.8
+++ b/man/udevd.8
@@ -25,7 +25,7 @@ udevd \- Device event managing daemon
.PP
udevd
.HP \w'\fB/sbin/udevd\fR\ 'u
-\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]
+\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]
.SH "DESCRIPTION"
.PP
\fBudevd\fR
@@ -47,6 +47,11 @@ Detach and run in the background\&.
Print debug messages to standard error\&.
.RE
.PP
+\fB\-r\fR, \fB\-\-ready\-notify=\fR
+.RS 4
+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\&.
+.RE
+.PP
\fB\-c\fR, \fB\-\-children\-max=\fR
.RS 4
Limit the number of events executed in parallel\&.
diff --git a/man/udevd.xml b/man/udevd.xml
index b13f74d70..3de99d2d2 100644
--- a/man/udevd.xml
+++ b/man/udevd.xml
@@ -34,6 +34,7 @@
/sbin/udevd
+
@@ -75,6 +76,16 @@
+
+ ,
+
+ 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.
+
+
+
,
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 2acf629f2..9bc6354b6 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -62,6 +62,7 @@ static int worker_watch[2] = { -1, -1 };
static int fd_signal = -1;
static int fd_ep = -1;
static int fd_inotify = -1;
+static int fd_ready = -1;
static bool stop_exec_queue;
static bool reload;
static bool arg_debug = false;
@@ -76,6 +77,7 @@ static UDEV_LIST(event_list);
Hashmap *workers;
static struct udev_list properties_list;
static bool udev_exit;
+static char udevd_ready_string[] = "udevd ready\n";
enum event_state {
EVENT_UNDEF,
@@ -1036,6 +1038,7 @@ static void help(void) {
" -V --version Print version of the program\n"
" -d --daemon Detach and run in the background\n"
" -D --debug Enable debug output\n"
+ " -r --ready-notify=FD Notify readiness via file descriptor\n"
" -c --children-max=INT Set maximum number of workers\n"
" -e --exec-delay=SECONDS Seconds to wait before executing RUN=\n"
" -t --event-timeout=SECONDS Seconds to wait before terminating an event\n"
@@ -1048,6 +1051,7 @@ static int parse_argv(int argc, char *argv[]) {
static const struct option options[] = {
{ "daemon", no_argument, NULL, 'd' },
{ "debug", no_argument, NULL, 'D' },
+ { "ready-notify", required_argument, NULL, 'r' },
{ "children-max", required_argument, NULL, 'c' },
{ "exec-delay", required_argument, NULL, 'e' },
{ "event-timeout", required_argument, NULL, 't' },
@@ -1104,6 +1108,11 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
}
break;
+ case 'r':
+ r = safe_atou(optarg, &fd_ready);
+ if (r < 0)
+ log_warning("Invalid --ready-notify ignored: %s", optarg);
+ break;
case 'h':
help();
return 0;
@@ -1372,6 +1381,20 @@ int main(int argc, char *argv[]) {
goto exit;
}
+ if (fd_ready != -1) {
+ size_t to_write = sizeof(udevd_ready_string) - 1;
+ char *wptr = udevd_ready_string;
+ do {
+ int r = write(fd_ready, wptr, to_write);
+ if (r < 0) {
+ log_error_errno(errno, "failed to write to readiness fd: %m");
+ break;
+ }
+ to_write -= r;
+ wptr += r;
+ } while (to_write > 0);
+ }
+
for (;;) {
static usec_t last_usec;
struct epoll_event ev[8];