]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
varlinkctl: add --timeout= switch to tweak time-out behaviour
authorLennart Poettering <lennart@poettering.net>
Fri, 6 Sep 2024 19:44:51 +0000 (21:44 +0200)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 6 Sep 2024 22:35:39 +0000 (07:35 +0900)
Fixes: #33772
man/varlinkctl.xml
src/varlinkctl/varlinkctl.c

index e936be2f43f299ddd48389190fe0bd8bafe10675..2a4bb160725d021c0733e90b6136e53cb084ca42 100644 (file)
       <varlistentry>
         <term><option>--more</option></term>
 
-        <listitem><para>When used with <command>call</command>: expect multiple method replies. If this flag is
-        set the method call is sent with the <constant>more</constant> flag set, which tells the service to
-        generate multiple replies, if needed. The command remains running until the service sends a reply
-        message that indicates it is the last in the series. This flag should be set only for method calls
-        that support this mechanism.</para>
+        <listitem><para>When used with <command>call</command>: expect multiple method replies. If this flag
+        is set the method call is sent with the <constant>more</constant> flag set, which tells the service
+        to generate multiple replies, if needed. The command remains running until the service sends a reply
+        message that indicates it is the last in the series (or if the configured time-out is reached, see
+        below). This flag should be set only for method calls that support this mechanism.</para>
 
         <para>If this mode is enabled output is automatically switched to JSON-SEQ mode, so that individual
         reply objects can be easily discerned.</para>
 
+        <para>This switch has no effect on the method call time-out applied by default: regardless if
+        <option>--more</option> is specified or not, the default time-out will be 45s. Use
+        <option>--timeout=</option> (see below) to change or disable the time-out. When invoking a method
+        call that continously returns updates it is typically desirable to disable the time-out with
+        <option>--timeout=infinity</option>. On the other hand, when invoking a <option>--more</option>
+        method call for the purpose of enumerating objects (which likely will complete quickly) it is
+        typically beneficial to leave the time-out logic enabled, for robustness reasons.</para>
+
         <xi:include href="version-info.xml" xpointer="v255"/></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>-E</option></term>
+
+        <listitem><para>A shortcut for <option>--more --timeout=infinity</option>. This switch is
+        useful for method calls that implement subscription to a continious stream of updates.</para>
+
+        <xi:include href="version-info.xml" xpointer="v257"/></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>--collect</option></term>
 
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--timeout=</option></term>
+
+        <listitem>
+          <para>Expects a time-out in seconds as parameter. By default a time-out of 45s is enforced. To turn
+          off the time-out specify <literal>infinity</literal> or an empty string.</para>
+
+          <xi:include href="version-info.xml" xpointer="v257"/>
+        </listitem>
+      </varlistentry>
+
       <xi:include href="standard-options.xml" xpointer="no-pager" />
       <xi:include href="standard-options.xml" xpointer="help" />
       <xi:include href="standard-options.xml" xpointer="version" />
index e99ea34964119dbdb9b5f6fd3050191a96254640..885c1b1dc2b08151d5f0b9c0f67b7c59b709544f 100644 (file)
@@ -26,6 +26,7 @@ static sd_varlink_method_flags_t arg_method_flags = 0;
 static bool arg_collect = false;
 static bool arg_quiet = false;
 static char **arg_graceful = NULL;
+static usec_t arg_timeout = 0;
 
 STATIC_DESTRUCTOR_REGISTER(arg_graceful, strv_freep);
 
@@ -65,6 +66,8 @@ static int help(void) {
                "  -j                     Same as --json=pretty on tty, --json=short otherwise\n"
                "  -q --quiet             Do not output method reply\n"
                "     --graceful=ERROR    Treat specified Varlink error as success\n"
+               "     --timeout=SECS      Maximum time to wait for method call completion\n"
+               "  -E                     Short for --more --timeout=infinity\n"
                "\nSee the %2$s for details.\n",
                program_invocation_short_name,
                link,
@@ -90,6 +93,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_JSON,
                 ARG_COLLECT,
                 ARG_GRACEFUL,
+                ARG_TIMEOUT,
         };
 
         static const struct option options[] = {
@@ -102,6 +106,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "collect",  no_argument,       NULL, ARG_COLLECT  },
                 { "quiet",    no_argument,       NULL, 'q'          },
                 { "graceful", required_argument, NULL, ARG_GRACEFUL },
+                { "timeout",  required_argument, NULL, ARG_TIMEOUT  },
                 {},
         };
 
@@ -110,7 +115,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "hjq", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "hjqE", options, NULL)) >= 0)
 
                 switch (c) {
 
@@ -124,6 +129,10 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_pager_flags |= PAGER_DISABLE;
                         break;
 
+                case 'E':
+                        arg_timeout = USEC_INFINITY;
+                        _fallthrough_;
+
                 case ARG_MORE:
                         arg_method_flags = (arg_method_flags & ~SD_VARLINK_METHOD_ONEWAY) | SD_VARLINK_METHOD_MORE;
                         break;
@@ -163,6 +172,21 @@ static int parse_argv(int argc, char *argv[]) {
 
                         break;
 
+                case ARG_TIMEOUT:
+                        if (isempty(optarg)) {
+                                arg_timeout = USEC_INFINITY;
+                                break;
+                        }
+
+                        r = parse_sec(optarg, &arg_timeout);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to parse --timeout= parameter '%s': %m", optarg);
+
+                        if (arg_timeout == 0)
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Timeout cannot be zero.");
+
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -185,6 +209,8 @@ static int varlink_connect_auto(sd_varlink **ret, const char *where) {
         assert(ret);
         assert(where);
 
+        _cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
+
         if (STARTSWITH_SET(where, "/", "./")) { /* If the string starts with a slash or dot slash we use it as a file system path */
                 _cleanup_close_ int fd = -EBADF;
                 struct stat st;
@@ -196,32 +222,35 @@ static int varlink_connect_auto(sd_varlink **ret, const char *where) {
                 if (fstat(fd, &st) < 0)
                         return log_error_errno(errno, "Failed to stat '%s': %m", where);
 
-                /* Is this a socket in the fs? Then connect() to it. */
                 if (S_ISSOCK(st.st_mode)) {
-                        r = sd_varlink_connect_address(ret, FORMAT_PROC_FD_PATH(fd));
+                        /* Is this a socket in the fs? Then connect() to it. */
+
+                        r = sd_varlink_connect_address(&vl, FORMAT_PROC_FD_PATH(fd));
                         if (r < 0)
                                 return log_error_errno(r, "Failed to connect to '%s': %m", where);
 
-                        return 0;
-                }
+                } else if (S_ISREG(st.st_mode) && (st.st_mode & 0111)) {
+                        /* Is this an executable binary? Then fork it off. */
 
-                /* Is this an executable binary? Then fork it off. */
-                if (S_ISREG(st.st_mode) && (st.st_mode & 0111)) {
-                        r = sd_varlink_connect_exec(ret, where, STRV_MAKE(where)); /* Ideally we'd use FORMAT_PROC_FD_PATH(fd) here too, but that breaks the #! logic */
+                        r = sd_varlink_connect_exec(&vl, where, STRV_MAKE(where)); /* Ideally we'd use FORMAT_PROC_FD_PATH(fd) here too, but that breaks the #! logic */
                         if (r < 0)
                                 return log_error_errno(r, "Failed to spawn '%s' process: %m", where);
-
-                        return 0;
-                }
-
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unrecognized path '%s' is neither an AF_UNIX socket, nor an executable binary.", where);
+                } else
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unrecognized path '%s' is neither an AF_UNIX socket, nor an executable binary.", where);
+        } else {
+                /* Otherwise assume this is an URL */
+                r = sd_varlink_connect_url(&vl, where);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to connect to URL '%s': %m", where);
         }
 
-        /* Otherwise assume this is an URL */
-        r = sd_varlink_connect_url(ret, where);
-        if (r < 0)
-                return log_error_errno(r, "Failed to connect to URL '%s': %m", where);
+        if (arg_timeout != 0) {
+                r = sd_varlink_set_relative_timeout(vl, arg_timeout);
+                if (r < 0)
+                        log_error_errno(r, "Failed to set Varlink timeout: %m");
+        }
 
+        *ret = TAKE_PTR(vl);
         return 0;
 }