It similar with StartTransientUnit but the NewTransientUnit does not start the unit immediately. Newly generated transient unit can be activated by "systemctl start". --- src/core/dbus-manager.c | 99 +++++++++++++++++++++++++++++----- src/core/org.freedesktop.systemd1.conf | 4 ++ src/core/service.c | 12 +++++ 3 files changed, 103 insertions(+), 12 deletions(-)
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 533ce43..84c913b 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -615,10 +615,15 @@ static int method_set_unit_properties(sd_bus *bus, sd_bus_message *message, void return bus_unit_method_set_properties(bus, message, u, error); } -static int method_start_transient_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { +static int new_transient_unit_from_message(sd_bus *bus, + sd_bus_message *message, + void *userdata, + sd_bus_error *error, + Unit **unit, + JobMode *mode, + bool keep) { const char *name, *smode; Manager *m = userdata; - JobMode mode; UnitType t; Unit *u; int r; @@ -631,7 +636,9 @@ static int method_start_transient_unit(sd_bus *bus, sd_bus_message *message, voi if (r < 0) return r; if (r == 0) - return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ + /* No authorization for now, but the async polkit + * stuff will call us again when it has it */ + return 1; r = sd_bus_message_read(message, "ss", &name, &smode); if (r < 0) @@ -639,14 +646,22 @@ static int method_start_transient_unit(sd_bus *bus, sd_bus_message *message, voi t = unit_name_to_type(name); if (t < 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit type."); + return sd_bus_error_setf(error, + SD_BUS_ERROR_INVALID_ARGS, + "Invalid unit type."); if (!unit_vtable[t]->can_transient) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t)); - - mode = job_mode_from_string(smode); - if (mode < 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s is invalid.", smode); + return sd_bus_error_setf(error, + SD_BUS_ERROR_INVALID_ARGS, + "Unit type %s does not support transient units.", + unit_type_to_string(t)); + + *mode = job_mode_from_string(smode); + if (*mode < 0) + return sd_bus_error_setf(error, + SD_BUS_ERROR_INVALID_ARGS, + "Job mode %s is invalid.", + smode); r = selinux_access_check(message, "start", error); if (r < 0) @@ -656,8 +671,12 @@ static int method_start_transient_unit(sd_bus *bus, sd_bus_message *message, voi if (r < 0) return r; - if (u->load_state != UNIT_NOT_FOUND || set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0) - return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name); + if (u->load_state != UNIT_NOT_FOUND || + set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0) + return sd_bus_error_setf(error, + BUS_ERROR_UNIT_EXISTS, + "Unit %s already exists.", + name); /* OK, the unit failed to load and is unreferenced, now let's * fill in the transient data instead */ @@ -675,10 +694,65 @@ static int method_start_transient_unit(sd_bus *bus, sd_bus_message *message, voi if (r < 0) return r; + *unit = u; manager_dispatch_load_queue(m); + return 0; +} + +static int method_new_transient_unit(sd_bus *bus, + sd_bus_message *message, + void *userdata, + sd_bus_error *error) { + _cleanup_free_ char *path = NULL; + JobMode mode; + Unit *u = NULL; + int r; + + r = new_transient_unit_from_message(bus, + message, + userdata, + error, + &u, + &mode, + true); + + if (r != 0) + return r; + + path = unit_dbus_path(u); + if (!path) + return -ENOMEM; + + return sd_bus_reply_method_return(message, "o", path); +} + +static int method_start_transient_unit(sd_bus *bus, + sd_bus_message *message, + void *userdata, + sd_bus_error *error) { + JobMode mode; + Unit *u = NULL; + int r; + + r = new_transient_unit_from_message(bus, + message, + userdata, + error, + &u, + &mode, + false); + if (r != 0) + return r; + /* Finally, start it */ - return bus_unit_queue_job(bus, message, u, JOB_START, mode, false, error); + return bus_unit_queue_job(bus, + message, + u, + JOB_START, + mode, + false, + error); } static int method_get_job(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { @@ -1881,6 +1955,7 @@ const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_METHOD("KillUnit", "ssi", NULL, method_kill_unit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("ResetFailedUnit", "s", NULL, method_reset_failed_unit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetUnitProperties", "sba(sv)", NULL, method_set_unit_properties, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("NewTransientUnit", "ssa(sv)a(sa(sv))", "o", method_new_transient_unit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("StartTransientUnit", "ssa(sv)a(sa(sv))", "o", method_start_transient_unit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("GetJob", "u", "o", method_get_job, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CancelJob", "u", NULL, method_cancel_job, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf index 3e13825..2b8648e 100644 --- a/src/core/org.freedesktop.systemd1.conf +++ b/src/core/org.freedesktop.systemd1.conf @@ -144,6 +144,10 @@ <allow send_destination="org.freedesktop.systemd1" send_interface="org.freedesktop.systemd1.Manager" + send_member="NewTransientUnit"/> + + <allow send_destination="org.freedesktop.systemd1" + send_interface="org.freedesktop.systemd1.Manager" send_member="StartTransientUnit"/> <allow send_destination="org.freedesktop.systemd1" diff --git a/src/core/service.c b/src/core/service.c index 395e0ca..52c0981 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -467,6 +467,14 @@ static int service_load(Unit *u) { } } + /* If transient service unit is generated by NewTransientUnit + * then this unit will be removed by gabage collector + * soon. But we want this unit is remained until be actived by + * other. And we don't know who is the other. So just prevent + * gabage collected. */ + if (u->transient) + u->no_gc = true; + return service_verify(s); } @@ -1642,6 +1650,10 @@ static int service_start(Unit *u) { assert(s); + /* Make sure be gabage collected transient service unit. */ + if (u->transient) + u->no_gc = false; + /* We cannot fulfill this request right now, try again later * please! */ if (s->state == SERVICE_STOP || -- 1.9.3 _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel