summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2010-05-09 23:53:52 +0200
committerLennart Poettering <lennart@poettering.net>2010-05-09 23:53:52 +0200
commit1137a57c2677936bab56c26591a42c93a5e670a8 (patch)
tree52a4b49bae3558526bcede18fbc3aba48857a967
parent6e620becc8543e9ea8381fcd779dd932c2464749 (diff)
environment: allow control of the environment block via D-Bus
-rw-r--r--dbus-manager.c55
-rw-r--r--dbus.c49
-rw-r--r--dbus.h2
-rw-r--r--execute.c3
-rw-r--r--execute.h1
-rw-r--r--manager.c5
-rw-r--r--manager.h2
-rw-r--r--missing.h1
-rw-r--r--mount.c1
-rw-r--r--service.c1
-rw-r--r--socket.c1
-rw-r--r--strv.c67
-rw-r--r--strv.h1
-rw-r--r--systemctl.vala48
-rw-r--r--systemd-interfaces.vala5
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);
diff --git a/dbus.c b/dbus.c
index 0054d1519e..6ed659a239 100644
--- a/dbus.c
+++ b/dbus.c
@@ -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;
+}
diff --git a/dbus.h b/dbus.h
index 47a6639b43..51b71eac61 100644
--- a/dbus.h
+++ b/dbus.h
@@ -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
diff --git a/execute.c b/execute.c
index 7192abfffb..a7775a4ea9 100644
--- a/execute.c
+++ b/execute.c
@@ -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;
}
diff --git a/execute.h b/execute.h
index f820d56cb8..5c2d15787e 100644
--- a/execute.h
+++ b/execute.h
@@ -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,
diff --git a/manager.c b/manager.c
index 1691719a66..a4696d6e99 100644
--- a/manager.c
+++ b/manager.c
@@ -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);
diff --git a/manager.h b/manager.h
index b6b6926bd8..a6500ac600 100644
--- a/manager.h
+++ b/manager.h
@@ -177,6 +177,8 @@ struct Manager {
char **sysvinit_path;
char **sysvrcnd_path;
+ char **environment;
+
usec_t boot_timestamp;
/* Data specific to the device subsystem */
diff --git a/missing.h b/missing.h
index a8b5e80b07..7db7d7d2e8 100644
--- a/missing.h
+++ b/missing.h
@@ -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
diff --git a/mount.c b/mount.c
index c989cddabf..ce99af0778 100644
--- a/mount.c
+++ b/mount.c
@@ -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,
diff --git a/service.c b/service.c
index 45f7110bd1..b208e9e0bc 100644
--- a/service.c
+++ b/service.c
@@ -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,
diff --git a/socket.c b/socket.c
index 755bc598da..402eeaf628 100644
--- a/socket.c
+++ b/socket.c
@@ -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,
diff --git a/strv.c b/strv.c
index ed5755a0d1..a749096f9a 100644
--- a/strv.c
+++ b/strv.c
@@ -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;
+}
diff --git a/strv.h b/strv.h
index 9cd8732b4f..f0be83dd59 100644
--- a/strv.h
+++ b/strv.h
@@ -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);