Also, this thread is getting on in age and since OP hasn't followed up to the later replies, I'll close this as per our policy.
]]>To be honest the system I'm using is Raspbian, on a Raspberry Pi. But it's related to the systemd question here, and I think it applies too.
What I want to do is to execute a custom script right before the system goes down, and that the shutdown/reboot procedure wait my custom script finish before starting killing processes.
If you are curious, the custom script is this one: https://ghostbin.com/paste/owbqn
What it does is softly kill an application named emulationstation, and therefore saving some data related with this application.
What I've reached so far:
- created that script and named it as "/home/pi/bin/killes.sh".
- created this unit
[Unit]
Description=Kill EmulationStation
Before=shutdown.target reboot.target halt.target
[Service]
Type=oneshot
ExecStart=/bin/true
ExecStop=-/home/pi/bin/killes.sh
[Install]
WantedBy=shutdown.target reboot.target halt.target
I've made some tests changing the script content with "touch /delete-me" and I'm sure the script is running. But when I need a little more elaborated script it doesn't work as expected.
Thanks in advance.
]]>anyways, one thing I found that at least shines a little light on that is "systemctl status <pid>", which shows you which unit it thinks the process belongs to. so if you want to make sure your unit's ExecStop runs before a specific process is killed, you can at least find out which unit you have to depend on.
but i think madness is at the end of that road - systemd really doesn't want to admit there's a value to processes it doesn't explicitly know. so i counsel letting systemd know the exact dependency by putting the process that you care about inside of a unit. i don't like it, but it is the systemd way, and for as stubborn as systemd is, it is not hard to make a new unit. so instead of starting your process directly, you would wrap it in foo.service and do "systemctl start foo.service" to start it, or something like that.
assuming it can run without the terminal, right?
that's easy to do if you're running everything as root. if you need to depend on a non-root process, i'm not entirely clear on that, but systemd.exec man page's User= looks promising? supposedly polkit can let you use systemctl as a user..
hope this helps
]]>Uhhuh. Surely it does (per the ordering dependencies). It's just specifying After=multi-user.target in a unit WantedBy=multi-user.target is creating an ordering dependency loop (because if a target Wants= a unit, then that unit is implicitly Before= that target — unless you say DefaultDependencies=no), and systemd has to throw out one of the conflicting dependencies.
are you sure about this? the systemd.target man page says:
AUTOMATIC DEPENDENCIES
Unless DefaultDependencies= is set to no in either of related units or an explicit ordering dependency is already defined,
target units will implicitly complement all configured dependencies of type Wants= or Requires= with dependencies of type
After=. Note that Wants= or Requires= must be defined in the target unit itself — if you for example define Wants=some.target
in some.service, the implicit ordering will not be added.
ExecStop= doesn't seem to wait for the process to finish (even on type=oneshot) so other units might kick in earlier.
Maniaxx, my experience mirrors yours, that even "After=multi-user.target" isn't sufficient to make the shutown start first. I'm glad that you're also finding that "ExecStop= doesn't seem to wait for the process to finish (even on type=oneshot)", and I really wonder whether or not "oneshot" should wait on shutdown; as I recall from studying the manpage, no explicit statement is made one way or the other. I might try to find a spot to report that omission; perhaps the systemd people can at least clarify what's supposed to happen there.
Uhhuh. Surely it does (per the ordering dependencies). It's just specifying After=multi-user.target in a unit WantedBy=multi-user.target is creating an ordering dependency loop (because if a target Wants= a unit, then that unit is implicitly Before= that target — unless you say DefaultDependencies=no), and systemd has to throw out one of the conflicting dependencies. Unfortunately, it does not have any concept of "priority" to prefer throwing out an implicit dependency — so it may very well prefer the implicit one and discard what you wrote explicitly.
Now replying to the original thread. Anne, you seem to want to run your unit before the session scopes are killed, correct? This, I'm afraid, is impossible with current systemd: session scope units are autogenerated, and there is no way to specify an After= dependency on all of them.
However, the dependency mechanism per se is not flawed in any way, it works, and if you magically knew the name of the needed session scope, then you could simply write After= to that scope (and After=user@<uid>.service to work around an unrelated bug which is going to be fixed before next release when LP reviews my pull requests), and your oneshot unit will be stopped before systemd even attempts to kill that session.
You can try to propose a RFE to make systemd add an "include" statement to the autogenerated session scope units, so that you can put your own snippets with ordering dependencies into that file and have them included in all autogenerated session scope units.
]]>Brebs, I had already tried using shutdown.target to start the script, but it still starts too late.
Damjan, I was able to start the service very late in the boot sequence, but still couldn't get it to start shutting down early enough.
Maniaxx, my experience mirrors yours, that even "After=multi-user.target" isn't sufficient to make the shutown start first. I'm glad that you're also finding that "ExecStop= doesn't seem to wait for the process to finish (even on type=oneshot)", and I really wonder whether or not "oneshot" should wait on shutdown; as I recall from studying the manpage, no explicit statement is made one way or the other. I might try to find a spot to report that omission; perhaps the systemd people can at least clarify what's supposed to happen there. I'm intrigued by the idea that the "sleep" blocks everything, though - I'll experiment with that in case it gives me useful ideas.
I probably won't work on this again for the next few weeks, but if I get anything to work, I'll report back.
Thanks to all for your help,
Anne.
]]>Edit: Correction. Its not reliable. 'After=multi-user.target' still starts it too late sometimes.
[Unit]
Description=Unmount personal blocking mounts
After=multi-user.target
[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/bin/true
ExecStop=/etc/early-shutdown-script.sh
ExecStop=/usr/bin/sleep 1
[Install]
WantedBy=multi-user.target
systemd-user-sessions.service is not what you are looking for, check the man page.
]]>Perhaps one could use shutdown.target to run a script.
]]>anne wrote:... but you're barking up the wrong tree.
Yeah, I guess you fooled me. Not providing relevant information, and not sharing the purpose of the script after two requests will have that effect. Good luck - I'm not sure anyone will care to try to help you if you persist like this.
I'm sorry, I'm not trying to be mysterious or difficult, but I
am trying to understand systemd; to some extent this is an
exercise for me for that purpose. I'm eventually going to need
to make sure that production systems get their services shut down
cleanly: apps before databases, etc. This seemed as though it
would be straightforward, based on the manpages, and quite possibly
it will be, and perhaps I'm stuck now only because the "service"
I'm trying to depend on isn't really a service - though I thought
that most things were services.
The actual problem I'm trying to solve with this is not that
important in itself, but, since you folks really want to know:
I start my X session manually with "startx", and I'd like it to
close down gracefully, with certain applications (xterms) being
killed first, with a short sleep between each kill. The original
reason for this was that I would get hangs during system shutdown
and even during first login after a reboot, which I eventually traced
to contention by tcsh over the .history.lock file. That particular
problem was eliminated for logging in by adding code to .cshrc to
blow that file away if it persists for more than one second, to
avoid .login blocking indefinitely trying to obtain this lockfile.
I also reduced the DefaultTimeoutStopSec to reduce the pain when this
happens on shutdown. Finally, if I exit X gracefully, all's well: my
xinitrc now has a script that runs right after the preferred client
exits, which kills the xterms one by one to reduce the chances of
tcsh tripping over itself with the lock files. (It also looks cool to
have the windows go away one by one, but that's neither here nor there!)
Of course, all of this suggests a bug in tcsh whereby file locking is
not done correctly, but it's beyond my ability in the short term to
track that down, and my workarounds work well enough. If I managed
desktops in production, I'd have to dig into why tcsh doesn't clean
up its .history.lock file properly, but fortunately, in production
I manage only servers, where I'm unlikely to encounter this problem. ;-)
In any case, my original problem of tcsh hangs on my home desktop has
been worked around as long as I exit X before shutting down the system.
However, while working on that problem, I became determined to learn
how to make systemd run a script before killing user processes,
with the intention of having a script kill my preferred client
and wait for the X server to disappear. I have a script that
does exactly that, but no matter what I do, I can't seem to make
systemd's killing of the user processes wait for my script to run.
I defined a service and tried various dependency and ordering
statements to try to convince systemd to stop my service before
killing the user processes. "systemctl status" shows my Xorg and
xterms and other X apps, as well as my shells, as children of
"session-c2.scope", which is in turn a child of "user-1043.slice",
which is a child of "user.slice". So in desperation I threw
everything at it and tried:
Requires=systemd-user-sessions.service systemd-logind.service user.slice local-fs.target
After=systemd-user-sessions.service systemd-logind.service user.slice local-fs.target
... hoping that my service would be stopped before the user slice was
stopped. No go.
I also tried alternative approaches where I made a service that was
wanted by and to be started before the shutdown.target, where the
start of the service would have been intended to run my script.
(By this point, I was simply creating a bunch of bogus units that
called "/usr/bin/logger" for ExecStart, ExecStop, ExecStop, and
ExecStopPost, just to see what was happening.) In pretty much
all cases, the starts happened at the right moment, and the stops
happened later than I wanted.
Finally, I really do appreciate efforts to help; people's time is
valuable and I don't want to waste it. But with all due respect,
I did provide relevant information in my original posting.
I explained that I was able to define a service and my ExecStop
was duly called during shutdown, but too late. I asked for help in
determining a dependency that would cause my service to be stopped
before the "Stopping Session" tasks started to kick in.
I assumed that I was missing some simple piece of knowledge with
respect to what triggers the user process kills during shutdown, and
that if I had this piece of knowledge, I'd be able to write a unit
file to call my script at the right moment.
The reason why I want to call a script before user processes are
killed isn't all that important: I might be taking system diagnostic
snapshots, for example, or automatically sending e-mail to everyone
logged in, to apologize for an unannounced reboot. No matter what
arbitrary reason I have, it should still be possible to do this, and
I'm quite astonished that it has turned out to be so difficult.
If someone knows what triggers the user session stops, and how to
depend on it, I hope that they will share that knowledge.
Thanks to all who've piped up, and I apologize for annoying some of you.
Anne.
]]>... but you're barking up the wrong tree.
Yeah, I guess you fooled me. Not providing relevant information, and not sharing the purpose of the script after two requests will have that effect. Good luck - I'm not sure anyone will care to try to help you if you persist like this.
]]>You could add an 'ExecStop=' line for the service for which you want the script to run before it stops, using a drop-in conf file for this service.
I'd be happy to do this, if I could figure out which service is
killing the end-user processes during shutdown. ... but if I
could figure that out, I could probably write the dependency!
(That is, if "Type=oneshot" successfully makes follow-up services
wait for its completion before starting their own shutdown - the
manpage explains that "the process has to exit before systemd starts
follow-up units" during start, but it's not clear that this
restriction is also enforced during shutdown.)
At the moment, though, I can't even make my "service" start shutting
down first, so making sure that any other service waits for it to
finish shutting down is rather moot.
Anne.
]]>At least let us know how long this script is likely needed to complete. Might it be more than 90 seconds? If so, have you set TimeoutStopSec? or DefaultTimeoutStopSec?
Not likely more than 5 seconds, but you're barking up the wrong tree.
It starts and it completes, but by the time it starts, the system has
already started killing user processes, and I want this script to run
before any end-user processes are killed.
What I can't seem to figure out is how to set up a dependency to
accomplish this.
Anne.
]]>