[systemd-devel] systemctl --user

Damien Robert Damien.Robert__sent at normalesup.org
Thu Aug 9 09:47:37 PDT 2012


>From Lennart Poettering, the Fri 03 Aug 2012 at 21:49:11 (+0200):
> > However, this is not the case when running a systemd --user, then systemctl
> > --user foo.service will not print the corresponding journal logs, even if
> > there are some. So here is to a feature request :)
> 
> This definitely makes snese. Added to the TODO list now.

Great!
 
> > so something like journalctl _SYSTEMD_CGROUP='the right regular expression'
> > could print them, but journalctl does not seem to support regular
> > expression yet.
> 
> regexes are really hard to index by, so I doubt we will support them.

You are right, it is probably more of the resort of a perl script to parse
the output of journalctl -o verbose. I'll try to write one.
 
> The journal bits in "systemctl status" are currently completely
> unprepared for --user, we really need to fix that.

Ok. I have to say that even if systemd --user is not yet completely ironed out,
it is really great and it allowed me to dismiss runsvdir that I was using
previously to launch my user services.

I will describe here my setup if other people are interested (or if you see
a better way to do it!), along with some bugs I found and other feature
requests that could be nice.

So when I log in, there are different types of services that I want to
launch:
1) services that I want always running (and if they exit, I want systemd to
   restart them): think offlineimap, mpd, ...
2) services that are linked to my current X session, think things you would
   put in ~/.xprofile or ~/.config/autostart like conky, ... Here I want
   these services to be restarted by systemd, except when I am closing the
   X session. And if I have several X session, I want one such service  by
   X session.
3) Eventually you could imagine services like (1), but that I want to stop
   whenever I have no active sessions anymore. Since I have no use such
   services, I have not implemented that.

So (1) is really easy, this is exactly what systemd is for. I regroup all
such services under session.target. The nice thing is that (2) is quite
easy to do using templates, whereas I could not do that previously with 
runsvdir. So I have a xsession at .target:
  [Unit]
  Description=xsession on display %I
  Wants=session.target
  AllowIsolate=yes
where I put my X session services (not that it automatically pull the
session services). For instance here is my conky at .service:

  [Unit]
  Description=conky on display %I 
  BindsTo=xsession at .target
  ConditionPathExists=%h/.conkyrc
  
  [Service]
  Environment=DISPLAY=%I
  ExecStart=/usr/bin/conky
  Restart=always
  RestartSec=1
  StandardOutput=null
  
  [Install]
  WantedBy=xsession at .target
  Also=xwatch at .service

So when I login, I launch systemctl --user start xsession@$DISPLAY.target
by putting this code in my ~/.xprofile:

  if [ -x /bin/systemd ]; then
    xhost + SI:localuser:`id -u -n`
    if [ systemctl --user --no-pager 2>/dev/null ]; then
       systemctl --no-block --user  start "xsession@${DISPLAY}.target"
    else
        exec systemd --user --unit="xsession@${DISPLAY}.target" &
    fi
  fi

Some explanations: before running systemctl --user, I want to make sure
that systemd --user is running, or if not launch it. That's what the 
  if [ systemctl --user --no-pager 2>/dev/null ]; 
is for.

A note about the xhost line: if I log on a X session with a new $DISPLAY,
since systemd is running from my first session, it may happen that the new
X session has not the same XDG_SESSION_COOKIE, and there will be
authorization problems when programs try to connect to the new X display.
The xhost line allow all programs with my uid to connect to the new X
session (it is there by default with gdm, but not when I log using startx
from a console).

Now the only thing left to do is to launch systemctl --user stop
xsession@$DISPLAY.target when I leave the current X session.
Because of the   BindsTo=xsession at .target, it will close the conky running
inside it. That is what the xwatch at .service is for:

  [Unit]
  Description=Watch for X on display %I
  BindsTo=xsession at .target
  
  [Service]
  Environment=DISPLAY=%I
  ExecStart=/home/username/script/services/xwatch %I
  
  [Install]
  WantedBy=xsession at .target

where xwatch is

  #!/bin/sh
  xprop -spy -root XFree86_VT
  echo "systemctl --user stop xsession@$1.target"
  systemctl --user stop "xsession@$1.target"

xprop is just the program I have chosen to communicate with the X socket (I
want a program that is not likely to crash, and this way I even know on
which VT the X session was launched in my logs). When the X session closes,
the xprop program terminates, and xwatch runs systemctl --user stop
"xsession@$1.target".

For (3), I have no need for it, but we could imagine a service timer that parse 
the results of ck-list-session, and stop the services when I have no seat
left.

Now for the bugs:
1) The specifiers (%something) work only when starting a service, not
loading it. For instance:
  ConditionPathExists=%h/.conkyrc
gives an error:
  Path in condition not absolute, ignoring: %h/.conkyrc
while something like
  ExecStart=/bin/echo %h
will work correctly and display my $HOME.
This is really annoying with user service files, because I have to specify
the home path manually, like in
  ExecStart=/home/username/script/services/xwatch %I
rather than
  ExecStart=%h/script/services/xwatch %I
and I don't always have the same $HOME (especially when I am not root...)

2) To work around the first problem, the services in ~/.config/systemd/user
are symlinks pointing to a service file with the right hardcoded HOME.
While systemctl start work fine with symlinks, systemctl enable does not:
   Failed to issue method call: No such file or directory
(this is not too annoying since I can always make the symlinks myself)

And the feature requests:
1) it would be nice to have a way to launch something when the service
   exit. (This is different from ExecStop is that it would be launched even
   if the service is not stopped by systemd). Maybe something like
   OnExitExec=
(one could even imagine adding things like OnExitSuccessExec=, OnExitFailureExec=, OnExitAbortExec=)

This would allow to write a pure systemd xwatch.service:

  [Unit]
  Description=Watch for X on display %I
  BindsTo=xsession at .target
  
  [Service]
  Environment=DISPLAY=%I
  ExecStart=/usr/bin/xprop -spy -root XFree86_VT
  OnExitExec=/usr/bin/systemctl --user stop xsession@%I.target
  
  [Install]
  WantedBy=xsession at .target

2) somewhat related: having a way to configure StartLimitAction= other than 
rebooting, which is not really usefull for user services.
(this would allow to simulate OnExitExec= by putting it on
StartLimitAction= and setting StartLimitBurst=1 and Restart=always, but it
is probably not a good idea).

-- 
Damien Robert


More information about the systemd-devel mailing list