diff options
author | Lennart Poettering <lennart@poettering.net> | 2010-05-09 23:53:52 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2010-05-09 23:53:52 +0200 |
commit | 1137a57c2677936bab56c26591a42c93a5e670a8 (patch) | |
tree | 52a4b49bae3558526bcede18fbc3aba48857a967 | |
parent | 6e620becc8543e9ea8381fcd779dd932c2464749 (diff) |
environment: allow control of the environment block via D-Bus
-rw-r--r-- | dbus-manager.c | 55 | ||||
-rw-r--r-- | dbus.c | 49 | ||||
-rw-r--r-- | dbus.h | 2 | ||||
-rw-r--r-- | execute.c | 3 | ||||
-rw-r--r-- | execute.h | 1 | ||||
-rw-r--r-- | manager.c | 5 | ||||
-rw-r--r-- | manager.h | 2 | ||||
-rw-r--r-- | missing.h | 1 | ||||
-rw-r--r-- | mount.c | 1 | ||||
-rw-r--r-- | service.c | 1 | ||||
-rw-r--r-- | socket.c | 1 | ||||
-rw-r--r-- | strv.c | 67 | ||||
-rw-r--r-- | strv.h | 1 | ||||
-rw-r--r-- | systemctl.vala | 48 | ||||
-rw-r--r-- | systemd-interfaces.vala | 5 |
15 files changed, 225 insertions, 17 deletions
diff --git a/dbus-manager.c b/dbus-manager.c index 47fb403f11..4b3b45e60c 100644 --- a/dbus-manager.c +++ b/dbus-manager.c @@ -24,6 +24,7 @@ #include "dbus.h" #include "log.h" #include "dbus-manager.h" +#include "strv.h" #define INTROSPECTION_BEGIN \ DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ @@ -59,6 +60,12 @@ " <method name=\"Reload\"/>" \ " <method name=\"Reexecute\"/>" \ " <method name=\"Exit\"/>" \ + " <method name=\"SetEnvironment\">" \ + " <arg name=\"names\" type=\"as\" direction=\"in\"/>" \ + " </method>" \ + " <method name=\"UnsetEnvironment\">" \ + " <arg name=\"names\" type=\"as\" direction=\"in\"/>" \ + " </method>" \ " <signal name=\"UnitNew\">" \ " <arg name=\"id\" type=\"s\"/>" \ " <arg name=\"unit\" type=\"o\"/>" \ @@ -82,6 +89,7 @@ " <property name=\"LogTarget\" type=\"s\" access=\"read\"/>" \ " <property name=\"NNames\" type=\"u\" access=\"read\"/>" \ " <property name=\"NJobs\" type=\"u\" access=\"read\"/>" \ + " <property name=\"Environment\" type=\"as\" access=\"read\"/>" \ " </interface>" \ BUS_PROPERTIES_INTERFACE \ BUS_INTROSPECTABLE_INTERFACE @@ -162,6 +170,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection { "org.freedesktop.systemd1.Manager", "LogTarget", bus_manager_append_log_target, "s", NULL }, { "org.freedesktop.systemd1.Manager", "NNames", bus_manager_append_n_names, "u", NULL }, { "org.freedesktop.systemd1.Manager", "NJobs", bus_manager_append_n_jobs, "u", NULL }, + { "org.freedesktop.systemd1.Manager", "Environment", bus_property_append_strv, "as", m->environment }, { NULL, NULL, NULL, NULL, NULL } }; @@ -572,6 +581,52 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection m->exit_code = MANAGER_EXIT; + } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) { + char **l = NULL, **e = NULL; + + if ((r = bus_parse_strv(message, &l)) < 0) { + if (r == -ENOMEM) + goto oom; + + return bus_send_error_reply(m, message, NULL, r); + } + + e = strv_env_merge(m->environment, l, NULL); + strv_free(l); + + if (!e) + goto oom; + + if (!(reply = dbus_message_new_method_return(message))) { + strv_free(e); + goto oom; + } + + strv_free(m->environment); + m->environment = e; + + } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) { + char **l = NULL, **e = NULL; + + if ((r = bus_parse_strv(message, &l)) < 0) { + if (r == -ENOMEM) + goto oom; + + return bus_send_error_reply(m, message, NULL, r); + } + + e = strv_env_delete(m->environment, l, NULL); + strv_free(l); + + if (!e) + goto oom; + + if (!(reply = dbus_message_new_method_return(message))) + goto oom; + + strv_free(m->environment); + m->environment = e; + } else return bus_default_message_handler(m, message, NULL, properties); @@ -1085,3 +1085,52 @@ int bus_property_append_int32(Manager *m, DBusMessageIter *i, const char *proper return 0; } + +int bus_parse_strv(DBusMessage *m, char ***_l) { + DBusMessageIter iter, sub; + unsigned n = 0, i = 0; + char **l; + + assert(m); + assert(_l); + + if (!dbus_message_iter_init(m, &iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_recurse(&iter, &sub); + + while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { + n++; + dbus_message_iter_next(&sub); + } + + if (!(l = new(char*, n+1))) + return -ENOMEM; + + assert_se(dbus_message_iter_init(m, &iter)); + dbus_message_iter_recurse(&iter, &sub); + + while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { + const char *s; + + assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING); + dbus_message_iter_get_basic(&sub, &s); + + if (!(l[i++] = strdup(s))) { + strv_free(l); + return -ENOMEM; + } + + dbus_message_iter_next(&sub); + } + + assert(i == n); + l[i] = NULL; + + if (_l) + *_l = l; + + return 0; +} @@ -102,4 +102,6 @@ int bus_property_append_uint64(Manager *m, DBusMessageIter *i, const char *prope return 0; \ } +int bus_parse_strv(DBusMessage *m, char ***_l); + #endif @@ -724,6 +724,7 @@ int exec_spawn(ExecCommand *command, char **argv, const ExecContext *context, int fds[], unsigned n_fds, + char **environment, bool apply_permissions, bool apply_chroot, bool confirm_spawn, @@ -1034,7 +1035,7 @@ int exec_spawn(ExecCommand *command, goto fail; } - if (!(final_env = strv_env_merge(environ, our_env, context->environment, NULL))) { + if (!(final_env = strv_env_merge(environment, our_env, context->environment, NULL))) { r = EXIT_MEMORY; goto fail; } @@ -182,6 +182,7 @@ int exec_spawn(ExecCommand *command, char **argv, const ExecContext *context, int fds[], unsigned n_fds, + char **environment, bool apply_permissions, bool apply_chroot, bool confirm_spawn, @@ -51,6 +51,7 @@ #include "unit-name.h" #include "dbus-unit.h" #include "dbus-job.h" +#include "missing.h" /* As soon as 16 units are in our GC queue, make sure to run a gc sweep */ #define GC_QUEUE_ENTRIES_MAX 16 @@ -336,6 +337,9 @@ int manager_new(ManagerRunningAs running_as, bool confirm_spawn, Manager **_m) { m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = m->dev_autofs_fd = -1; m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */ + if (!(m->environment = strv_copy(environ))) + goto fail; + if (!(m->units = hashmap_new(string_hash_func, string_compare_func))) goto fail; @@ -544,6 +548,7 @@ void manager_free(Manager *m) { strv_free(m->unit_path); strv_free(m->sysvinit_path); strv_free(m->sysvrcnd_path); + strv_free(m->environment); free(m->cgroup_controller); free(m->cgroup_hierarchy); @@ -177,6 +177,8 @@ struct Manager { char **sysvinit_path; char **sysvrcnd_path; + char **environment; + usec_t boot_timestamp; /* Data specific to the device subsystem */ @@ -35,5 +35,4 @@ static inline int pivot_root(const char *new_root, const char *put_old) { return syscall(SYS_pivot_root, new_root, put_old); } - #endif @@ -490,6 +490,7 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) { NULL, &m->exec_context, NULL, 0, + m->meta.manager->environment, true, true, UNIT(m)->meta.manager->confirm_spawn, @@ -1187,6 +1187,7 @@ static int service_spawn( argv, &s->exec_context, fds, n_fds, + s->meta.manager->environment, apply_permissions, apply_chroot, UNIT(s)->meta.manager->confirm_spawn, @@ -578,6 +578,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) { argv, &s->exec_context, NULL, 0, + s->meta.manager->environment, true, true, UNIT(s)->meta.manager->confirm_spawn, @@ -434,3 +434,70 @@ fail: return NULL; } + +static bool env_match(const char *t, const char *pattern) { + assert(t); + assert(pattern); + + /* pattern a matches string a + * a matches a= + * a matches a=b + * a= matches a= + * a=b matches a=b + * a= does not match a + * a=b does not match a= + * a=b does not match a + * a=b does not match a=c */ + + if (streq(t, pattern)) + return true; + + if (!strchr(pattern, '=')) { + size_t l = strlen(pattern); + + return strncmp(t, pattern, l) == 0 && t[l] == '='; + } + + return false; +} + +char **strv_env_delete(char **x, ...) { + size_t n = 0, i = 0; + char **l, **k, **r, **j; + va_list ap; + + /* Deletes every entry fromx that is mentioned in the other + * string lists */ + + n = strv_length(x); + + if (!(r = new(char*, n+1))) + return NULL; + + STRV_FOREACH(k, x) { + va_start(ap, x); + + while ((l = va_arg(ap, char**))) + STRV_FOREACH(j, l) + if (env_match(*k, *j)) + goto delete; + + va_end(ap); + + if (!(r[i++] = strdup(*k))) { + strv_free(r); + return NULL; + } + + continue; + + delete: + va_end(ap); + } + + r[i] = NULL; + + assert(i <= n); + + return r; +} @@ -54,6 +54,7 @@ char **strv_split_quoted(const char *s) _malloc; char *strv_join(char **l, const char *separator) _malloc; char **strv_env_merge(char **x, ...) _sentinel; +char **strv_env_delete(char **x, ...) _sentinel; #define STRV_FOREACH(s, l) \ for ((s) = (l); (s) && *(s); (s)++) diff --git a/systemctl.vala b/systemctl.vala index 388ab7d505..ddbede94b6 100644 --- a/systemctl.vala +++ b/systemctl.vala @@ -74,21 +74,24 @@ int main (string[] args) { context.add_main_entries(entries, null); context.set_description( "Commands:\n" + - " list-units List units\n" + - " list-jobs List jobs\n" + - " clear-jobs Cancel all jobs\n" + - " load [NAME...] Load one or more units\n" + - " cancel [JOB...] Cancel one or more jobs\n" + - " start [NAME...] Start on or more units\n" + - " stop [NAME...] Stop on or more units\n" + - " enter [NAME] Start one unit and stop all others\n" + - " restart [NAME...] Restart on or more units\n" + - " reload [NAME...] Reload on or more units\n" + - " monitor Monitor unit/job changes\n" + - " dump Dump server status\n" + - " snapshot [NAME] Create a snapshot\n" + - " daemon-reload Reload daemon configuration\n" + - " daemon-reexecute Reexecute daemon\n"); + " list-units List units\n" + + " list-jobs List jobs\n" + + " clear-jobs Cancel all jobs\n" + + " load [NAME...] Load one or more units\n" + + " cancel [JOB...] Cancel one or more jobs\n" + + " start [NAME...] Start on or more units\n" + + " stop [NAME...] Stop on or more units\n" + + " enter [NAME] Start one unit and stop all others\n" + + " restart [NAME...] Restart on or more units\n" + + " reload [NAME...] Reload on or more units\n" + + " monitor Monitor unit/job changes\n" + + " dump Dump server status\n" + + " snapshot [NAME] Create a snapshot\n" + + " daemon-reload Reload daemon configuration\n" + + " daemon-reexecute Reexecute daemon\n" + + " show-environment Dump environment\n" + + " set-environment [NAME=VALUE...] Set one or more environment variables\n" + + " unset-environment [NAME...] Unset one or more environment variables\n"); try { context.parse(ref args); @@ -245,6 +248,7 @@ int main (string[] args) { } else if (args[1] == "dump") stdout.puts(manager.dump()); + else if (args[1] == "snapshot") { ObjectPath p = manager.create_snapshot(args.length > 2 ? args[2] : ""); @@ -255,12 +259,26 @@ int main (string[] args) { "org.freedesktop.systemd1.Unit") as Unit; stdout.printf("%s\n", u.id); + } else if (args[1] == "daemon-reload") manager.reload(); + else if (args[1] == "daemon-reexecute" || args[1] == "daemon-reexec") manager.reexecute(); + else if (args[1] == "daemon-exit") manager.exit(); + + else if (args[1] == "show-environment") { + foreach(var x in manager.environment) + stderr.printf("%s\n", x); + + } else if (args[1] == "set-environment") + manager.set_environment(args[2:args.length]); + + else if (args[1] == "unset-environment") + manager.unset_environment(args[2:args.length]); + else { stderr.printf("Unknown command %s.\n", args[1]); return 1; diff --git a/systemd-interfaces.vala b/systemd-interfaces.vala index 045bb55047..a95dc01f55 100644 --- a/systemd-interfaces.vala +++ b/systemd-interfaces.vala @@ -43,6 +43,8 @@ public interface Manager : DBus.Object { ObjectPath unit_path; } + public abstract string[] environment { owned get; } + public abstract UnitInfo[] list_units() throws DBus.Error; public abstract JobInfo[] list_jobs() throws DBus.Error; @@ -63,6 +65,9 @@ public interface Manager : DBus.Object { public abstract ObjectPath create_snapshot(string name = "", bool cleanup = false) throws DBus.Error; + public abstract void set_environment(string[] names) throws DBus.Error; + public abstract void unset_environment(string[] names) throws DBus.Error; + public abstract signal void unit_new(string id, ObjectPath path); public abstract signal void unit_removed(string id, ObjectPath path); public abstract signal void job_new(uint32 id, ObjectPath path); |