1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
29 #include "unit-name.h"
30 #include "path-util.h"
32 static bool arg_scope = false;
33 static bool arg_user = false;
34 static bool arg_remain_after_exit = false;
35 static const char *arg_unit = NULL;
36 static const char *arg_description = NULL;
37 static const char *arg_slice = NULL;
38 static bool arg_send_sighup = false;
40 static int help(void) {
42 printf("%s [OPTIONS...] COMMAND [ARGS...]\n\n"
43 "Run the specified command in a transient scope or service unit.\n\n"
44 " -h --help Show this help\n"
45 " --version Show package version\n"
46 " --user Run as user unit\n"
47 " --scope Run this as scope rather than service\n"
48 " --unit=UNIT Run under the specified unit name\n"
49 " --description=TEXT Description for unit\n"
50 " --slice=SLICE Run in the specified slice\n"
51 " -r --remain-after-exit Leave service around until explicitly stopped\n"
52 " --send-sighup Send SIGHUP when terminating\n",
53 program_invocation_short_name);
58 static int parse_argv(int argc, char *argv[]) {
70 static const struct option options[] = {
71 { "help", no_argument, NULL, 'h' },
72 { "version", no_argument, NULL, ARG_VERSION },
73 { "user", no_argument, NULL, ARG_USER },
74 { "scope", no_argument, NULL, ARG_SCOPE },
75 { "unit", required_argument, NULL, ARG_UNIT },
76 { "description", required_argument, NULL, ARG_DESCRIPTION },
77 { "slice", required_argument, NULL, ARG_SLICE },
78 { "remain-after-exit", no_argument, NULL, 'r' },
79 { "send-sighup", no_argument, NULL, ARG_SEND_SIGHUP },
88 while ((c = getopt_long(argc, argv, "+hr", options, NULL)) >= 0) {
98 puts(SYSTEMD_FEATURES);
113 case ARG_DESCRIPTION:
114 arg_description = optarg;
121 case ARG_SEND_SIGHUP:
122 arg_send_sighup = true;
126 arg_remain_after_exit = true;
133 log_error("Unknown option code %c", c);
138 if (optind >= argc) {
139 log_error("Command line to execute required.");
146 static int message_start_transient_unit_new(sd_bus *bus, const char *name, sd_bus_message **ret) {
147 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
150 log_info("Running as unit %s.", name);
152 r = sd_bus_message_new_method_call(
154 "org.freedesktop.systemd1",
155 "/org/freedesktop/systemd1",
156 "org.freedesktop.systemd1.Manager",
157 "StartTransientUnit", &m);
161 r = sd_bus_message_append(m, "ss", name, "fail");
165 r = sd_bus_message_open_container(m, 'a', "(sv)");
169 r = sd_bus_message_append(m, "(sv)", "Description", "s", arg_description);
173 if (!isempty(arg_slice)) {
174 _cleanup_free_ char *slice;
176 slice = unit_name_mangle_with_suffix(arg_slice, ".slice");
180 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
185 r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", arg_send_sighup);
195 static int message_start_transient_unit_send(sd_bus *bus, sd_bus_message *m, sd_bus_error *error, sd_bus_message **reply) {
198 r = sd_bus_message_close_container(m);
202 return sd_bus_send_with_reply_and_block(bus, m, 0, error, reply);
205 static int start_transient_service(
208 sd_bus_error *error) {
210 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
211 _cleanup_free_ char *name = NULL;
216 name = unit_name_mangle_with_suffix(arg_unit, ".service");
218 asprintf(&name, "run-%lu.service", (unsigned long) getpid());
222 r = message_start_transient_unit_new(bus, name, &m);
226 r = sd_bus_message_append(m, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit);
230 r = sd_bus_message_open_container(m, 'r', "sv");
234 r = sd_bus_message_append(m, "s", "ExecStart");
238 r = sd_bus_message_open_container(m, 'v', "a(sasb)");
242 r = sd_bus_message_open_container(m, 'a', "(sasb)");
246 r = sd_bus_message_open_container(m, 'r', "sasb");
250 r = sd_bus_message_append(m, "s", argv[0]);
254 r = sd_bus_message_open_container(m, 'a', "s");
258 STRV_FOREACH(i, argv) {
259 r = sd_bus_message_append(m, "s", *i);
264 r = sd_bus_message_close_container(m);
268 r = sd_bus_message_append(m, "b", false);
272 r = sd_bus_message_close_container(m);
276 r = sd_bus_message_close_container(m);
280 r = sd_bus_message_close_container(m);
284 r = sd_bus_message_close_container(m);
288 return message_start_transient_unit_send(bus, m, error, &reply);
291 static int start_transient_scope(
294 sd_bus_error *error) {
296 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
297 _cleanup_free_ char *name = NULL;
301 name = unit_name_mangle_with_suffix(arg_unit, ".scope");
303 asprintf(&name, "run-%lu.scope", (unsigned long) getpid());
307 r = message_start_transient_unit_new(bus, name, &m);
311 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
315 r = message_start_transient_unit_send(bus, m, error, &reply);
319 execvp(argv[0], argv);
320 log_error("Failed to execute: %m");
324 int main(int argc, char* argv[]) {
325 sd_bus_error error = SD_BUS_ERROR_NULL;
326 _cleanup_bus_unref_ sd_bus *bus = NULL;
327 _cleanup_free_ char *description = NULL, *command = NULL;
330 log_parse_environment();
333 r = parse_argv(argc, argv);
337 r = find_binary(argv[optind], &command);
339 log_error("Failed to find executable %s: %s", argv[optind], strerror(-r));
342 argv[optind] = command;
344 if (!arg_description) {
345 description = strv_join(argv + optind, " ");
351 arg_description = description;
355 r = sd_bus_open_user(&bus);
357 r = sd_bus_open_system(&bus);
359 log_error("Failed to create new bus connection: %s", strerror(-r));
364 r = start_transient_scope(bus, argv + optind, &error);
366 r = start_transient_service(bus, argv + optind, &error);
368 log_error("Failed start transient unit: %s", error.message ? error.message : strerror(-r));
369 sd_bus_error_free(&error);
374 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;