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/>.
26 #include "bus-internal.h"
27 #include "bus-message.h"
30 #include "unit-name.h"
32 static bool arg_scope = false;
33 static bool arg_user = false;
34 static const char *arg_unit = NULL;
35 static const char *arg_description = NULL;
36 static const char *arg_slice = NULL;
38 static int help(void) {
40 printf("%s [OPTIONS...] [COMMAND LINE...]\n\n"
41 "Notify the init system about service status updates.\n\n"
42 " -h --help Show this help\n"
43 " --version Show package version\n"
44 " --user Run as user unit\n"
45 " --scope Run this as scope rather than service\n"
46 " --unit=UNIT Run under the specified unit name\n"
47 " --description=TEXT Description for unit\n"
48 " --slice=SLICE Run in the specified slice\n",
49 program_invocation_short_name);
54 static int parse_argv(int argc, char *argv[]) {
65 static const struct option options[] = {
66 { "help", no_argument, NULL, 'h' },
67 { "version", no_argument, NULL, ARG_VERSION },
68 { "user", no_argument, NULL, ARG_USER },
69 { "scope", no_argument, NULL, ARG_SCOPE },
70 { "unit", required_argument, NULL, ARG_UNIT },
71 { "description", required_argument, NULL, ARG_DESCRIPTION },
72 { "slice", required_argument, NULL, ARG_SLICE },
81 while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0) {
91 puts(SYSTEMD_FEATURES);
106 case ARG_DESCRIPTION:
107 arg_description = optarg;
118 log_error("Unknown option code %c", c);
123 if (optind >= argc) {
124 log_error("Command line to execute required.");
131 static int message_start_transient_unit_new(sd_bus *bus, const char *name, sd_bus_message **ret) {
132 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
135 log_info("Running as unit %s.", name);
137 r = sd_bus_message_new_method_call(
139 "org.freedesktop.systemd1",
140 "/org/freedesktop/systemd1",
141 "org.freedesktop.systemd1.Manager",
142 "StartTransientUnit", &m);
146 r = sd_bus_message_append(m, "ss", name, "fail");
150 r = sd_bus_message_open_container(m, 'a', "(sv)");
154 r = sd_bus_message_append(m, "(sv)", "Description", "s", arg_description);
158 if (!isempty(arg_slice)) {
159 _cleanup_free_ char *slice;
161 slice = unit_name_mangle_with_suffix(arg_slice, ".slice");
165 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
176 static int message_start_transient_unit_send(sd_bus *bus, sd_bus_message *m, sd_bus_error *error, sd_bus_message **reply) {
179 r = sd_bus_message_close_container(m);
183 return sd_bus_send_with_reply_and_block(bus, m, 0, error, reply);
186 static int start_transient_service(
189 sd_bus_error *error) {
191 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
192 _cleanup_free_ char *name = NULL;
197 name = unit_name_mangle_with_suffix(arg_unit, ".service");
199 asprintf(&name, "run-%lu.service", (unsigned long) getpid());
203 r = message_start_transient_unit_new(bus, name, &m);
207 r = sd_bus_message_open_container(m, 'r', "sv");
211 r = sd_bus_message_append(m, "s", "ExecStart");
215 r = sd_bus_message_open_container(m, 'v', "a(sasb)");
219 r = sd_bus_message_open_container(m, 'a', "(sasb)");
223 r = sd_bus_message_open_container(m, 'r', "sasb");
227 r = sd_bus_message_append(m, "s", argv[0]);
231 r = sd_bus_message_open_container(m, 'a', "s");
235 STRV_FOREACH(i, argv) {
236 r = sd_bus_message_append(m, "s", *i);
241 r = sd_bus_message_close_container(m);
245 r = sd_bus_message_append(m, "b", false);
249 r = sd_bus_message_close_container(m);
253 r = sd_bus_message_close_container(m);
257 r = sd_bus_message_close_container(m);
261 r = sd_bus_message_close_container(m);
265 return message_start_transient_unit_send(bus, m, error, &reply);
268 static int start_transient_scope(
271 sd_bus_error *error) {
273 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
274 _cleanup_free_ char *name = NULL;
278 name = unit_name_mangle_with_suffix(arg_unit, ".scope");
280 asprintf(&name, "run-%lu.scope", (unsigned long) getpid());
284 r = message_start_transient_unit_new(bus, name, &m);
288 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
292 r = message_start_transient_unit_send(bus, m, error, &reply);
296 execvp(argv[0], argv);
297 log_error("Failed to execute: %m");
301 int main(int argc, char* argv[]) {
302 sd_bus_error error = SD_BUS_ERROR_NULL;
303 _cleanup_bus_unref_ sd_bus *bus = NULL;
304 _cleanup_free_ char *description = NULL;
307 log_parse_environment();
310 r = parse_argv(argc, argv);
314 if (!arg_description) {
315 description = strv_join(argv + optind, " ");
321 arg_description = description;
325 r = sd_bus_open_user(&bus);
327 r = sd_bus_open_system(&bus);
329 log_error("Failed to create new bus connection: %s", strerror(-r));
334 r = start_transient_scope(bus, argv + optind, &error);
336 r = start_transient_service(bus, argv + optind, &error);
338 log_error("Failed start transient unit: %s", error.message ? error.message : strerror(-r));
339 sd_bus_error_free(&error);
344 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;