]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
socket-activate: add --now option
authorDaniel Foster <daniel@amesite.me>
Mon, 26 May 2025 15:08:38 +0000 (01:08 +1000)
committerDaniel Foster <daniel@amesite.me>
Tue, 10 Jun 2025 03:38:33 +0000 (13:38 +1000)
Add a --now option that starts the program instantly, instead of waiting for a
connection on the socket. This is useful, for instance, when developing:

Say I have a Rust, socket-activated web service. I can test it with:
systemd-socket-activate -l 8080 --fdname=http cargo run

However this delays running the service (which potentially involves compilation)
to when I try to connect to it, which wastes time. Since it delays compilation,
I also don't see any warning or errors in the code until it gets a connection
either.

The name's now a bit of a misnomer, since starting the service immediately isn't
really socket activation, but oh well ¯\_(ツ)_/⁻

man/systemd-socket-activate.xml
src/socket-activate/socket-activate.c

index 4c29fa2c66568b6a4a8e95cc728e1833e2e9087e..09f0d5cad609804af966d282755644b5d16fa2f9 100644 (file)
@@ -72,7 +72,7 @@
         <term><option>--accept</option></term>
 
         <listitem><para>Launch an instance of the service program for each connection and pass the connection
-        socket.</para>
+        socket. May not be combined with <option>--now</option>.</para>
 
         <xi:include href="version-info.xml" xpointer="v230"/></listitem>
       </varlistentry>
         <xi:include href="version-info.xml" xpointer="v230"/></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--now</option></term>
+
+        <listitem><para>Start the service program instantly, instead of waiting for a connection on the
+        socket(s). May not be combined with <option>--accept</option>.
+        </para>
+
+        <xi:include href="version-info.xml" xpointer="v258"/></listitem>
+      </varlistentry>
+
       <xi:include href="standard-options.xml" xpointer="help" />
       <xi:include href="standard-options.xml" xpointer="version" />
     </variablelist>
index e62b762c950478639592d48f83ead0e9efc89faf..a80080b9cd060a933426896a91a28b8233cce9c3 100644 (file)
@@ -30,6 +30,7 @@ static int arg_socket_type = SOCK_STREAM;
 static char **arg_setenv = NULL;
 static char **arg_fdnames = NULL;
 static bool arg_inetd = false;
+static bool arg_now = false;
 
 static int add_epoll(int epoll_fd, int fd) {
         struct epoll_event ev = {
@@ -117,9 +118,11 @@ static int open_sockets(int *ret_epoll_fd) {
                         log_warning("More than one fd name specified with --accept.");
         }
 
-        epoll_fd = epoll_create1(EPOLL_CLOEXEC);
-        if (epoll_fd < 0)
-                return log_error_errno(errno, "Failed to create epoll object: %m");
+        if (!arg_now) {
+                epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+                if (epoll_fd < 0)
+                        return log_error_errno(errno, "Failed to create epoll object: %m");
+        }
 
         for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + count; fd++) {
                 _cleanup_free_ char *name = NULL;
@@ -127,9 +130,11 @@ static int open_sockets(int *ret_epoll_fd) {
                 getsockname_pretty(fd, &name);
                 log_info("Listening on %s as %i.", strna(name), fd);
 
-                r = add_epoll(epoll_fd, fd);
-                if (r < 0)
-                        return r;
+                if (epoll_fd >= 0) {
+                        r = add_epoll(epoll_fd, fd);
+                        if (r < 0)
+                                return r;
+                }
         }
 
         *ret_epoll_fd = TAKE_FD(epoll_fd);
@@ -323,6 +328,7 @@ static int help(void) {
                "  -E --setenv=NAME[=VALUE]   Pass an environment variable to children\n"
                "     --fdname=NAME[:NAME...] Specify names for file descriptors\n"
                "     --inetd                 Enable inetd file descriptor passing protocol\n"
+               "     --now                   Start instantly instead of waiting for connection\n"
                "\nNote: file descriptors from sd_listen_fds() will be passed through.\n"
                "\nSee the %s for details.\n",
                program_invocation_short_name,
@@ -339,6 +345,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_FDNAME,
                 ARG_SEQPACKET,
                 ARG_INETD,
+                ARG_NOW,
         };
 
         static const struct option options[] = {
@@ -352,6 +359,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "environment", required_argument, NULL, 'E'           }, /* legacy alias */
                 { "fdname",      required_argument, NULL, ARG_FDNAME    },
                 { "inetd",       no_argument,       NULL, ARG_INETD     },
+                { "now",         no_argument,       NULL, ARG_NOW       },
                 {}
         };
 
@@ -432,6 +440,10 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_inetd = true;
                         break;
 
+                case ARG_NOW:
+                        arg_now = true;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -449,6 +461,10 @@ static int parse_argv(int argc, char *argv[]) {
                                        "Datagram sockets do not accept connections. "
                                        "The --datagram and --accept options may not be combined.");
 
+        if (arg_accept && arg_now)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "--now cannot be used in conjunction with --accept.");
+
         if (arg_fdnames && arg_inetd)
                 log_warning("--fdname= has no effect with --inetd present.");
 
@@ -493,14 +509,16 @@ static int run(int argc, char **argv) {
         for (;;) {
                 struct epoll_event event;
 
-                if (epoll_wait(epoll_fd, &event, 1, -1) < 0) {
-                        if (errno == EINTR)
-                                continue;
+                if (epoll_fd >= 0) {
+                        if (epoll_wait(epoll_fd, &event, 1, -1) < 0) {
+                                if (errno == EINTR)
+                                        continue;
 
-                        return log_error_errno(errno, "epoll_wait() failed: %m");
-                }
+                                return log_error_errno(errno, "epoll_wait() failed: %m");
+                        }
 
-                log_info("Communication attempt on fd %i.", event.data.fd);
+                        log_info("Communication attempt on fd %i.", event.data.fd);
+                }
 
                 if (!arg_accept)
                         return exec_process(exec_argv, SD_LISTEN_FDS_START, (size_t) n);