run: add support to create transient path and socket unit
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 18 Dec 2017 14:46:45 +0000 (23:46 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 23 Dec 2017 09:48:27 +0000 (18:48 +0900)
src/run/run.c

index 510b6ab..b018d15 100644 (file)
@@ -69,6 +69,8 @@ static enum {
         ARG_STDIO_DIRECT,    /* Directly pass our stdin/stdout/stderr to the activated service, useful for usage in shell pipelines, requested by --pipe */
         ARG_STDIO_AUTO,      /* If --pipe and --pty are used together we use --pty when invoked on a TTY, and --pipe otherwise */
 } arg_stdio = ARG_STDIO_NONE;
+static char **arg_path_property = NULL;
+static char **arg_socket_property = NULL;
 static char **arg_timer_property = NULL;
 static bool with_timer = false;
 static bool arg_quiet = false;
@@ -102,6 +104,10 @@ static void help(void) {
                "  -P --pipe                       Pass STDIN/STDOUT/STDERR directly to service\n"
                "  -q --quiet                      Suppress information messages during runtime\n"
                "  -G --collect                    Unload unit after it ran, even when failed\n\n"
+               "Path options:\n"
+               "     --path-property=NAME=VALUE   Set path unit property\n\n"
+               "Socket options:\n"
+               "     --socket-property=NAME=VALUE Set socket unit property\n\n"
                "Timer options:\n"
                "     --on-active=SECONDS          Run after SECONDS delay\n"
                "     --on-boot=SECONDS            Run SECONDS after machine was booted up\n"
@@ -153,6 +159,8 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_ON_UNIT_INACTIVE,
                 ARG_ON_CALENDAR,
                 ARG_TIMER_PROPERTY,
+                ARG_PATH_PROPERTY,
+                ARG_SOCKET_PROPERTY,
                 ARG_NO_BLOCK,
                 ARG_NO_ASK_PASSWORD,
                 ARG_WAIT,
@@ -189,12 +197,15 @@ static int parse_argv(int argc, char *argv[]) {
                 { "on-unit-inactive",  required_argument, NULL, ARG_ON_UNIT_INACTIVE },
                 { "on-calendar",       required_argument, NULL, ARG_ON_CALENDAR      },
                 { "timer-property",    required_argument, NULL, ARG_TIMER_PROPERTY   },
+                { "path-property",     required_argument, NULL, ARG_PATH_PROPERTY    },
+                { "socket-property",   required_argument, NULL, ARG_SOCKET_PROPERTY  },
                 { "no-block",          no_argument,       NULL, ARG_NO_BLOCK         },
                 { "no-ask-password",   no_argument,       NULL, ARG_NO_ASK_PASSWORD  },
                 { "collect",           no_argument,       NULL, 'G'                  },
                 {},
         };
 
+        bool with_trigger = false;
         int r, c;
 
         assert(argc >= 0);
@@ -369,6 +380,20 @@ static int parse_argv(int argc, char *argv[]) {
                                 !!startswith(optarg, "OnCalendar=");
                         break;
 
+                case ARG_PATH_PROPERTY:
+
+                        if (strv_extend(&arg_path_property, optarg) < 0)
+                                return log_oom();
+
+                        break;
+
+                case ARG_SOCKET_PROPERTY:
+
+                        if (strv_extend(&arg_socket_property, optarg) < 0)
+                                return log_oom();
+
+                        break;
+
                 case ARG_NO_BLOCK:
                         arg_no_block = true;
                         break;
@@ -388,6 +413,13 @@ static int parse_argv(int argc, char *argv[]) {
                         assert_not_reached("Unhandled option");
                 }
 
+        with_trigger = !!arg_path_property || !!arg_socket_property || with_timer;
+
+        /* currently, only single trigger (path, socket, timer) unit can be created simultaneously */
+        if ((int) !!arg_path_property + (int) !!arg_socket_property + (int) with_timer > 1) {
+                log_error("Only single trigger (path, socket, timer) unit can be created.");
+                return -EINVAL;
+        }
 
         if (arg_stdio == ARG_STDIO_AUTO) {
                 /* If we both --pty and --pipe are specified we'll automatically pick --pty if we are connected fully
@@ -398,7 +430,7 @@ static int parse_argv(int argc, char *argv[]) {
                         ARG_STDIO_DIRECT;
         }
 
-        if ((optind >= argc) && (!arg_unit || !with_timer)) {
+        if ((optind >= argc) && (!arg_unit || !with_trigger)) {
                 log_error("Command line to execute required.");
                 return -EINVAL;
         }
@@ -418,7 +450,7 @@ static int parse_argv(int argc, char *argv[]) {
                 return -EINVAL;
         }
 
-        if (arg_stdio != ARG_STDIO_NONE && (with_timer || arg_scope)) {
+        if (arg_stdio != ARG_STDIO_NONE && (with_trigger || arg_scope)) {
                 log_error("--pty/--pipe is not compatible in timer or --scope mode.");
                 return -EINVAL;
         }
@@ -433,8 +465,8 @@ static int parse_argv(int argc, char *argv[]) {
                 return -EINVAL;
         }
 
-        if (arg_scope && with_timer) {
-                log_error("Timer options are not supported in --scope mode.");
+        if (arg_scope && with_trigger) {
+                log_error("Path, socket or timer options are not supported in --scope mode.");
                 return -EINVAL;
         }
 
@@ -449,8 +481,8 @@ static int parse_argv(int argc, char *argv[]) {
                         return -EINVAL;
                 }
 
-                if (with_timer) {
-                        log_error("--wait may not be combined with timer operations.");
+                if (with_trigger) {
+                        log_error("--wait may not be combined with path, socket or timer operations.");
                         return -EINVAL;
                 }
 
@@ -1283,14 +1315,15 @@ static int start_transient_scope(
         return log_error_errno(errno, "Failed to execute: %m");
 }
 
-static int start_transient_timer(
+static int start_transient_trigger(
                 sd_bus *bus,
-                char **argv) {
+                char **argv,
+                const char *suffix) {
 
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
         _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
-        _cleanup_free_ char *timer = NULL, *service = NULL;
+        _cleanup_free_ char *trigger = NULL, *service = NULL;
         const char *object = NULL;
         int r;
 
@@ -1309,17 +1342,17 @@ static int start_transient_timer(
                         if (!service)
                                 return log_oom();
 
-                        r = unit_name_change_suffix(service, ".timer", &timer);
+                        r = unit_name_change_suffix(service, suffix, &trigger);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to change unit suffix: %m");
                         break;
 
                 case UNIT_TIMER:
-                        timer = strdup(arg_unit);
-                        if (!timer)
+                        trigger = strdup(arg_unit);
+                        if (!trigger)
                                 return log_oom();
 
-                        r = unit_name_change_suffix(timer, ".service", &service);
+                        r = unit_name_change_suffix(trigger, ".service", &service);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to change unit suffix: %m");
                         break;
@@ -1329,7 +1362,7 @@ static int start_transient_timer(
                         if (r < 0)
                                 return log_error_errno(r, "Failed to mangle unit name: %m");
 
-                        r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".timer", &timer);
+                        r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, suffix, &trigger);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to mangle unit name: %m");
 
@@ -1340,7 +1373,7 @@ static int start_transient_timer(
                 if (r < 0)
                         return r;
 
-                r = unit_name_change_suffix(service, ".timer", &timer);
+                r = unit_name_change_suffix(service, suffix, &trigger);
                 if (r < 0)
                         return log_error_errno(r, "Failed to change unit suffix: %m");
         }
@@ -1360,7 +1393,7 @@ static int start_transient_timer(
                 return bus_log_create_error(r);
 
         /* Name and Mode */
-        r = sd_bus_message_append(m, "ss", timer, "fail");
+        r = sd_bus_message_append(m, "ss", trigger, "fail");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -1369,7 +1402,14 @@ static int start_transient_timer(
         if (r < 0)
                 return bus_log_create_error(r);
 
-        r = transient_timer_set_properties(m);
+        if (streq(suffix, ".path"))
+                r = transient_unit_set_properties(m, UNIT_PATH, arg_path_property);
+        else if (streq(suffix, ".socket"))
+                r = transient_unit_set_properties(m, UNIT_SOCKET, arg_socket_property);
+        else if (streq(suffix, ".timer"))
+                r = transient_timer_set_properties(m);
+        else
+                assert_not_reached("Invalid suffix");
         if (r < 0)
                 return r;
 
@@ -1415,7 +1455,7 @@ static int start_transient_timer(
 
         r = sd_bus_call(bus, m, 0, &error, &reply);
         if (r < 0) {
-                log_error("Failed to start transient timer unit: %s", bus_error_message(&error, -r));
+                log_error("Failed to start transient %s unit: %s", suffix + 1, bus_error_message(&error, -r));
                 return r;
         }
 
@@ -1428,7 +1468,7 @@ static int start_transient_timer(
                 return r;
 
         if (!arg_quiet) {
-                log_info("Running timer as unit: %s", timer);
+                log_info("Running %s as unit: %s", suffix + 1, trigger);
                 if (argv[0])
                         log_info("Will run service as unit: %s", service);
         }
@@ -1489,14 +1529,20 @@ int main(int argc, char* argv[]) {
 
         if (arg_scope)
                 r = start_transient_scope(bus, argv + optind);
+        else if (arg_path_property)
+                r = start_transient_trigger(bus, argv + optind, ".path");
+        else if (arg_socket_property)
+                r = start_transient_trigger(bus, argv + optind, ".socket");
         else if (with_timer)
-                r = start_transient_timer(bus, argv + optind);
+                r = start_transient_trigger(bus, argv + optind, ".timer");
         else
                 r = start_transient_service(bus, argv + optind, &retval);
 
 finish:
         strv_free(arg_environment);
         strv_free(arg_property);
+        strv_free(arg_path_property);
+        strv_free(arg_socket_property);
         strv_free(arg_timer_property);
 
         return r < 0 ? EXIT_FAILURE : retval;