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;
37 static int help(void) {
39 printf("%s [OPTIONS...] [COMMAND LINE...]\n\n"
40 "Notify the init system about service status updates.\n\n"
41 " -h --help Show this help\n"
42 " --version Show package version\n"
43 " --user Run as user unit\n"
44 " --scope Run this as scope rather than service\n"
45 " --unit=UNIT Run under the specified unit name\n"
46 " --description=TEXT Description for unit\n",
47 program_invocation_short_name);
52 static int parse_argv(int argc, char *argv[]) {
62 static const struct option options[] = {
63 { "help", no_argument, NULL, 'h' },
64 { "version", no_argument, NULL, ARG_VERSION },
65 { "user", no_argument, NULL, ARG_USER },
66 { "scope", no_argument, NULL, ARG_SCOPE },
67 { "unit", required_argument, NULL, ARG_UNIT },
68 { "description", required_argument, NULL, ARG_DESCRIPTION },
77 while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0) {
87 puts(SYSTEMD_FEATURES);
102 case ARG_DESCRIPTION:
103 arg_description = optarg;
110 log_error("Unknown option code %c", c);
115 if (optind >= argc) {
116 log_error("Command line to execute required.");
123 static int message_start_transient_unit_new(sd_bus *bus, const char *name, sd_bus_message **ret) {
124 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
127 log_info("Running as unit %s.", name);
129 r = sd_bus_message_new_method_call(
131 "org.freedesktop.systemd1",
132 "/org/freedesktop/systemd1",
133 "org.freedesktop.systemd1.Manager",
134 "StartTransientUnit", &m);
138 r = sd_bus_message_append(m, "ss", name, "fail");
142 r = sd_bus_message_open_container(m, 'a', "(sv)");
146 r = sd_bus_message_append(m, "(sv)", "Description", "s", arg_description);
156 static int message_start_transient_unit_send(sd_bus *bus, sd_bus_message *m, sd_bus_error *error, sd_bus_message **reply) {
159 r = sd_bus_message_close_container(m);
163 return sd_bus_send_with_reply_and_block(bus, m, 0, error, reply);
166 static int start_transient_service(
169 sd_bus_error *error) {
171 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
172 _cleanup_free_ char *name = NULL;
177 name = unit_name_mangle_with_suffix(arg_unit, ".service");
179 asprintf(&name, "run-%lu.service", (unsigned long) getpid());
183 r = message_start_transient_unit_new(bus, name, &m);
187 r = sd_bus_message_open_container(m, 'r', "sv");
191 r = sd_bus_message_append(m, "s", "ExecStart");
195 r = sd_bus_message_open_container(m, 'v', "a(sasb)");
199 r = sd_bus_message_open_container(m, 'a', "(sasb)");
203 r = sd_bus_message_open_container(m, 'r', "sasb");
207 r = sd_bus_message_append(m, "s", argv[0]);
211 r = sd_bus_message_open_container(m, 'a', "s");
215 STRV_FOREACH(i, argv) {
216 r = sd_bus_message_append(m, "s", *i);
221 r = sd_bus_message_close_container(m);
225 r = sd_bus_message_append(m, "b", false);
229 r = sd_bus_message_close_container(m);
233 r = sd_bus_message_close_container(m);
237 r = sd_bus_message_close_container(m);
241 r = sd_bus_message_close_container(m);
245 return message_start_transient_unit_send(bus, m, error, &reply);
248 static int start_transient_scope(
251 sd_bus_error *error) {
253 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
254 _cleanup_free_ char *name = NULL;
258 name = unit_name_mangle_with_suffix(arg_unit, ".scope");
260 asprintf(&name, "run-%lu.scope", (unsigned long) getpid());
264 r = message_start_transient_unit_new(bus, name, &m);
268 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
272 r = message_start_transient_unit_send(bus, m, error, &reply);
276 execvp(argv[0], argv);
277 log_error("Failed to execute: %m");
281 int main(int argc, char* argv[]) {
282 sd_bus_error error = SD_BUS_ERROR_NULL;
283 _cleanup_bus_unref_ sd_bus *bus = NULL;
284 _cleanup_free_ char *description = NULL;
287 log_parse_environment();
290 r = parse_argv(argc, argv);
294 if (!arg_description) {
295 description = strv_join(argv + optind, " ");
301 arg_description = description;
305 r = sd_bus_open_user(&bus);
307 r = sd_bus_open_system(&bus);
309 log_error("Failed to create new bus connection: %s", strerror(-r));
314 r = start_transient_scope(bus, argv + optind, &error);
316 r = start_transient_service(bus, argv + optind, &error);
318 log_error("Failed start transient unit: %s", error.message ? error.message : strerror(-r));
319 sd_bus_error_free(&error);
324 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;