Discussion:
[systemd-devel] Quick ? about ExecStartPre and Restart
Paul D. DeRocco
2013-07-03 22:38:55 UTC
Permalink
I'm new to systemd, and I'm confused about something. The docs include the
following sentence under the Restart directive:

"Configures whether the service shall be restarted when the service process
exits, is killed, or a timeout is reached. The service process may be the
main service process, but also one of the processes specified with
ExecStartPre=, ExecStartPost=, ExecStopPre=, ExecStopPost=, or ExecReload=."

Read literally, this suggests that if I set this to "on-success" or
"always", and I have an ExecStartPre that runs a quick command (in my case,
to copy my main service executable from a flash drive to a RAM drive), then
as soon as that completes, systemd will say, "Hey, the service has
terminated, time to restart it" and never get around to the ExecStart that
really does the work.

Is that really true? Or is that just a mistake in the docs? If it's not a
mistake, how do I configure it so that it won't restart when the command
launched by ExecStartPre terminates with a 0 exit code, but will restart if
the actual service started by ExecStart terminates with a 0 exit code?

Or is there another preferable way to do this?
--
Ciao, Paul D. DeRocco
Paul mailto:***@ix.netcom.com
Reindl Harald
2013-07-03 23:06:32 UTC
Permalink
Post by Paul D. DeRocco
I'm new to systemd, and I'm confused about something. The docs include the
"Configures whether the service shall be restarted when the service process
exits, is killed, or a timeout is reached. The service process may be the
main service process, but also one of the processes specified with
ExecStartPre=, ExecStartPost=, ExecStopPre=, ExecStopPost=, or ExecReload=."
Read literally, this suggests that if I set this to "on-success" or
"always", and I have an ExecStartPre that runs a quick command (in my case,
to copy my main service executable from a flash drive to a RAM drive), then
as soon as that completes, systemd will say, "Hey, the service has
terminated, time to restart it" and never get around to the ExecStart that
really does the work.
Is that really true? Or is that just a mistake in the docs? If it's not a
mistake, how do I configure it so that it won't restart when the command
launched by ExecStartPre terminates with a 0 exit code, but will restart if
the actual service started by ExecStart terminates with a 0 exit code?
it is not true and the documentation ha sno mistake

systemd does *not* consider the service as failed if ExecStartPre
terminates with a clean 0 exit code - it is considered as failed
if the ExecStartPre command does return a *non zero* code and
even that can be avoided with ExecStartPre=-/path/to/bin as the
doc states
Paul D. DeRocco
2013-07-03 23:45:49 UTC
Permalink
Post by Reindl Harald
Post by Paul D. DeRocco
I'm new to systemd, and I'm confused about something. The
docs include the
"Configures whether the service shall be restarted when the
service process
exits, is killed, or a timeout is reached. The service
process may be the
main service process, but also one of the processes specified with
ExecStartPre=, ExecStartPost=, ExecStopPre=, ExecStopPost=,
or ExecReload=."
Read literally, this suggests that if I set this to "on-success" or
"always", and I have an ExecStartPre that runs a quick
command (in my case,
to copy my main service executable from a flash drive to a
RAM drive), then
as soon as that completes, systemd will say, "Hey, the service has
terminated, time to restart it" and never get around to the
ExecStart that
really does the work.
Is that really true? Or is that just a mistake in the docs?
If it's not a
mistake, how do I configure it so that it won't restart
when the command
launched by ExecStartPre terminates with a 0 exit code, but
will restart if
the actual service started by ExecStart terminates with a 0
exit code?
it is not true and the documentation ha sno mistake
systemd does *not* consider the service as failed if ExecStartPre
terminates with a clean 0 exit code - it is considered as failed
if the ExecStartPre command does return a *non zero* code and
even that can be avoided with ExecStartPre=-/path/to/bin as the
doc states
I understand that, but I want the service to be restarted on success, not on
failure. By that I mean that if my ExecStart process (the actual service)
ever terminates with a 0 exit code, I want the whole thing to restart,
beginning with the ExecStartPre. But I DON'T want the 0 exit code from
ExecStartPre to restart anything, because that's not the actual service.
--
Ciao, Paul D. DeRocco
Paul mailto:***@ix.netcom.com
Paul D. DeRocco
2013-07-04 00:04:19 UTC
Permalink
so make *two* services while the first replaces ExecStartPre
and it's "ExecStartPost=/usr/bin/systemctl start service2.service"
"but I want the service to be restarted on success" is generally
very uncommon and you can hardly have two commands in a single
service with the opposite behavior
I suppose I could do that. Perhaps there is a cleaner way. All I want to do
is this:

1) I want my service executable to be copied from flash to RAM disk, and
then executed from there, so that the original can be updated while the copy
is running.

2) I want the service to be able to stop itself, and have systemd repeat the
copy operation and run the new copy.

3) If the service actually fails due to a bad configuration, it should die
and stay dead, since restarting it would just fail again.

Seems like a simple pattern that someone must have done before, and it
shouldn't take two services to do it. I thought that the ExecStartPre would
be a good way to do the copy.

I suppose I could also rewrite my service so that it returns a zero exit
code if its initialization fails, and a nonzero exit code if it ever wants
to restart itself, and then use Restart=on-failure. Does that sound
sensible?
--
Ciao, Paul D. DeRocco
Paul mailto:***@ix.netcom.com
Jan Alexander Steffens
2013-07-04 06:35:48 UTC
Permalink
Post by Paul D. DeRocco
1) I want my service executable to be copied from flash to RAM disk, and
then executed from there, so that the original can be updated while the copy
is running.
You don't need to copy it to somewhere else. You can replace an
executable without the running process being disturbed, by deleting
the file and creating (or moving) a new one in its place. Most tools
(like "cp") will do this when they overwrite a file. Then simply
restart the service (or have it exec() itself), and the new version
will be running.

The old version of the executable will continue to exist—even though
it has no file name—until nothing uses it anymore.
Paul D. DeRocco
2013-07-04 08:17:39 UTC
Permalink
On Thu, Jul 4, 2013 at 2:04 AM, Paul D. DeRocco
Post by Paul D. DeRocco
1) I want my service executable to be copied from flash to
RAM disk, and
then executed from there, so that the original can be
updated while the copy is running.
You don't need to copy it to somewhere else. You can replace an
executable without the running process being disturbed, by deleting
the file and creating (or moving) a new one in its place. Most tools
(like "cp") will do this when they overwrite a file. Then simply
restart the service (or have it exec() itself), and the new version
will be running.
The old version of the executable will continue to exist-even though
it has no file name-until nothing uses it anymore.
Is that true on all filesystems? This is a FAT16 volume on a flash drive in
an embedded system. It's also possible that the power might get yanked while
it's in this state, leaving an orphan file. Finally, since it will be
updated via a Samba file share, I don't know what sort of command will be
used to change it; it might be an overwrite plus lengthen or truncate
operation.
--
Ciao, Paul D. DeRocco
Paul mailto:***@ix.netcom.com
Jan Alexander Steffens
2013-07-04 08:28:21 UTC
Permalink
Post by Paul D. DeRocco
Post by Jan Alexander Steffens
You don't need to copy it to somewhere else. You can replace an
executable without the running process being disturbed, by deleting
the file and creating (or moving) a new one in its place. Most tools
(like "cp") will do this when they overwrite a file. Then simply
restart the service (or have it exec() itself), and the new version
will be running.
The old version of the executable will continue to exist—even though
it has no file name—until nothing uses it anymore.
Is that true on all filesystems? This is a FAT16 volume on a flash drive in
an embedded system. It's also possible that the power might get yanked while
it's in this state, leaving an orphan file. Finally, since it will be
updated via a Samba file share, I don't know what sort of command will be
used to change it; it might be an overwrite plus lengthen or truncate
operation.
Yes, I believe it's true on all file systems. I tested again with FAT16.

However, I was mistaken about "cp" doing a delete-and-replace by
default, because I forgot I was using "cp --reflink=auto" on a btrfs
volume. Without --reflink, I get an ETXTBSY when trying to copy over
an in-use executable.

"cp -f" works on both filesystems.

Even if Samba doesn't cooperate, doing a manual delete before copying
the new executable should work.
Reindl Harald
2013-07-03 23:51:31 UTC
Permalink
Post by Paul D. DeRocco
Post by Paul D. DeRocco
I'm new to systemd, and I'm confused about something. The
docs include the
"Configures whether the service shall be restarted when the
service process
exits, is killed, or a timeout is reached. The service
process may be the
main service process, but also one of the processes specified with
ExecStartPre=, ExecStartPost=, ExecStopPre=, ExecStopPost=,
or ExecReload=."
Read literally, this suggests that if I set this to "on-success" or
"always", and I have an ExecStartPre that runs a quick
command (in my case,
to copy my main service executable from a flash drive to a
RAM drive), then
as soon as that completes, systemd will say, "Hey, the service has
terminated, time to restart it" and never get around to the
ExecStart that
really does the work.
Is that really true? Or is that just a mistake in the docs?
If it's not a
mistake, how do I configure it so that it won't restart
when the command
launched by ExecStartPre terminates with a 0 exit code, but
will restart if
the actual service started by ExecStart terminates with a 0
exit code?
it is not true and the documentation has no mistake
systemd does *not* consider the service as failed if ExecStartPre
terminates with a clean 0 exit code - it is considered as failed
if the ExecStartPre command does return a *non zero* code and
even that can be avoided with ExecStartPre=-/path/to/bin as the
doc states
I understand that, but I want the service to be restarted on success, not on
failure. By that I mean that if my ExecStart process (the actual service)
ever terminates with a 0 exit code, I want the whole thing to restart,
beginning with the ExecStartPre. But I DON'T want the 0 exit code from
ExecStartPre to restart anything, because that's not the actual service
so make *two* services while the first replaces ExecStartPre
and it's "ExecStartPost=/usr/bin/systemctl start service2.service"

"but I want the service to be restarted on success" is generally
very uncommon and you can hardly have two commands in a single
service with the opposite behavior
Lennart Poettering
2013-07-05 20:27:04 UTC
Permalink
Post by Paul D. DeRocco
I'm new to systemd, and I'm confused about something. The docs include the
"Configures whether the service shall be restarted when the service process
exits, is killed, or a timeout is reached. The service process may be the
main service process, but also one of the processes specified with
ExecStartPre=, ExecStartPost=, ExecStopPre=, ExecStopPost=, or ExecReload=."
Read literally, this suggests that if I set this to "on-success" or
"always", and I have an ExecStartPre that runs a quick command (in my case,
to copy my main service executable from a flash drive to a RAM drive), then
as soon as that completes, systemd will say, "Hey, the service has
terminated, time to restart it" and never get around to the ExecStart that
really does the work.
This is indeed badly expressed, I added to the TODO list that we fix
this.

So what's actually meant here is that if a command line from
ExecStartPre= *fails* this already causes a restart of the entire
daemon. But if it suceeds, then the runtime of the main daemon is what
matters, and if the main daemon dies it is restarted.
Post by Paul D. DeRocco
Is that really true? Or is that just a mistake in the docs? If it's not a
mistake, how do I configure it so that it won't restart when the command
launched by ExecStartPre terminates with a 0 exit code, but will restart if
the actual service started by ExecStart terminates with a 0 exit code?
Or is there another preferable way to do this?
"on-success" and "always" do what you think they do, and the docs just
suck in this case. We need to fix the docs.

Lennart
--
Lennart Poettering - Red Hat, Inc.
Loading...