New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optional integration with elogind for auto-quitting the user daemons on user logout #1
Comments
Hi, Thanks for this request. It sounds interesting. I have to start by However, you clearly have a good use case for this. And I'm hoping that it And daemon already completely suppresses daemony behaviour when started by Perhaps this just needs a new option to cause daemon to do the initial Do you think that that would do the trick? If so, and if you are in a Does that sound plausible? Or is it wishful thinking? If it is wishful thinkng, it might be necessary to add lots of code to If you are in a position to contribute such a change, that would be great. Also, I can't work on it right now. But I could probably start next month or Is there any elogind-specific documentation on how elogind manages user |
First of all, thanks you for your interest for my feature(s) proposal! Unfortunately, I am not a C/C++ programmer, then I cannot help with patches. However, I am more than willing to help with the testing, in any way you consider that is needed. And I can help with a presentation of what I think is needed your Further, I will talk about A little rehash: a systemd "user target" daemon is just a program, which has no idea how to daemonize itself. In practice, when the user logins, the systemd forks itself and runs an instance as this particular user, where it continues to run those BUT, there are some rules on running those
After considerations and thinking done with my friends from Slackware community, apparently there are two main
After our experiments, for both
Right now, we need to start as
However, there are some caveats:
We have a way also to stop this Our idea is to use your
With the following conditions:
Now, regarding the elogind API documentation, it is in fact the extracted https://www.freedesktop.org/software/systemd/man/sd-login.html Also from what I understand, the analogy goes so far that you can build your Another thing is that a friend of mine found a snippet to talk with elogind/systemd which I show you bellow
This program could be compiled against
and again
That's all. Thanks you very much in anticipation. |
Hi! This friend of mine who found on Internet the snippet shown in the previous post, managed to make some changes to snippet, as to report the login sessions of a given user, defined by his UID.
This snippet, watch the hard-coded the first unpriviledged user in Slackwware with UID 1000, and apparently it is capable to count its login sessions, showing something like:
This is the report after switching to VT1, login as this first user, then doing same on VT2, and doing logout from those two consoles. So, yes. it tracks the number of login sessions for UID 1000. With the hope that those new information are useful, I wish you all the best! |
Hi, Thanks for all that. It's really very useful, and it looks like everything I should need to get started. However, when I compile the above on Debian, it doesn't seem to work the way I would expect. Running it from an ssh session as my only login to the virtual machine, I get the first line "login monitor timeout = -1 milliseconds", but nothing after that. And I am UID 1000 so being logged in via ssh should count as a session (I assume). I expected it to output a line every 500ms saying that there was 1 session, but it didn't (Note that I hadn't read the code properly yet). But when I did a graphical login to the VM, it output 6 lines, 3 saying 1 session, and another 3 saying 2 sessions. It's as though it was counting the ssh login but only after the graphical login happened. There probably wasn't an event to retrieve until then, which probably makes sense. But additional ssh logins while it's running don't cause it to output anything, which doesn't make sense. Do ssh logins count as a session or not? They seem to, since logging out of the graphical session causes it to report 1 session afterwards, which I assume is the original ssh login. If it isn't, what is it? Anyway, I'll read the code properly and the associated manpages until it all makes sense. I can get it to behave like I expect if I output the number of sessions after each epoll_wait() timeout. But it seems as though the first ssh login counts as a session but that any additional concurrent ssh logins don't add to the number of sessions. That's probably fine for your purposes. As long as the number of sessions goes to zero when all logins are over, that should be fine. I want to release a minor update before adding this. But it shouldn't take too long. cheers, P.S. The --foreground option is probably OK if autostart backgrounds it but you should probably test it with and without that option and see if it makes any difference. The --respawn option will keep it running if it terminates, but be warned that daemon will introduce delays if it thinks that the client process is terminating too quickly too many times. That can be tweaked and overridden with other options. To ensure that only a single instance is running, you need to use the --name option. That will be needed for this anyway. Putting the pidfile into $XDG_RUNTIME_DIR requires using the --pidfiles option. There'll be a new option for this new auto-stopping behaviour, but I haven't decided on its name yet (names are hard). It'll probably be --bind (as in bound to the user session). |
Hi, first of all, thank you very much for those fantastic news! I am anytime at your disposition for any "field testing" you consider to be needed on the real target operating system of this feature: Slackware. Regarding epoll and printing the user sessions, I've noticed the behavior described by you, and as a uneducated guess, apparently, is not only about pooling, but also about (e)logind sending events about things happening within user sessions. So, we get an output "when something happens" on the (e)logind management of the user sessions, then maybe is logical that our sessions probe will not see the event of logging in, because when it is started, that already happened. And also looks quite certain that the daemon will never see an initial count of However, in my humble opinion, the most important information notified by (e)logind is that the user sessions count dropped at Probably is possible to query (e)logind and to classify the user sessions, either being remote or local console, or graphical. But for now let's keep the things KISS, and we will see if there's a need to tune further the behavior. In other hand, I should inform you about some possible bad news... Like I said already, we intend to launch the supervised PipeWire from a desktop file on XDG autostart - and there the shell variables are not expanded. So, a desktop file like the one bellow will not work as expected:
I did some tests using a "fake" script, and I am very sure that So, there I have an idea: either your daemon to get the ability to lookup itself on the environment variables for the values starting with In other hand, even the Similar concerns looks being raised by Lennart Poetering into PulseAudio code:
https://github.com/pulseaudio/pulseaudio/blob/master/src/modules/module-systemd-login.c#L88 So, for those reasons he proposed an eventual alternate path for the PID files, something like: Certainly, I would love to test (and to report back) which one is the better way, after you to add the changes in daemon's code. To test myself the different variants with a single build of |
Thanks for the offer to test it. I can test it on Debian, but you testing it on Slackware with the actual intended use case will be more helpful. The problem of the environment variables on the command line could be solved by invoking daemon like this:
That way the shell does the expansion. However, I might add basic environment variable and ~ home directory expansion anyway, as it could be helpful in the configuration files as well. But technically, it would not be backwards compatible, which I wouldn't like, so I'd probably add an --expand option to enable it. The pidfile directory being deleted prematurely would be a problem, so I would also recommend not using it. Another reason not to use it is that daemon's --list option works slightly better when all of the pidfiles in the pidfiles directory were started by daemon(1). The reasons are explained in the manpage which suggests considering having a separate pidfiles directory just for daemons that are started by daemon(1). |
Hi, regarding the PID files path, what you think about this idea: The On our brainstorming to find the best solution while requesting the minimal changes to you, this looks the simpler solution to have an "per user" setup which does not disturb the functionality for another users. And at least in Slackware, the path And thanks for considering the volatility of Also, from our side experiments, looks like this path may or may not be deleted before the |
Thanks for the suggestion, but I don't think it's a good idea for the --bind option to implicitly affect the pidfiles directory. It sounds sensible, but I think it would be better if that remained explicit. My reason is that when the user wants to check on or interact with a daemon (i.e. with --running --stop --restart --signal --list), they will need to provide the --pidfiles option explicitly. If --bind implicitly alters the pidfiles directory, this will obscure the fact that the user has to match an implicitly selected pidfiles directory. And the documentation about default pidfiles directories is already complicated enough. I'd rather not complicate it further. But being explicit doesn't necessarily mean that it has to be on the command line. It can be in a configuration file instead. Then it will apply both to uses of the --bind option, and to uses of those other options. I think that's a better way to manage the pidfiles directory. For example, /etc/daemon.conf (or /etc/dademon.conf.d/*) could contain:
But I will make deamon auto-create the pidfiles directory if it is within the user's home directory. That's an excellent idea. By the way, when I said that the automatic deletion of the $XDG_RUNTIME_DIR directory would be a problem, I was thinking of using a separate watchdog process to stop the daemon. I even had a funny name for it: "daemokles". That method would have relied on the existence of the pidfile. But I'm thinking it will be more reliable to handle it within the daemon process itself, which means that the deletion of the pidfiles directory wouldn't prevent it from doing the right thing. But I'd still rather avoid using a volatile pidfiles directory. P.S. Sorry for all the delays in responding. I appreciate your patience. And I am getting much closer to doing this. :-) |
Let me know when you need me to test this feature. And thanks for your efforts! BTW, would be very nice if this feature would become available on the near future, as Slackware is right now on 15.0 alpha1, and we hope for proposing quickly your daemon for adoption, to be available on Slackware 15.0 for supervising the PipeWire services and eventual other "user target" daemons. |
Hi, I finally implemented the new --bind option. It's attached. Please test it. It works with systemd. Hopefully it'll work with elogind as well. The configure scripts looks for both. Note that I haven't yet done the environment variable and ~ expansion that we discussed yet, or the automatic creation of pidfiles directories within the user's home directory yet. But they'll be ready soon. Daemons that use --bind don't need to be named, and so they don't need pidfiles, so those features aren't essential for testing --bind. |
Hi, after building the
The result of my experiment is that it works perfectly, quitting itself (and the PipeWire instance) on KDE Plasma5 session logout both as You are great, man! Thank you very much, you did a fantastic job! Here, I have some notes:
Now I will try to build a proper Slackware package for our smart PS. I think that failing on flushing the sd monitor and getting the sessions count should be treated as fatal system errors because probably something very bad happens on logind. |
Thanks for the testing. That's great news. And thanks for the manpage bug. What's the output of I assume Slackware will still want to use /etc for config files. If not, that can be changed But I'll add $(DESTDIR) to CONF_INSDIR anyway. Thanks again. I'll make the other changes quickly (now that I've gotten started). |
Hi,
Unfortunatelly, the Slackware does not customize the uname output too much, but you can look for And yes, we use
That temporary folder is then used by the build script to create the Slackware package, which is essentially a tarball. BTW, I wonder if you can't do a (beta?) release focusing on fixes of build system now that that This will be really useful. |
BTW, I seen that your build system can generate packages of different types. So, I wonder if you can add also Slackware on your known packages to build, as it is very simple:
Where The result will be a Slackware package named like This is an example of
It should have exactly 11 lines and the text to respect the size of the handy ruler. Ideally, you should put also a link to So, this one would be perfect:
|
To see what Slackware do with its package builds, here is a build script
This is the
The |
BTW, why we need a separate line of |
Please permit the tilde expansion for home, also for root, like this
As difference of Debian, the Slackware has a fully functional root account, so people may be interested to run your daemon as And I think that talking with password/shadow library is quite safe, right? So, a minimal expanding (only for home tilde) would be quite safe also for root, ight? OR, at least please leave to root the ability to expand its own home tilde, as looks like we need to use just a config file like:
for a XDG autostart file like
With this setup the daemon supervisor will work equally for any user, be it the root or an unprivileged user. |
There's a patch which is more appropriate to your original idea, as it permit for root only the expansion of a simple tilde (its own home)
|
I think I can release the new version tomorrow. Thanks for the info about /etc/slackware-version. That's enough to configure for Slackware automatically. I don't really want to include building a Slackware package in the makefiles. The existing binary package-building parts of the makefiles are very old and haven't been used in a decade. I'm sure many of them are out of date. I think it's best if people with expertise in the packaging system of each platform handle that. I can't keep up with it all. "make install-daemon-conf" is separate because it's optional. Daemon will work without the config files. But more importantly, installing config files is complicated if there is already one there. Different platforms handle it differently. This way, the person installing (or building a package) has to decide how to handle it, and I won't get blamed for destroying someone's existing config file, or trying to handle it myself in a way that doesn't fit in with the platform's usual way of doing things. Thanks so much for spotting the bug in expand(). That's fantastic. But your solution isn't quite right. The environment variables should be expanded before the user home directory notation (not after), so that environment variables can contain user home directory notation (just in case). And it's OK for root to expand another user's home directory, since the information is coming from /etc/passwd, which is trusted, and not from the process environment, which isn't. I didn't intend to prevent root from expanding home directories. It was just a mistake. It's fixed now. Thanks again. |
Thanks again for your hard work! I am very happy to see the see the new release. BTW, as a last minute suggestion: that man page part about the interaction of systemd's configuration of So, also on elogind is this option, which probably have same effects like in systemd. |
Does elogind kill all user processes on logout if KillUserProcesses=yes like systemd does? And is the KillUserProcesses setting in the same configuration file (i.e. /etc/systemd/logind.conf)? |
Yes, it does just like systemd, the single difference I seen is that the config file is differently named: That |
BTW, please take a look at this post: Looks like a forum member got something like bellow after using a chained execution on client (PipeWire)
Then, after logout:
This So, we have a wrong daemon usage or a bug? Or we found a bug on PipeWire? |
Looks that was just a false alarm! Apparently was just a wrong setup and we find the proper way to run the Separately, by a second instance of |
Oh, dear. Zombies are never fun. It's very tempting to blame someone else's software when things go wrong like this, but I'm never confident that that's a valid response. Without being able to replicate and investigate the problem, it's hard to know the real cause. But I think I can make a good guess. A zombie process happens when a process terminates, and its parent process doesn't wait() for it, so as to obtain its termination status. Pipewire has terminated, but daemon hasn't wait()ed for its status yet. Daemon wait()s for its client's termination status after it has both received the SIGCHLD signal to let it know that a child process and died, and after that child process's stdout file descriptor has closed (daemon wants to make sure that it reads any final output from the client). But it's possible for the client's stdout file descriptor to stay open after it terminates: i.e. when the client has started its own child process (e.g. pipewire-pulse) which shares its parent's process's stdout, and that other process is still running, and is still keeping stdout open. Daemon is effectively waiting for pipewire-pulse to terminate as well. That will close the shared stdout. But pipewire hasn't terminated pipewire-pulse. It probably assumes that whatever sent it a SIGTERM will also send a SIGTERM to pipewire-pulse. But daemon won't do that because it doesn't know anything about pipewire-pulse. Daemon assumes that the client process will handle the termination of its own child processes when it receives a SIGTERM signal. So, it looks like this happened:
If pipewire and pipewire-pulse do share the same stdout file descriptor, that would prevent pipewire's stdout from closing (from daemon's point of view), and this would result. There are several approaches to fixing this:
Option 1 requires getting pipewire changed. Option 2 should prevent pipewire becoming a zombie, and cause it and the daemon process to disappear from the process list, but it won't do anything to terminate pipewire-pulse. That's still running. Option 3 is probably the quickest and easiest approach that should get both the pipewire and pipewire-pulse processes terminated cleanly. Please ask 0XBF to try option 3 and let me know if it works. |
Good. I thought getting a separate daemon to run pipewire-pulse would fix it. |
Please, you can show me a I want to show that on forum as demo of
|
Yes, looks like this is the proper solution. |
The --output (or -o) option captures both the client's stdout and stderr to a file or syslog: log=/var/log/daemontest.log There are also --stdout (-O) and --stderr (-E) options to separate stdout and stderr. The --errlog (or -l) and --dbglog (or -b) options capture any error or debug output from daemon itself: daemon --output="$log" --errlog="$log" --dbglog="$log" -- cmd If you specify an actual filepath, it bypasses syslog and writes directly to the file. To use syslog, specify a syslog facility and priority (e.g. "local0.err") instead of a file path. |
Thanks you! |
I can have a suggestion? Instead of I believe that those who wants this feature (like us) could activate it, while the others will got the "standard" daemon supervisor. |
I think it's easier the way it is, because if libsystemd or libelogind are present (with header files), that's enough to include the functionality. Someone doesn't have to make sure that one of those libraries is installed, and also say that they want it used. Having it installed should make it obvious that they want it used. The only reason I added --disable-logind was so that I had an easy way to disable it before committing changes to the code, so the checked in code didn't have it by default. But having said that, if --enable-logind existed and wasn't the default (when possible), then I wouldn't have to always remember to --disable-logind before committing code. So I'll change it. By the way, the change earlier involving |
I may make another little suggestion? There's a way to setup the Slackware comes in different flavors, and bellow is a valid logic on our build scripts:
Usually, the variable
BTW, looks like the Slackware configure part fails to set properly the man dir to |
Currently, you need to pass CPPFLAGS, CFLAGS and LDFLAGS to make directly, not configure. |
I understand. Thanks! |
This what does your
So, the man page is installed on |
I forgot that MAN_LOCDIR is only used when PREFIX != /usr. MAN_SYSDIR is used when PREFIX is /usr. The slackware config changes MAN_SYSDIR as well now. And it changes PREFIX=/usr so you don't need --prefix=/usr. Try again with the new commit. |
Thanks! 👍 |
Just a little cosmetic change on
to be
Thanks! |
Sure. I've just released daemon-0.8. Thanks for all the suggestions. |
Thank you for all your hard work! 👏 👏 👏 👏 👏 👏 👏 👏 👏 👏 👏 👏 👏 👏 |
I believe that for the non-systemd Linux distributions which uses a traditional INIT system, would be exceptionally useful if this daemon would have an optional integration with elogind for auto-quitting the user daemons on user logout.
There's my reasoning and a little background for this proposal:
The systemd has the ability to run daemons as particular users, eventually one instance for each user, and to stop those particular daemon instances on user logout. This is what they call "user target" daemons, and a notable example of software which is designed to be run in this way is PipeWire, a multimedia server which is used massively by the modern KDE Plasma5 especially under Wayland sessions, and it is even proposed as a PulseAudio replacement into next Fedora 34.
For the non-systemd Linux distributions using a traditional INIT system, notable being Slackware, for the user sessions management there's the alternative of elogind. However, this elogind has no support for running daemons, either systemd wide or as user, and probably it is not supposed to have this, being rather a systemd-logind service alike.
From my own experiments with Slackware development tree, where's about to be merged the KDE Plasma5 and elogind, there's a way to start those "user target" daemon, notable being PulseAudio and PipeWire: via XDG autostart desktop files. However, there's no generic way to stop them, excluding configuring elogind to kill all user processes on logout, which have negative effects on running properly applications like TMux or Screen. That's why this should be generally avoided.
Fortunately, the PulseAudio has the ability to integrate with systemd (or elogind) and to watch the user logout, then to auto-quit its user instances on logout. While the PipeWire has no support for this features, being simply unaware of the running user sessions management.
How this systemd support for "user target" daemons is widelly available for the Linux distributions using it, I suspect that in the future would be even more software relying on it for its user daemons. Support which like I said, is not available yet for the non-systemd distributions using a classic init system. That's why I looked for a generic way to have this feature available.
There enters your "daemon" which is capable to run user daemons, it is even capable to watch their running and to re-spawn them, and it capable to run in background any imaginable program.
I believe that if your daemon gets the ability to watch the users logout, and to auto-quit its instances for a particular user, just like PulseAudio, it could be "the missing piece" for the non-systemd Linux distributions like Slackware (but not limited to) for properly handling those "user target" daemons designed for systemd.
Please consider my proposal, I believe that it would not be so complicated to add (looking at what PulseAudio do) and would transform your "daemon" in a fundamental piece of software for the non-systemd Linux distrbutions which still uses the classical INIT systems like is SysV init.
PS. I believe that what PulseAudio do for its systemd integration is there:
https://github.com/pulseaudio/pulseaudio/blob/master/src/modules/module-systemd-login.c
The text was updated successfully, but these errors were encountered: