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;
36 static int help(void) {
38 printf("%s [OPTIONS...] [COMMAND LINE...]\n\n"
39 "Notify the init system about service status updates.\n\n"
40 " -h --help Show this help\n"
41 " --version Show package version\n"
42 " --user Run as user unit\n"
43 " --scope Run this as scope rather than service\n"
44 " --unit=UNIT Run under the specified unit name\n",
45 program_invocation_short_name);
50 static int parse_argv(int argc, char *argv[]) {
59 static const struct option options[] = {
60 { "help", no_argument, NULL, 'h' },
61 { "version", no_argument, NULL, ARG_VERSION },
62 { "user", no_argument, NULL, ARG_USER },
63 { "scope", no_argument, NULL, ARG_SCOPE },
64 { "unit", required_argument, NULL, ARG_UNIT },
73 while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0) {
83 puts(SYSTEMD_FEATURES);
102 log_error("Unknown option code %c", c);
107 if (optind >= argc) {
108 log_error("Command line to execute required.");
115 static int message_start_transient_unit_new(sd_bus *bus, const char *name, sd_bus_message **ret) {
116 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
119 log_info("Running as unit %s.", name);
121 r = sd_bus_message_new_method_call(
123 "org.freedesktop.systemd1",
124 "/org/freedesktop/systemd1",
125 "org.freedesktop.systemd1.Manager",
126 "StartTransientUnit", &m);
130 r = sd_bus_message_append(m, "ss", name, "fail");
134 r = sd_bus_message_open_container(m, 'a', "(sv)");
138 r = sd_bus_message_open_container(m, 'r', "sv");
148 static int message_start_transient_unit_send(sd_bus *bus, sd_bus_message *m, sd_bus_error *error, sd_bus_message **reply) {
151 r = sd_bus_message_close_container(m);
155 r = sd_bus_message_close_container(m);
159 return sd_bus_send_with_reply_and_block(bus, m, 0, error, reply);
162 static int start_transient_service(
165 sd_bus_error *error) {
167 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
168 _cleanup_free_ char *name = NULL;
173 name = unit_name_mangle_with_suffix(arg_unit, ".service");
175 asprintf(&name, "run-%lu.service", (unsigned long) getpid());
179 r = message_start_transient_unit_new(bus, name, &m);
183 r = sd_bus_message_append(m, "s", "ExecStart");
187 r = sd_bus_message_open_container(m, 'v', "a(sasb)");
191 r = sd_bus_message_open_container(m, 'a', "(sasb)");
195 r = sd_bus_message_open_container(m, 'r', "sasb");
199 r = sd_bus_message_append(m, "s", argv[0]);
203 r = sd_bus_message_open_container(m, 'a', "s");
207 STRV_FOREACH(i, argv) {
208 r = sd_bus_message_append(m, "s", *i);
213 r = sd_bus_message_close_container(m);
217 r = sd_bus_message_append(m, "b", false);
221 r = sd_bus_message_close_container(m);
225 r = sd_bus_message_close_container(m);
229 r = sd_bus_message_close_container(m);
233 return message_start_transient_unit_send(bus, m, error, &reply);
236 static int start_transient_scope(
239 sd_bus_error *error) {
241 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
242 _cleanup_free_ char *name = NULL;
246 name = unit_name_mangle_with_suffix(arg_unit, ".scope");
248 asprintf(&name, "run-%lu.scope", (unsigned long) getpid());
252 r = message_start_transient_unit_new(bus, name, &m);
256 r = sd_bus_message_append(m, "sv", "PIDs", "au", 1, (uint32_t) getpid());
260 r = message_start_transient_unit_send(bus, m, error, &reply);
264 execvp(argv[0], argv);
265 log_error("Failed to execute: %m");
269 int main(int argc, char* argv[]) {
270 sd_bus_error error = SD_BUS_ERROR_NULL;
271 _cleanup_bus_unref_ sd_bus *bus = NULL;
274 log_parse_environment();
277 r = parse_argv(argc, argv);
282 r = sd_bus_open_user(&bus);
284 r = sd_bus_open_system(&bus);
286 log_error("Failed to create new bus connection: %s", strerror(-r));
291 r = start_transient_scope(bus, argv + optind, &error);
293 r = start_transient_service(bus, argv + optind, &error);
295 log_error("Failed start transient unit: %s", error.message);
296 sd_bus_error_free(&error);
301 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;