From 18d515aeb3a2007fa0a762b9b9658f489d4b403d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 28 Apr 2015 12:21:31 +0200 Subject: [PATCH] run: synchronously wait until the scope unit we create is started Otherwise it might happen that by the time PID 1 adds our process to the scope unit the process might already have died, if the process is short-running (such as an invocation to /bin/true). https://bugs.freedesktop.org/show_bug.cgi?id=86520 Cherry-picked from: de158ed22db60e3a6654557fa4aa72f7248550af Resolves: #1283192 --- src/libsystemd/sd-bus/bus-util.c | 10 ++++++++++ src/libsystemd/sd-bus/bus-util.h | 1 + src/run/run.c | 42 +++++++++++++++++++++++++++++++++------- 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c index e48abf5..6d56150 100644 --- a/src/libsystemd/sd-bus/bus-util.c +++ b/src/libsystemd/sd-bus/bus-util.c @@ -1854,6 +1854,16 @@ int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) { return set_put_strdup(d->jobs, path); } +int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet) { + int r; + + r = bus_wait_for_jobs_add(d, path); + if (r < 0) + return log_oom(); + + return bus_wait_for_jobs(d, quiet); +} + int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes) { const char *type, *path, *source; int r; diff --git a/src/libsystemd/sd-bus/bus-util.h b/src/libsystemd/sd-bus/bus-util.h index 21db982..8c8846c 100644 --- a/src/libsystemd/sd-bus/bus-util.h +++ b/src/libsystemd/sd-bus/bus-util.h @@ -209,6 +209,7 @@ int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret); void bus_wait_for_jobs_free(BusWaitForJobs *d); int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path); int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet); +int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet); DEFINE_TRIVIAL_CLEANUP_FUNC(BusWaitForJobs*, bus_wait_for_jobs_free); diff --git a/src/run/run.c b/src/run/run.c index 0e5bde2..dd1338f 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -806,14 +806,20 @@ static int start_transient_scope( char **argv) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; _cleanup_strv_free_ char **env = NULL, **user_env = NULL; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; _cleanup_free_ char *scope = NULL; + const char *object = NULL; int r; assert(bus); assert(argv); + r = bus_wait_for_jobs_new(bus, &w); + if (r < 0) + return log_oom(); + if (arg_unit) { scope = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".scope"); if (!scope) @@ -854,7 +860,7 @@ static int start_transient_scope( if (r < 0) return bus_log_create_error(r); - r = sd_bus_call(bus, m, 0, &error, NULL); + 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; @@ -914,8 +920,16 @@ static int start_transient_scope( if (!env) return log_oom(); + r = sd_bus_message_read(reply, "o", &object); + if (r < 0) + return bus_log_parse_error(r); + + r = bus_wait_for_jobs_one(w, object, arg_quiet); + if (r < 0) + return r; + if (!arg_quiet) - log_info("Running as unit %s.", scope); + log_info("Running scope as unit %s.", scope); execvpe(argv[0], argv, env); @@ -927,13 +941,19 @@ static int start_transient_timer( char **argv) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; _cleanup_free_ char *timer = NULL, *service = NULL; + const char *object = NULL; int r; assert(bus); assert(argv); + r = bus_wait_for_jobs_new(bus, &w); + if (r < 0) + return log_oom(); + if (arg_unit) { switch(unit_name_to_type(arg_unit)) { @@ -1034,15 +1054,23 @@ static int start_transient_timer( if (r < 0) return bus_log_create_error(r); - r = sd_bus_call(bus, m, 0, &error, NULL); + 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; } - log_info("Running as unit %s.", timer); + r = sd_bus_message_read(reply, "o", &object); + if (r < 0) + return bus_log_parse_error(r); + + r = bus_wait_for_jobs_one(w, object, arg_quiet); + if (r < 0) + return r; + + log_info("Running timer as unit %s.", timer); if (argv[0]) - log_info("Will run as unit %s.", service); + log_info("Will run service as unit %s.", service); return 0; }