]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/run/run.c
coccinelle: make use of SYNTHETIC_ERRNO
[thirdparty/systemd.git] / src / run / run.c
index 5d7441ac939105427ef024f5722322723d1313be..63f135db2fbfa641626a22f0789c5d9f4d5606b3 100644 (file)
@@ -1,22 +1,4 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
-/***
-  This file is part of systemd.
-
-  Copyright 2013 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
 
 #include <getopt.h>
 #include <stdio.h>
 #include "format-util.h"
 #include "parse-util.h"
 #include "path-util.h"
+#include "pretty-print.h"
 #include "process-util.h"
 #include "ptyfwd.h"
 #include "signal-util.h"
 #include "spawn-polkit-agent.h"
 #include "strv.h"
 #include "terminal-util.h"
+#include "unit-def.h"
 #include "unit-name.h"
 #include "user-util.h"
 
@@ -68,12 +52,21 @@ 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;
 static bool arg_aggressive_gc = false;
 
-static void help(void) {
+static int help(void) {
+        _cleanup_free_ char *link = NULL;
+        int r;
+
+        r = terminal_urlify_man("systemd-run", "1", &link);
+        if (r < 0)
+                return log_oom();
+
         printf("%s [OPTIONS...] {COMMAND} [ARGS...]\n\n"
                "Run the specified command in a transient scope or service.\n\n"
                "  -h --help                       Show this help\n"
@@ -101,6 +94,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"
@@ -109,11 +106,16 @@ static void help(void) {
                "     --on-unit-inactive=SECONDS   Run SECONDS after the last deactivation\n"
                "     --on-calendar=SPEC           Realtime timer\n"
                "     --timer-property=NAME=VALUE  Set timer unit property\n"
-               , program_invocation_short_name);
+               "\nSee the %s for details.\n"
+               , program_invocation_short_name
+               , link
+        );
+
+        return 0;
 }
 
 static int add_timer_property(const char *name, const char *val) {
-        _cleanup_free_ char *p = NULL;
+        char *p;
 
         assert(name);
         assert(val);
@@ -125,8 +127,6 @@ static int add_timer_property(const char *name, const char *val) {
         if (strv_consume(&arg_timer_property, p) < 0)
                 return log_oom();
 
-        p = NULL;
-
         return 0;
 }
 
@@ -152,6 +152,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,
@@ -188,12 +190,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);
@@ -204,8 +209,7 @@ static int parse_argv(int argc, char *argv[]) {
                 switch (c) {
 
                 case 'h':
-                        help();
-                        return 0;
+                        return help();
 
                 case ARG_VERSION:
                         return version();
@@ -368,6 +372,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;
@@ -387,6 +405,12 @@ 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)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Only single trigger (path, socket, timer) unit can be created.");
 
         if (arg_stdio == ARG_STDIO_AUTO) {
                 /* If we both --pty and --pipe are specified we'll automatically pick --pty if we are connected fully
@@ -397,72 +421,60 @@ static int parse_argv(int argc, char *argv[]) {
                         ARG_STDIO_DIRECT;
         }
 
-        if ((optind >= argc) && (!arg_unit || !with_timer)) {
-                log_error("Command line to execute required.");
-                return -EINVAL;
-        }
+        if ((optind >= argc) && (!arg_unit || !with_trigger))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Command line to execute required.");
 
-        if (arg_user && arg_transport != BUS_TRANSPORT_LOCAL) {
-                log_error("Execution in user context is not supported on non-local systems.");
-                return -EINVAL;
-        }
+        if (arg_user && arg_transport != BUS_TRANSPORT_LOCAL)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Execution in user context is not supported on non-local systems.");
 
-        if (arg_scope && arg_transport != BUS_TRANSPORT_LOCAL) {
-                log_error("Scope execution is not supported on non-local systems.");
-                return -EINVAL;
-        }
+        if (arg_scope && arg_transport != BUS_TRANSPORT_LOCAL)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Scope execution is not supported on non-local systems.");
 
-        if (arg_scope && (arg_remain_after_exit || arg_service_type)) {
-                log_error("--remain-after-exit and --service-type= are not supported in --scope mode.");
-                return -EINVAL;
-        }
+        if (arg_scope && (arg_remain_after_exit || arg_service_type))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "--remain-after-exit and --service-type= are not supported in --scope mode.");
 
-        if (arg_stdio != ARG_STDIO_NONE && (with_timer || arg_scope)) {
-                log_error("--pty/--pipe is not compatible in timer or --scope mode.");
-                return -EINVAL;
-        }
+        if (arg_stdio != ARG_STDIO_NONE && (with_trigger || arg_scope))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "--pty/--pipe is not compatible in timer or --scope mode.");
 
-        if (arg_stdio != ARG_STDIO_NONE && arg_transport == BUS_TRANSPORT_REMOTE) {
-                log_error("--pty/--pipe is only supported when connecting to the local system or containers.");
-                return -EINVAL;
-        }
+        if (arg_stdio != ARG_STDIO_NONE && arg_transport == BUS_TRANSPORT_REMOTE)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "--pty/--pipe is only supported when connecting to the local system or containers.");
 
-        if (arg_stdio != ARG_STDIO_NONE && arg_no_block) {
-                log_error("--pty/--pipe is not compatible with --no-block.");
-                return -EINVAL;
-        }
+        if (arg_stdio != ARG_STDIO_NONE && arg_no_block)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "--pty/--pipe is not compatible with --no-block.");
 
-        if (arg_scope && with_timer) {
-                log_error("Timer options are not supported in --scope mode.");
-                return -EINVAL;
-        }
+        if (arg_scope && with_trigger)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Path, socket or timer options are not supported in --scope mode.");
 
-        if (arg_timer_property && !with_timer) {
-                log_error("--timer-property= has no effect without any other timer options.");
-                return -EINVAL;
-        }
+        if (arg_timer_property && !with_timer)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "--timer-property= has no effect without any other timer options.");
 
         if (arg_wait) {
-                if (arg_no_block) {
-                        log_error("--wait may not be combined with --no-block.");
-                        return -EINVAL;
-                }
+                if (arg_no_block)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "--wait may not be combined with --no-block.");
 
-                if (with_timer) {
-                        log_error("--wait may not be combined with timer operations.");
-                        return -EINVAL;
-                }
+                if (with_trigger)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "--wait may not be combined with path, socket or timer operations.");
 
-                if (arg_scope) {
-                        log_error("--wait may not be combined with --scope.");
-                        return -EINVAL;
-                }
+                if (arg_scope)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "--wait may not be combined with --scope.");
         }
 
         return 1;
 }
 
-static int transient_unit_set_properties(sd_bus_message *m, char **properties) {
+static int transient_unit_set_properties(sd_bus_message *m, UnitType t, char **properties) {
         int r;
 
         r = sd_bus_message_append(m, "(sv)", "Description", "s", arg_description);
@@ -475,7 +487,7 @@ static int transient_unit_set_properties(sd_bus_message *m, char **properties) {
                         return bus_log_create_error(r);
         }
 
-        r = bus_append_unit_property_assignment_many(m, properties);
+        r = bus_append_unit_property_assignment_many(m, t, properties);
         if (r < 0)
                 return r;
 
@@ -489,7 +501,7 @@ static int transient_cgroup_set_properties(sd_bus_message *m) {
         if (!isempty(arg_slice)) {
                 _cleanup_free_ char *slice = NULL;
 
-                r = unit_name_mangle_with_suffix(arg_slice, UNIT_NAME_NOGLOB, ".slice", &slice);
+                r = unit_name_mangle_with_suffix(arg_slice, arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, ".slice", &slice);
                 if (r < 0)
                         return log_error_errno(r, "Failed to mangle name '%s': %m", arg_slice);
 
@@ -521,7 +533,7 @@ static int transient_service_set_properties(sd_bus_message *m, char **argv, cons
 
         assert(m);
 
-        r = transient_unit_set_properties(m, arg_property);
+        r = transient_unit_set_properties(m, UNIT_SERVICE, arg_property);
         if (r < 0)
                 return r;
 
@@ -694,7 +706,7 @@ static int transient_scope_set_properties(sd_bus_message *m) {
 
         assert(m);
 
-        r = transient_unit_set_properties(m, arg_property);
+        r = transient_unit_set_properties(m, UNIT_SCOPE, arg_property);
         if (r < 0)
                 return r;
 
@@ -718,7 +730,7 @@ static int transient_timer_set_properties(sd_bus_message *m) {
 
         assert(m);
 
-        r = transient_unit_set_properties(m, arg_timer_property);
+        r = transient_unit_set_properties(m, UNIT_TIMER, arg_timer_property);
         if (r < 0)
                 return r;
 
@@ -762,10 +774,10 @@ static int make_unit_name(sd_bus *bus, UnitType t, char **ret) {
          * name our transient units. */
 
         id = startswith(unique, ":1.");
-        if (!id) {
-                log_error("Unique name %s has unexpected format.", unique);
-                return -EINVAL;
-        }
+        if (!id)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Unique name %s has unexpected format.",
+                                       unique);
 
         p = strjoin("run-u", id, ".", unit_type_to_string(t));
         if (!p)
@@ -844,7 +856,9 @@ static int run_context_update(RunContext *c, const char *path) {
                                    "org.freedesktop.systemd1",
                                    path,
                                    map,
+                                   BUS_MAP_STRDUP,
                                    &error,
+                                   NULL,
                                    c);
         if (r < 0) {
                 sd_event_exit(c->event, EXIT_FAILURE);
@@ -897,7 +911,7 @@ static int start_transient_service(
         if (arg_stdio == ARG_STDIO_PTY) {
 
                 if (arg_transport == BUS_TRANSPORT_LOCAL) {
-                        master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY);
+                        master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
                         if (master < 0)
                                 return log_error_errno(errno, "Failed to acquire pseudo tty: %m");
 
@@ -925,10 +939,8 @@ static int start_transient_service(
                                                &error,
                                                &pty_reply,
                                                "s", arg_host);
-                        if (r < 0) {
-                                log_error("Failed to get machine PTY: %s", bus_error_message(&error, -r));
-                                return r;
-                        }
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to get machine PTY: %s", bus_error_message(&error, -r));
 
                         r = sd_bus_message_read(pty_reply, "hs", &master, &s);
                         if (r < 0)
@@ -952,7 +964,7 @@ static int start_transient_service(
         }
 
         if (arg_unit) {
-                r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".service", &service);
+                r = unit_name_mangle_with_suffix(arg_unit, arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, ".service", &service);
                 if (r < 0)
                         return log_error_errno(r, "Failed to mangle unit name: %m");
         } else {
@@ -1028,7 +1040,6 @@ static int start_transient_service(
                         .inactive_enter_usec = USEC_INFINITY,
                 };
                 _cleanup_free_ char *path = NULL;
-                const char *mt;
 
                 c.bus = sd_bus_ref(bus);
 
@@ -1058,18 +1069,20 @@ static int start_transient_service(
                 if (!path)
                         return log_oom();
 
-                mt = strjoina("type='signal',"
-                              "sender='org.freedesktop.systemd1',"
-                              "path='", path, "',"
-                              "interface='org.freedesktop.DBus.Properties',"
-                              "member='PropertiesChanged'");
-                r = sd_bus_add_match(bus, &c.match, mt, on_properties_changed, &c);
+                r = sd_bus_match_signal_async(
+                                bus,
+                                &c.match,
+                                "org.freedesktop.systemd1",
+                                path,
+                                "org.freedesktop.DBus.Properties",
+                                "PropertiesChanged",
+                                on_properties_changed, NULL, &c);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to add properties changed signal.");
+                        return log_error_errno(r, "Failed to request properties changed signal match: %m");
 
                 r = sd_bus_attach_event(bus, c.event, SD_EVENT_PRIORITY_NORMAL);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to attach bus to event loop.");
+                        return log_error_errno(r, "Failed to attach bus to event loop: %m");
 
                 r = run_context_update(&c, path);
                 if (r < 0)
@@ -1154,7 +1167,7 @@ static int start_transient_scope(
                 return log_oom();
 
         if (arg_unit) {
-                r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".scope", &scope);
+                r = unit_name_mangle_with_suffix(arg_unit, arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, ".scope", &scope);
                 if (r < 0)
                         return log_error_errno(r, "Failed to mangle scope name: %m");
         } else {
@@ -1203,10 +1216,8 @@ static int start_transient_scope(
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
         r = sd_bus_call(bus, m, 0, &error, &reply);
-        if (r < 0) {
-                log_error("Failed to start transient scope unit: %s", bus_error_message(&error, -r));
-                return r;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to start transient scope unit: %s", bus_error_message(&error, -r));
 
         if (arg_nice_set) {
                 if (setpriority(PRIO_PROCESS, 0, arg_nice) < 0)
@@ -1216,7 +1227,7 @@ static int start_transient_scope(
         if (arg_exec_group) {
                 gid_t gid;
 
-                r = get_group_creds(&arg_exec_group, &gid);
+                r = get_group_creds(&arg_exec_group, &gid, 0);
                 if (r < 0)
                         return log_error_errno(r, "Failed to resolve group %s: %m", arg_exec_group);
 
@@ -1229,7 +1240,7 @@ static int start_transient_scope(
                 uid_t uid;
                 gid_t gid;
 
-                r = get_user_creds_clean(&arg_exec_user, &uid, &gid, &home, &shell);
+                r = get_user_creds(&arg_exec_user, &uid, &gid, &home, &shell, USER_CREDS_CLEAN|USER_CREDS_PREFER_NSS);
                 if (r < 0)
                         return log_error_errno(r, "Failed to resolve user %s: %m", arg_exec_user);
 
@@ -1282,14 +1293,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;
 
@@ -1308,27 +1320,27 @@ 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;
 
                 default:
-                        r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".service", &service);
+                        r = unit_name_mangle_with_suffix(arg_unit, arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, ".service", &service);
                         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, arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, suffix, &trigger);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to mangle unit name: %m");
 
@@ -1339,7 +1351,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");
         }
@@ -1359,7 +1371,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);
 
@@ -1368,7 +1380,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;
 
@@ -1413,10 +1432,8 @@ static int start_transient_timer(
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
         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));
-                return r;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to start transient %s unit: %s", suffix + 1, bus_error_message(&error, -r));
 
         r = sd_bus_message_read(reply, "o", &object);
         if (r < 0)
@@ -1427,7 +1444,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);
         }
@@ -1488,14 +1505,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;