2 * dbus-update-activation-environment - update D-Bus, and optionally
3 * systemd, activation environment
5 * Copyright © 2014-2015 Collabora Ltd.
7 * Permission is hereby granted, free of charge, to any person
8 * obtaining a copy of this software and associated documentation files
9 * (the "Software"), to deal in the Software without restriction,
10 * including without limitation the rights to use, copy, modify, merge,
11 * publish, distribute, sublicense, and/or sell copies of the Software,
12 * and to permit persons to whom the Software is furnished to do so,
13 * subject to the following conditions:
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34 #ifdef HAVE_SYSEXITS_H
35 # include <sysexits.h>
38 #include <dbus/dbus.h>
42 # include <sys/stat.h>
43 # include <sys/types.h>
46 #include "tool-common.h"
48 #define PROGNAME "dbus-update-activation-environment"
54 #ifndef EX_UNAVAILABLE
55 # define EX_UNAVAILABLE 69
63 /* The Windows C runtime uses a different name */
64 #define environ _environ
65 #elif defined(__APPLE__)
66 # include <crt_externs.h>
67 # define environ (*_NSGetEnviron ())
68 #elif HAVE_DECL_ENVIRON && defined(HAVE_UNISTD_H)
71 extern char **environ;
74 /* we don't really have anything useful to say about the stage at which we
76 #define oom() tool_oom ("updating environment")
78 static dbus_bool_t verbose = FALSE;
80 static void say (const char *format, ...) _DBUS_GNUC_PRINTF (1, 2);
83 say (const char *format,
91 fprintf (stderr, "%s: ", PROGNAME);
92 va_start (ap, format);
93 vfprintf (stderr, format, ap);
100 systemd_user_running (void)
102 char *xdg_runtime_dir = getenv ("XDG_RUNTIME_DIR");
105 dbus_bool_t ret = FALSE;
107 if (xdg_runtime_dir == NULL)
110 /* Assume that XDG_RUNTIME_DIR/systemd exists if and only if
111 * "systemd --user" is running. It's OK to use asprintf() here
112 * because we know we're on Linux. */
113 if (asprintf (&path, "%s/systemd", xdg_runtime_dir) < 0)
116 if (stat (path, &buf) == 0)
125 main (int argc, char **argv)
127 DBusConnection *conn;
130 DBusError error = DBUS_ERROR_INIT;
131 DBusMessageIter msg_iter;
132 DBusMessageIter array_iter;
134 int first_non_option = argc;
135 dbus_bool_t all = FALSE;
137 DBusMessage *sd_msg = NULL;
138 DBusMessageIter sd_msg_iter;
139 DBusMessageIter sd_array_iter;
140 dbus_bool_t systemd = FALSE;
143 for (i = 1; i < argc; i++)
145 if (argv[i][0] != '-')
147 first_non_option = i;
150 else if (strcmp (argv[i], "--") == 0)
152 first_non_option = i + 1;
155 else if (strcmp (argv[i], "--all") == 0)
159 else if (strcmp (argv[i], "--systemd") == 0)
164 say ("not on Linux, ignoring --systemd argument");
167 else if (strcmp (argv[i], "--verbose") == 0)
174 "%1$s: update environment variables that will be set for D-Bus\n"
175 " session services\n"
177 "%1$s [options] VAR[=VAL] [VAR2[=VAL2] ...]\n"
178 " Add specified variables to D-Bus activation environment.\n"
179 " If omitted, values are taken from current environment;\n"
180 " variables not found in the environment are ignored.\n"
182 " Add entire current environment to D-Bus activation\n"
188 " Upload all environment variables.\n"
190 " Also update the 'systemd --user' environment\n"
200 if (all && first_non_option < argc)
202 fprintf (stderr, "%s: error: --all cannot be used with VAR or "
203 "VAR=VAL arguments\n", PROGNAME);
207 conn = dbus_bus_get (DBUS_BUS_SESSION, &error);
212 "%s: error: unable to connect to D-Bus: %s\n", PROGNAME,
217 msg = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
218 DBUS_INTERFACE_DBUS, "UpdateActivationEnvironment");
223 dbus_message_iter_init_append (msg, &msg_iter);
225 if (!dbus_message_iter_open_container (&msg_iter, DBUS_TYPE_ARRAY,
226 "{ss}", &array_iter))
232 if (!systemd_user_running ())
234 /* This is only best-effort. */
235 say ("systemd --user not found, ignoring --systemd argument");
242 sd_msg = dbus_message_new_method_call ("org.freedesktop.systemd1",
243 "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager",
249 dbus_message_iter_init_append (sd_msg, &sd_msg_iter);
251 if (!dbus_message_iter_open_container (&sd_msg_iter, DBUS_TYPE_ARRAY,
252 "s", &sd_array_iter))
257 for (i = all ? 0 : first_non_option;
258 all ? environ[i] != NULL : i < argc;
265 DBusMessageIter pair_iter;
277 if (!dbus_validate_utf8 (var, NULL))
279 /* var is either of the form VAR or VAR=VAL */
281 "%s: warning: environment variable not UTF-8: %s\n",
286 eq = strchr (copy, '=');
292 /* items in the environment block should be of the form
295 "%s: warning: environment variable without '=': %s\n",
301 /* items on the command-line may be of the form VAR
302 * in which case we infer the value from the environment */
307 /* nothing to be done here */
311 if (!dbus_validate_utf8 (val, NULL))
314 "%s: warning: environment variable not UTF-8: %s=%s\n",
322 /* split VAR=VAL into VAR and VAL */
332 /* recombine if necessary */
333 if (asprintf (&combined, "%s=%s", copy, val) < 0)
336 if (!dbus_message_iter_append_basic (&sd_array_iter,
337 DBUS_TYPE_STRING, &combined))
344 if (!dbus_message_iter_open_container (&array_iter,
345 DBUS_TYPE_DICT_ENTRY, NULL, &pair_iter))
348 say ("setting %s=%s", copy, val);
350 if (!dbus_message_iter_append_basic (&pair_iter, DBUS_TYPE_STRING,
354 if (!dbus_message_iter_append_basic (&pair_iter, DBUS_TYPE_STRING,
358 if (!dbus_message_iter_close_container (&array_iter, &pair_iter))
365 if (!dbus_message_iter_close_container (&msg_iter, &array_iter))
370 !dbus_message_iter_close_container (&sd_msg_iter, &sd_array_iter))
374 reply = dbus_connection_send_with_reply_and_block (conn, msg, -1, &error);
379 "%s: error sending to dbus-daemon: %s: %s\n",
380 PROGNAME, error.name, error.message);
381 exit (EX_UNAVAILABLE);
384 if (dbus_set_error_from_message (&error, msg) ||
385 !dbus_message_get_args (msg, &error, DBUS_TYPE_INVALID))
388 "%s: error from dbus-daemon: %s: %s\n",
389 PROGNAME, error.name, error.message);
390 exit (EX_UNAVAILABLE);
393 dbus_message_unref (reply);
398 reply = dbus_connection_send_with_reply_and_block (conn, sd_msg, -1,
401 /* non-fatal, the main purpose of this thing is to communicate
402 * with dbus-daemon */
406 "%s: warning: error sending to systemd: %s: %s\n",
407 PROGNAME, error.name, error.message);
409 else if (dbus_set_error_from_message (&error, msg) ||
410 !dbus_message_get_args (msg, &error, DBUS_TYPE_INVALID))
413 "%s: warning: error from systemd: %s: %s\n",
414 PROGNAME, error.name, error.message);
418 dbus_message_unref (reply);
420 dbus_message_unref (sd_msg);
421 dbus_error_free (&error);
425 dbus_message_unref (msg);
426 dbus_connection_unref (conn);