[systemd-devel] [PATCH 1/3] dbus: introduce new method call NewTransientUnit

WaLyong Cho walyong.cho at samsung.com
Mon Oct 6 22:20:08 PDT 2014


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



More information about the systemd-devel mailing list