Adding D-Bus mailing list to Cc; questions about the user bus are
significant for D-Bus as well as for systemd --user, and modifications
of dbus-launch doubly so.

On 08/01/15 11:55, Colin Guthrie wrote:
> I've got a modified dbus-launch that can be slotted in nicely

I'm happy for dbus to get better integration with systemd --user (and I
plan to work on it myself at some point) but I would much prefer
dbus-launch to not be the way it happens.

Modifying dbus-launch is fine for experimentation, but I would really
like it to become a historical curiosity for people with bizarre
multi-machine X11. It's fairly horrible code and there has never really
been a canonical list of what is and isn't intended to work. Instead of
altering dbus-launch, I would very much prefer to give
libdbus/GDBus/etc. a better thing they can try before calling
dbus-launch; I believe the current suggestion is looking for a Unix
socket in XDG_RUNTIME_DIR/bus (formerly
XDG_RUNTIME_DIR/dbus/user_bus_socket like in user-session-units).

In particular, on Wayland systems, I would like dbus-launch to be
something that is not relevant and never has been.

Related:

https://bugs.freedesktop.org/show_bug.cgi?id=61301
https://bugs.freedesktop.org/show_bug.cgi?id=61303
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=681241
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=774626

> It also pokes systemd --user with the environment
> too.

I attach a prototype of a standalone dbus-update-activation-environment
tool, left over from last time I looked into this. It pokes all of its
environment variables into both dbus-daemon (required) and "systemd
--user" (if present), then execs its arguments. It is untested, and
should probably upload variables specified by command-line arguments
rather than all of them, and exit 0 rather than exec'ing an argument;
but it's a start.

I think having the X session or PAM stack do something similar to that
is likely to be a better approach to compatibility with code that
assumes environment variables propagate through the whole session (e.g.
Debian's Xsession.d) than having dbus-launch grow yet more magic.

The observant will notice that I have not attached it to a feature
request or anything; that's because it probably doesn't work yet, I got
halfway through prototyping it.

> The issue I currently have is that the dbus daemon itself is now part of
> the user@.service cgroup and NOT part of the session cgroup

I think that's unavoidable; if we want any services that exist outside
the scope of an individual login session, then this is how they are
going to have to work.

> In GNOME for example, gnome-terminal is started via dbus activation
> (gnome-terminal-server).

I think that's OK. Anything "in the foreground" whose lifetime is tied
to the shell will die from SIGHUP when gnome-terminal exits because the
terminal got disconnected from X11. Meanwhile, anything that has done
the usual shell things to go to the background, or is in a screen or
tmux, ends up in the same situation as a D-Bus session service or a
systemd user service: it survives for exactly as long as systemd --user
(which might persist after last-logout, or not, according to sysadmin
configuration) and then dies. Either way, it seems like what you want?

As I understand it, the supported situations are "systemd --user lasts
longer than the X11 session" (for normal use) and "systemd --user lasts
exactly as long as the X11 session" (for shared computers where the
sysadmin wants to avoid non-session processes hanging around), but not
"systemd --user exits before the X11 session does".

    S
#include <errno.h>
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>

#include <dbus/dbus.h>

#define THIS "debian-dbus-upload-environment"

extern char **environ;

static void oom (void) __attribute__ ((__noreturn__));

static void
oom (void)
{
  fprintf (stderr, "%s: out of memory\n", THIS);
  _exit (EX_UNAVAILABLE);
}

static dbus_bool_t
systemd_user_running (void)
{
  char *xdg_runtime_dir = getenv ("XDG_RUNTIME_DIR");
  char *path;
  struct stat buf;

  if (xdg_runtime_dir == NULL)
    return FALSE;

  /* assume that XDG_RUNTIME_DIR/systemd exists if and only if
   * "systemd --user" is running */
  if (asprintf (&path, "%s/systemd", xdg_runtime_dir) < 0)
    oom ();

  if (stat (path, &buf) < 0)
    return FALSE;

  free (path);

  return TRUE;
}

int
main (int argc, char **argv)
{
  char **next = NULL;
  char **envp;
  DBusConnection *conn;
  DBusMessage *msg;
  DBusMessage *sd_msg;
  DBusMessage *reply;
  DBusError error = DBUS_ERROR_INIT;
  DBusMessageIter msg_iter;
  DBusMessageIter sd_msg_iter;
  DBusMessageIter array_iter;
  DBusMessageIter sd_array_iter;
  int i;
  struct stat stat_buf;

  for (i = 1; i < argc; i++)
    {
      if (strcmp (argv[i], "--") == 0 && (i + 1) < argc)
        {
          next = argv + i + 1;
          break;
        }
      else
        {
          fprintf (stderr,
              "%s: usage:\n"
              "%s [-- next-executable [arguments...]]\n",
              THIS, THIS);
          return EX_USAGE;
        }
    }

  conn = dbus_bus_get (DBUS_BUS_SESSION, &error);

  if (conn == NULL)
    {
      fprintf (stderr,
          "%s: error: unable to connect to D-Bus: %s\n", THIS, error.message);
      return EX_OSERR;
    }

  msg = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
      DBUS_INTERFACE_DBUS, "UpdateActivationEnvironment");

  if (msg == NULL)
    oom ();

  sd_msg = dbus_message_new_method_call ("org.freedesktop.systemd1",
      "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager",
      "SetEnvironment");

  if (sd_msg == NULL)
    oom ();

  dbus_message_iter_init_append (msg, &msg_iter);
  dbus_message_iter_open_container (&msg_iter, DBUS_TYPE_ARRAY,
      "{ss}", &array_iter);

  dbus_message_iter_open_container (&sd_msg_iter, DBUS_TYPE_ARRAY,
      "{ss}", &sd_array_iter);

  for (envp = environ; *envp != NULL; envp++)
    {
      char *copy;
      char *eq;
      char *val;
      DBusMessageIter pair_iter;

      if (!dbus_validate_utf8 (*envp, NULL))
        {
          fprintf (stderr,
              "%s: warning: environment variable not UTF-8: %s\n",
              THIS, *envp);
          continue;
        }

      copy = strdup (*envp);

      if (copy == NULL)
        oom ();

      eq = strchr (copy, '=');

      if (eq == NULL)
        {
          fprintf (stderr,
              "%s: warning: environment variable without '=': %s\n",
              THIS, copy);
          free (copy);
          continue;
        }

      *eq = '\0';
      val = eq + 1;

      if (!dbus_message_iter_append_basic (&sd_array_iter, DBUS_TYPE_STRING,
              envp))
        oom ();

      if (!dbus_message_iter_open_container (&array_iter,
              DBUS_TYPE_DICT_ENTRY, NULL, &pair_iter))
        oom ();

      if (!dbus_message_iter_append_basic (&pair_iter, DBUS_TYPE_STRING,
              &copy))
        oom ();

      if (!dbus_message_iter_append_basic (&pair_iter, DBUS_TYPE_STRING,
              &val))
        oom ();

      if (!dbus_message_iter_close_container (&array_iter, &pair_iter))
        oom ();

      free (copy);
    }

  if (!dbus_message_iter_close_container (&msg_iter, &array_iter))
    oom ();

  if (!dbus_message_iter_close_container (&sd_msg_iter, &sd_array_iter))
    oom ();

  reply = dbus_connection_send_with_reply_and_block (conn, msg, -1, &error);

  if (reply == NULL)
    {
      fprintf (stderr,
          "%s: error sending to dbus-daemon: %s: %s\n",
          THIS, error.name, error.message);
      return EX_UNAVAILABLE;
    }

  if (!dbus_message_get_args (msg, &error, DBUS_TYPE_INVALID))
    {
      fprintf (stderr,
          "%s: error from dbus-daemon: %s: %s\n",
          THIS, error.name, error.message);
      return EX_UNAVAILABLE;
    }

  dbus_message_unref (reply);

  if (systemd_user_running ())
    {
      reply = dbus_connection_send_with_reply_and_block (conn, sd_msg, -1,
          &error);

      /* non-fatal, the main purpose of this thing is to communicate
       * with dbus-daemon */
      if (reply == NULL)
        {
          fprintf (stderr,
              "%s: error sending to systemd: %s: %s\n",
              THIS, error.name, error.message);
        }
      else if (!dbus_message_get_args (msg, &error, DBUS_TYPE_INVALID))
        {
          fprintf (stderr,
              "%s: error from systemd: %s: %s\n",
              THIS, error.name, error.message);
        }
    }

  if (next != NULL)
    {
      execvp (next[0], next);

      fprintf (stderr,
          "%s: error: cannot execute %s: %s\n",
          THIS, next[0], strerror (errno));
      return EX_UNAVAILABLE;
    }

  return 0;
}

_______________________________________________
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel

Reply via email to