Re: [systemd-devel] Questions regarding dbus started via systemd --user

Simon McVittie <simon.mcvittie-ZGY8ohtN/[email protected]>
Newsgroups gmane.comp.freedesktop.dbus,gmane.comp.sysutils.systemd.devel
Organization Collabora Ltd.
Message-ID <[email protected]>
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 [email protected] 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

_______________________________________________
dbus mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dbus
debian-dbus-update-activation-environment.c (text/x-csrc, 5.1 KB)
#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;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.