Discussion:
question about system reboot and shutdown
Add Reply
Marek Floriańczyk
2017-08-08 14:03:07 UTC
Reply
Permalink
Raw Message
Hi all,

I have a small device MicroUPS which helps me to shutdown my system on
embedded devices, it is controlled by script /etc/init.d/microups and in this
script I need to know whether system is going down for reboot or for halt,
because in case of halt I need to send small data over RS232 to MicroUPS
device to cut the power off.

In previous version of init system I checked $runlevel variable but now I'm
doing some "grep" commands according to this post

https://stackoverflow.com/questions/25166085/how-can-a-systemd-controlled-service-distinguish-between-shutdown-and-reboot

and sometimes my method doesn't work. Either in /usr/bin/systemctl list-jobs
there is sometimes reboot and shutdown process present, or my microupsd
process gets killed before it sends data to the MicroUPS device over Rs232.

What would be the proper way to distinguish between system is going down for
reboot and for shutdown ?

Best Regards
Marek
Andrei Borzenkov
2017-08-08 18:04:18 UTC
Reply
Permalink
Raw Message
Post by Marek Floriańczyk
What would be the proper way to distinguish between system is going down for
reboot and for shutdown ?
Straightforward way is to make your service WantedBy poweroff.target and
halt.target. You can then have second service WantedBy reboot.target and
kexec.target. They may even call the same binary (script) but with
different arguments.
Marek Floriańczyk
2017-08-08 18:45:32 UTC
Reply
Permalink
Raw Message
Post by Andrei Borzenkov
Post by Marek Floriańczyk
What would be the proper way to distinguish between system is going down
for reboot and for shutdown ?
Straightforward way is to make your service WantedBy poweroff.target and
halt.target. You can then have second service WantedBy reboot.target and
kexec.target. They may even call the same binary (script) but with
different arguments.
Thanks for answer,

So, my binary "microupsd" is started by /etc/init.d/microups at the boot time
to monitor power input, battery status etc.
During system halt I need to send SIGUSR1 to this "microupsd" process at which
it will send command to microups device, moreover I would like to give it
some time (like 1-2 seconds) to accomplish the transmission.
I don't need to send anything in case of reboot.

Should I prepare some script that sends SIGUSR1 to "microupsd" process and
then sleeps for 2 seconds and set it as WantedBy poweroff.target and
halt.target ?

How can I be sure that this script will be called before "microupsd" is
actually killed during system shutdown ?

Best Regards
Marek
Mantas Mikulėnas
2017-08-08 19:35:12 UTC
Reply
Permalink
Raw Message
I suggest first porting microupsd itself to a native systemd .service file
(so that it'll have process monitoring and everything). That might even fix
part of the problem.

Normally services are given a certain amount of time to stop after SIGTERM
(or whatever KillSignal was set, or whatever ExecStop command was
specified). Even if microupsd doesn't handle SIGTERM nicely (which I'd call
a bug), it's possible to add some... arbitrary delays.

Units are stopped due to having automatic Conflicts=shutdown.target, if I
remember correctly. I'm not sure if disabling that default dependency is a
good approach though...

This time I can't think of a good combination that'd solve both problems
without introducing some ugly race conditions...
Post by Marek Floriańczyk
Post by Andrei Borzenkov
Post by Marek Floriańczyk
What would be the proper way to distinguish between system is going
down
Post by Andrei Borzenkov
Post by Marek Floriańczyk
for reboot and for shutdown ?
Straightforward way is to make your service WantedBy poweroff.target and
halt.target. You can then have second service WantedBy reboot.target and
kexec.target. They may even call the same binary (script) but with
different arguments.
Thanks for answer,
So, my binary "microupsd" is started by /etc/init.d/microups at the boot time
to monitor power input, battery status etc.
During system halt I need to send SIGUSR1 to this "microupsd" process at which
it will send command to microups device, moreover I would like to give it
some time (like 1-2 seconds) to accomplish the transmission.
I don't need to send anything in case of reboot.
Should I prepare some script that sends SIGUSR1 to "microupsd" process and
then sleeps for 2 seconds and set it as WantedBy poweroff.target and
halt.target ?
How can I be sure that this script will be called before "microupsd" is
actually killed during system shutdown ?
Best Regards
Marek
_______________________________________________
systemd-devel mailing list
https://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
Mantas Mikulėnas <***@gmail.com>
Sent from my phone
Marek Floriańczyk
2017-08-08 20:04:18 UTC
Reply
Permalink
Raw Message
Post by Mantas Mikulėnas
I suggest first porting microupsd itself to a native systemd .service file
(so that it'll have process monitoring and everything). That might even fix
part of the problem.
Hi

I have no problem with changing some code in microupsd so it behave in certain
way. It is handling SIGTERM and other signals if needed.
The problem for me is that SIGTERM is send to process during system reboot and
system halt - so I need to differentiate between the two.

If you can suggest me a way, maybe with some example I will change my code.

Best Regards
Marek
Post by Mantas Mikulėnas
Normally services are given a certain amount of time to stop after SIGTERM
(or whatever KillSignal was set, or whatever ExecStop command was
specified). Even if microupsd doesn't handle SIGTERM nicely (which I'd call
a bug), it's possible to add some... arbitrary delays.
Units are stopped due to having automatic Conflicts=shutdown.target, if I
remember correctly. I'm not sure if disabling that default dependency is a
good approach though...
This time I can't think of a good combination that'd solve both problems
without introducing some ugly race conditions...
Post by Marek Floriańczyk
Post by Andrei Borzenkov
Post by Marek Floriańczyk
What would be the proper way to distinguish between system is going
down
Post by Andrei Borzenkov
Post by Marek Floriańczyk
for reboot and for shutdown ?
Straightforward way is to make your service WantedBy poweroff.target and
halt.target. You can then have second service WantedBy reboot.target and
kexec.target. They may even call the same binary (script) but with
different arguments.
Thanks for answer,
So, my binary "microupsd" is started by /etc/init.d/microups at the boot time
to monitor power input, battery status etc.
During system halt I need to send SIGUSR1 to this "microupsd" process at which
it will send command to microups device, moreover I would like to give it
some time (like 1-2 seconds) to accomplish the transmission.
I don't need to send anything in case of reboot.
Should I prepare some script that sends SIGUSR1 to "microupsd" process and
then sleeps for 2 seconds and set it as WantedBy poweroff.target and
halt.target ?
How can I be sure that this script will be called before "microupsd" is
actually killed during system shutdown ?
Best Regards
Marek
_______________________________________________
systemd-devel mailing list
https://lists.freedesktop.org/mailman/listinfo/systemd-devel
Jérémy Rosen
2017-08-09 07:47:54 UTC
Reply
Permalink
Raw Message
Hi
Post by Marek Floriańczyk
I have no problem with changing some code in microupsd so it behave in certain
way. It is handling SIGTERM and other signals if needed.
The problem for me is that SIGTERM is send to process during system reboot and
system halt - so I need to differentiate between the two.
SIGTERM is sent, by default, to all processes early during shutdown.

You need to disable DefaultDependencies for your process to not recieve
the default SIGTERM and then trigger it yourself with the WandedBy that
was already described...


Your daemon is a late-shutdown daemon, not a normal daemon. I think
that deactivating default dependencies in this case makes sense.

I strongly advice carefully reading the section on default dependencies in
systemd.service, though... You will deactivate all default dependencies and
you probably don't want that. You'll need to manually reactivate the other
default dependencies

BR
Jérémy
Post by Marek Floriańczyk
If you can suggest me a way, maybe with some example I will change my code.
Best Regards
Marek
Post by Mantas Mikulėnas
Normally services are given a certain amount of time to stop after SIGTERM
(or whatever KillSignal was set, or whatever ExecStop command was
specified). Even if microupsd doesn't handle SIGTERM nicely (which I'd call
a bug), it's possible to add some... arbitrary delays.
Units are stopped due to having automatic Conflicts=shutdown.target, if I
remember correctly. I'm not sure if disabling that default dependency is a
good approach though...
This time I can't think of a good combination that'd solve both problems
without introducing some ugly race conditions...
Post by Marek Floriańczyk
Post by Andrei Borzenkov
Post by Marek Floriańczyk
What would be the proper way to distinguish between system is going
down
Post by Andrei Borzenkov
Post by Marek Floriańczyk
for reboot and for shutdown ?
Straightforward way is to make your service WantedBy poweroff.target and
halt.target. You can then have second service WantedBy reboot.target and
kexec.target. They may even call the same binary (script) but with
different arguments.
Thanks for answer,
So, my binary "microupsd" is started by /etc/init.d/microups at the boot time
to monitor power input, battery status etc.
During system halt I need to send SIGUSR1 to this "microupsd" process at which
it will send command to microups device, moreover I would like to give it
some time (like 1-2 seconds) to accomplish the transmission.
I don't need to send anything in case of reboot.
Should I prepare some script that sends SIGUSR1 to "microupsd" process and
then sleeps for 2 seconds and set it as WantedBy poweroff.target and
halt.target ?
How can I be sure that this script will be called before "microupsd" is
actually killed during system shutdown ?
Best Regards
Marek
_______________________________________________
systemd-devel mailing list
https://lists.freedesktop.org/mailman/listinfo/systemd-devel
_______________________________________________
systemd-devel mailing list
https://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
Logo <http://www.smile.fr/>

20 rue des Jardins
92600 AsniÚres-sur-Seine
www.smile.fr <http://www.smile.fr/>
*Jérémy ROSEN*
Architecte technique
Email : ***@smile.fr <mailto:***@smile.fr>
Tel : +33141402967

Facebook <https://www.facebook.com/smileopensource> Google%2B
<http://fr.slideshare.net/SmileOpenSource/presentations> LinkedIn
<https://www.linkedin.com/company/smile> Twitter
<https://twitter.com/GroupeSmile>


bandeaux_mail
<http://www.smile.fr/Offres-services/Offres/Ingenierie?utm_source=signature&utm_medium=email&utm_campaign=signature>

eco Pour la planÚte, n'imprimez ce mail que si c'est nécessaire
Lennart Poettering
2017-08-09 08:29:37 UTC
Reply
Permalink
Raw Message
Post by Marek Floriańczyk
Hi all,
I have a small device MicroUPS which helps me to shutdown my system on
embedded devices, it is controlled by script /etc/init.d/microups and in this
script I need to know whether system is going down for reboot or for halt,
because in case of halt I need to send small data over RS232 to MicroUPS
device to cut the power off.
Note that this is necessarily racy: you can't really know how long the
system will actually take to shut down, hence if you trigger your
hardware for shutdown at an early phase of the shutdown process you
now start racing the remaining shutdown phase against the hardware turning
off power...

If you want to fix this properly, and remove this race entirely the
only fully correct way out I see is to use an initrd for booting, and
doing the RS232 thing from that. Note that if you use a properly
prepared initrd, systemd will actually transition back to it at
shutdown, and while doing so it will permit unmounting the root file
system properly at shutdown. And only if you start the RS232 thing
after the point where the root fs is unmounted you can fully remove
the race in the generic case, since only at that point everything is
fully synced to disk, all complex storage is disassembled and so on.

Now, adding this to the initrd is not the easiest thing in the world,
and in particular in embedded devices avoiding an initrd might be a
good thing. As long as you have no complex storage (i.e. no DM, no
LVM, no LUKS, no RAID, no iscsi, yaddayadda) you can instead cut a
corner and just drop in a shutdown script to
/usr/lib/systemd/system-shutdown/. All executable files in that
directory are run at very late boot, at a point where all file systems
that can be unmounted have been unmounted and the rest have been
remounted read-only (i.e. the root fs will be r/o and everything else
is gone). All services are gone at that point too, hence you live in a
very minimal, very reduced environment. If you issue your RS232
commands from that environment you should be mostly good. (but again,
if you do complex storage all of this falls apart, and you have to do
the initrd thing instead).

Note that /usr/lib/systemd/system-shutdown/ is outside of usual
service management. It's run at a point where service management is
already turned off. As such, you really just drop executable scripts
or binaries there, and nothing long-running, no daemons or such, just
simple programs that run and exit.

For details about this facility see the systemd-halt.service(8) man
page. The scripts executed that way will get one parameter, which
tells it what operation is being executed. And if its "poweroff", then
you know that the system is going down for powering off rather than
reboot.

Lennart
--
Lennart Poettering, Red Hat
Marek Floriańczyk
2017-08-09 09:02:51 UTC
Reply
Permalink
Raw Message
Post by Lennart Poettering
Post by Marek Floriańczyk
Hi all,
I have a small device MicroUPS which helps me to shutdown my system on
embedded devices, it is controlled by script /etc/init.d/microups and in
this script I need to know whether system is going down for reboot or for
halt, because in case of halt I need to send small data over RS232 to
MicroUPS device to cut the power off.
Note that this is necessarily racy: you can't really know how long the
system will actually take to shut down, hence if you trigger your
hardware for shutdown at an early phase of the shutdown process you
now start racing the remaining shutdown phase against the hardware turning
off power...
If you want to fix this properly, and remove this race entirely the
only fully correct way out I see is to use an initrd for booting, and
doing the RS232 thing from that. Note that if you use a properly
prepared initrd, systemd will actually transition back to it at
shutdown, and while doing so it will permit unmounting the root file
system properly at shutdown. And only if you start the RS232 thing
after the point where the root fs is unmounted you can fully remove
the race in the generic case, since only at that point everything is
fully synced to disk, all complex storage is disassembled and so on.
Now, adding this to the initrd is not the easiest thing in the world,
and in particular in embedded devices avoiding an initrd might be a
good thing. As long as you have no complex storage (i.e. no DM, no
LVM, no LUKS, no RAID, no iscsi, yaddayadda) you can instead cut a
corner and just drop in a shutdown script to
/usr/lib/systemd/system-shutdown/. All executable files in that
directory are run at very late boot, at a point where all file systems
that can be unmounted have been unmounted and the rest have been
remounted read-only (i.e. the root fs will be r/o and everything else
is gone). All services are gone at that point too, hence you live in a
very minimal, very reduced environment. If you issue your RS232
commands from that environment you should be mostly good. (but again,
if you do complex storage all of this falls apart, and you have to do
the initrd thing instead).
Note that /usr/lib/systemd/system-shutdown/ is outside of usual
service management. It's run at a point where service management is
already turned off. As such, you really just drop executable scripts
or binaries there, and nothing long-running, no daemons or such, just
simple programs that run and exit.
For details about this facility see the systemd-halt.service(8) man
page. The scripts executed that way will get one parameter, which
tells it what operation is being executed. And if its "poweroff", then
you know that the system is going down for powering off rather than
reboot.
Hi,

This looks like a good way for me.
I cannot really use initrd, because my MicroUPS is intended to work not only
for me but also for an average people, with some .deb package to install.
This is an early version of my device, now it looks different, has higher
power output and so on
https://www.indiegogo.com/projects/microups-for-raspberry-beaglebone-cubieboard#/


I'm aware of race condition but some microcomputers like Raspberry if they
shutdown the operating system, the power is still ON, and I have no way to
figure out when to turn power off. So what I'm doing is telling microups device
to cut power off 30 seconds after shutdown has been initiated (parameter is
configurable).
Microcomputers usually have some SD card, sometimes built-in NAND memory, and
sometimes single SATA SSD disk, so complex storage is not an issue (I think)

The question is, will my binary be able to open RS232 port eg. /dev/ttyACM0
when filesystem is Read-Only ?
And if it is binary it will need to load some libs at least libc at the start.

The man page you pointed to says the parameter is: "halt", "poweroff",
"reboot" or "kexec", so the first two should work for me.

Best Regards
Marek
Post by Lennart Poettering
Lennart
Mantas Mikulėnas
2017-08-09 09:17:44 UTC
Reply
Permalink
Raw Message
/dev is a separate filesystem and is never read-only.

Another approach would be to let microupsd exit normally, but then start a
separate microupsd instance (e.g. microupsd-shutdown.service) which
schedules the UPS poweroff.
Post by Lennart Poettering
Post by Lennart Poettering
Post by Marek Floriańczyk
Hi all,
I have a small device MicroUPS which helps me to shutdown my system on
embedded devices, it is controlled by script /etc/init.d/microups and
in
Post by Lennart Poettering
Post by Marek Floriańczyk
this script I need to know whether system is going down for reboot or
for
Post by Lennart Poettering
Post by Marek Floriańczyk
halt, because in case of halt I need to send small data over RS232 to
MicroUPS device to cut the power off.
Note that this is necessarily racy: you can't really know how long the
system will actually take to shut down, hence if you trigger your
hardware for shutdown at an early phase of the shutdown process you
now start racing the remaining shutdown phase against the hardware
turning
Post by Lennart Poettering
off power...
If you want to fix this properly, and remove this race entirely the
only fully correct way out I see is to use an initrd for booting, and
doing the RS232 thing from that. Note that if you use a properly
prepared initrd, systemd will actually transition back to it at
shutdown, and while doing so it will permit unmounting the root file
system properly at shutdown. And only if you start the RS232 thing
after the point where the root fs is unmounted you can fully remove
the race in the generic case, since only at that point everything is
fully synced to disk, all complex storage is disassembled and so on.
Now, adding this to the initrd is not the easiest thing in the world,
and in particular in embedded devices avoiding an initrd might be a
good thing. As long as you have no complex storage (i.e. no DM, no
LVM, no LUKS, no RAID, no iscsi, yaddayadda) you can instead cut a
corner and just drop in a shutdown script to
/usr/lib/systemd/system-shutdown/. All executable files in that
directory are run at very late boot, at a point where all file systems
that can be unmounted have been unmounted and the rest have been
remounted read-only (i.e. the root fs will be r/o and everything else
is gone). All services are gone at that point too, hence you live in a
very minimal, very reduced environment. If you issue your RS232
commands from that environment you should be mostly good. (but again,
if you do complex storage all of this falls apart, and you have to do
the initrd thing instead).
Note that /usr/lib/systemd/system-shutdown/ is outside of usual
service management. It's run at a point where service management is
already turned off. As such, you really just drop executable scripts
or binaries there, and nothing long-running, no daemons or such, just
simple programs that run and exit.
For details about this facility see the systemd-halt.service(8) man
page. The scripts executed that way will get one parameter, which
tells it what operation is being executed. And if its "poweroff", then
you know that the system is going down for powering off rather than
reboot.
Hi,
This looks like a good way for me.
I cannot really use initrd, because my MicroUPS is intended to work not only
for me but also for an average people, with some .deb package to install.
This is an early version of my device, now it looks different, has higher
power output and so on
https://www.indiegogo.com/projects/microups-for-raspberry-beaglebone-cubieboard#/
I'm aware of race condition but some microcomputers like Raspberry if they
shutdown the operating system, the power is still ON, and I have no way to
figure out when to turn power off. So what I'm doing is telling microups device
to cut power off 30 seconds after shutdown has been initiated (parameter is
configurable).
Microcomputers usually have some SD card, sometimes built-in NAND memory, and
sometimes single SATA SSD disk, so complex storage is not an issue (I think)
The question is, will my binary be able to open RS232 port eg. /dev/ttyACM0
when filesystem is Read-Only ?
And if it is binary it will need to load some libs at least libc at the start.
The man page you pointed to says the parameter is: "halt", "poweroff",
"reboot" or "kexec", so the first two should work for me.
Best Regards
Marek
Post by Lennart Poettering
Lennart
_______________________________________________
systemd-devel mailing list
https://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
Mantas Mikulėnas <***@gmail.com>
Sent from my phone
Marek Floriańczyk
2017-08-09 09:42:20 UTC
Reply
Permalink
Raw Message
Post by Mantas Mikulėnas
/dev is a separate filesystem and is never read-only.
right ;)
Post by Mantas Mikulėnas
Another approach would be to let microupsd exit normally, but then start a
separate microupsd instance (e.g. microupsd-shutdown.service) which
schedules the UPS poweroff.
Thanks for suggestion
I will stick to the approach suggested by Lennart it looks like a simple
solution to me, and the binary is called at the very late stage of shutdown
process after every databases and daemons are closed.
Post by Mantas Mikulėnas
Post by Lennart Poettering
Post by Lennart Poettering
Post by Marek Floriańczyk
Hi all,
I have a small device MicroUPS which helps me to shutdown my system on
embedded devices, it is controlled by script /etc/init.d/microups and
in
Post by Lennart Poettering
Post by Marek Floriańczyk
this script I need to know whether system is going down for reboot or
for
Post by Lennart Poettering
Post by Marek Floriańczyk
halt, because in case of halt I need to send small data over RS232 to
MicroUPS device to cut the power off.
Note that this is necessarily racy: you can't really know how long the
system will actually take to shut down, hence if you trigger your
hardware for shutdown at an early phase of the shutdown process you
now start racing the remaining shutdown phase against the hardware
turning
Post by Lennart Poettering
off power...
If you want to fix this properly, and remove this race entirely the
only fully correct way out I see is to use an initrd for booting, and
doing the RS232 thing from that. Note that if you use a properly
prepared initrd, systemd will actually transition back to it at
shutdown, and while doing so it will permit unmounting the root file
system properly at shutdown. And only if you start the RS232 thing
after the point where the root fs is unmounted you can fully remove
the race in the generic case, since only at that point everything is
fully synced to disk, all complex storage is disassembled and so on.
Now, adding this to the initrd is not the easiest thing in the world,
and in particular in embedded devices avoiding an initrd might be a
good thing. As long as you have no complex storage (i.e. no DM, no
LVM, no LUKS, no RAID, no iscsi, yaddayadda) you can instead cut a
corner and just drop in a shutdown script to
/usr/lib/systemd/system-shutdown/. All executable files in that
directory are run at very late boot, at a point where all file systems
that can be unmounted have been unmounted and the rest have been
remounted read-only (i.e. the root fs will be r/o and everything else
is gone). All services are gone at that point too, hence you live in a
very minimal, very reduced environment. If you issue your RS232
commands from that environment you should be mostly good. (but again,
if you do complex storage all of this falls apart, and you have to do
the initrd thing instead).
Note that /usr/lib/systemd/system-shutdown/ is outside of usual
service management. It's run at a point where service management is
already turned off. As such, you really just drop executable scripts
or binaries there, and nothing long-running, no daemons or such, just
simple programs that run and exit.
For details about this facility see the systemd-halt.service(8) man
page. The scripts executed that way will get one parameter, which
tells it what operation is being executed. And if its "poweroff", then
you know that the system is going down for powering off rather than
reboot.
Hi,
This looks like a good way for me.
I cannot really use initrd, because my MicroUPS is intended to work not only
for me but also for an average people, with some .deb package to install.
This is an early version of my device, now it looks different, has higher
power output and so on
https://www.indiegogo.com/projects/microups-for-raspberry-beaglebone-cubie
board#/
I'm aware of race condition but some microcomputers like Raspberry if they
shutdown the operating system, the power is still ON, and I have no way to
figure out when to turn power off. So what I'm doing is telling microups device
to cut power off 30 seconds after shutdown has been initiated (parameter is
configurable).
Microcomputers usually have some SD card, sometimes built-in NAND memory, and
sometimes single SATA SSD disk, so complex storage is not an issue (I think)
The question is, will my binary be able to open RS232 port eg. /dev/ttyACM0
when filesystem is Read-Only ?
And if it is binary it will need to load some libs at least libc at the start.
The man page you pointed to says the parameter is: "halt", "poweroff",
"reboot" or "kexec", so the first two should work for me.
Best Regards
Marek
Post by Lennart Poettering
Lennart
_______________________________________________
systemd-devel mailing list
https://lists.freedesktop.org/mailman/listinfo/systemd-devel
Tilman Baumann
2017-08-09 09:28:01 UTC
Reply
Permalink
Raw Message
DL;DR
UPS shutdowns are tricky. Clean file-systems are not the only concern.
But if you can make assumptions about your storage backend you might be
able to cut corners safely.

In my experience, the only place where you can hook in a non racy way is
in the kernel.

https://unix.stackexchange.com/questions/122557/how-does-the-system-shutdown-of-a-linux-kernel-work-internally

Because this is the hook which a lot of RAID systems and storage
back-ends use to signal a clean poweroff.
If you just halt your system very late in shutdown in userspace and
switch the lights off, the kernel will never run this code.
The result is that for example RAID unclean flags are still set.

UPS kernel drivers generally solve this problem by setting a 'powerfail'
flag before they initiate a shutdown.
The driver is hooked in the shutdown notifier and initiates the poweroff
through the UPS.

Another race condition is, that during the shutdown, the power could
have come back. THE UPS needs to recognize that and still power off the
system to ensure a reboot and then switch it back on.

But I think in your case, using a time based approach is quite valid.
Late in shutdown, set the powerfail flag in the UPS and set a poweroff
timer. While that timer is ticking in the UPS, your system will continue
shutting down safely and halt. And when the timer ran out the UPS will
switch the lights off.
That is by nature racy. But in a well defined system I suppose the risk
is manageable.


Mind you, my exposure tho this stuff is 10 years old or so. A lot might
have happened since then.
Back then I was fighting with a APC UPS which did not support timer
based poweroff and in combination with a 3ware RAID controller lead to
degraded volumes after powerfail.
The shutdown was done in userspace and the UPS did not know timer based
shutdowns. Hence the kernel hook never ran.

BTW. if you don't want to reinvent the wheel. networkupstools (NUT) was
back then the only really sensible software stack that did in practice
most things right.
As I said. My experience is 10 years dated. And I don't know if NUT
works well with systemd. And of course a network based system is
overkill. But perhaps you can have a look at it for some 'best practices'
Post by Lennart Poettering
Post by Marek Floriańczyk
Hi all,
I have a small device MicroUPS which helps me to shutdown my system on
embedded devices, it is controlled by script /etc/init.d/microups and in
this script I need to know whether system is going down for reboot or for
halt, because in case of halt I need to send small data over RS232 to
MicroUPS device to cut the power off.
Note that this is necessarily racy: you can't really know how long the
system will actually take to shut down, hence if you trigger your
hardware for shutdown at an early phase of the shutdown process you
now start racing the remaining shutdown phase against the hardware turning
off power...
If you want to fix this properly, and remove this race entirely the
only fully correct way out I see is to use an initrd for booting, and
doing the RS232 thing from that. Note that if you use a properly
prepared initrd, systemd will actually transition back to it at
shutdown, and while doing so it will permit unmounting the root file
system properly at shutdown. And only if you start the RS232 thing
after the point where the root fs is unmounted you can fully remove
the race in the generic case, since only at that point everything is
fully synced to disk, all complex storage is disassembled and so on.
Now, adding this to the initrd is not the easiest thing in the world,
and in particular in embedded devices avoiding an initrd might be a
good thing. As long as you have no complex storage (i.e. no DM, no
LVM, no LUKS, no RAID, no iscsi, yaddayadda) you can instead cut a
corner and just drop in a shutdown script to
Tilman Baumann
2017-08-09 09:51:07 UTC
Reply
Permalink
Raw Message
Post by Tilman Baumann
DL;DR
UPS shutdowns are tricky. Clean file-systems are not the only concern.
But if you can make assumptions about your storage backend you might be
able to cut corners safely.
In my experience, the only place where you can hook in a non racy way is
in the kernel.
https://unix.stackexchange.com/questions/122557/how-does-the-system-shutdown-of-a-linux-kernel-work-internally
Apologies, I copy and pasted the wrong link
https://stackoverflow.com/questions/5938325/how-do-i-detect-reboot-shutdown-from-a-linux-driver

The magic is here IIRC
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/kernel/reboot.c
Marek Floriańczyk
2017-08-09 12:51:40 UTC
Reply
Permalink
Raw Message
Post by Tilman Baumann
Post by Tilman Baumann
DL;DR
UPS shutdowns are tricky. Clean file-systems are not the only concern.
But if you can make assumptions about your storage backend you might be
able to cut corners safely.
In my experience, the only place where you can hook in a non racy way is
in the kernel.
https://unix.stackexchange.com/questions/122557/how-does-the-system-shutdo
wn-of-a-linux-kernel-work-internally
Apologies, I copy and pasted the wrong link
https://stackoverflow.com/questions/5938325/how-do-i-detect-reboot-shutdown-> from-a-linux-driver
The magic is here IIRC
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree
/kernel/reboot.c _______________________________________________
NUT looks like quite active based on their website.
Microupsd daemon handles also some switches and leds for the end user, I mean
user can press some switch on the device and daemon will perform an action
described in configuration file, so porting everything to NUT would take more
time that I actually got for this.

Thank You all. I will try to write some simple binary, place it in
/lib/systemd/system-shutdown/
and test it.

Best Regards
Marek
Post by Tilman Baumann
systemd-devel mailing list
https://lists.freedesktop.org/mailman/listinfo/systemd-devel
Michael Biebl
2017-08-09 12:54:25 UTC
Reply
Permalink
Raw Message
Post by Marek Floriańczyk
NUT looks like quite active based on their website.
Microupsd daemon handles also some switches and leds for the end user, I mean
user can press some switch on the device and daemon will perform an action
described in configuration file, so porting everything to NUT would take more
time that I actually got for this.
Thank You all. I will try to write some simple binary, place it in
/lib/systemd/system-shutdown/
and test it.
Apparently nut uses this approach as well:
https://packages.debian.org/sid/amd64/nut-server/filelist
--
Why is it that all of the instruments seeking intelligent life in the
universe are pointed away from Earth?
Marek Floriańczyk
2017-08-09 13:22:16 UTC
Reply
Permalink
Raw Message
Post by Michael Biebl
Post by Marek Floriańczyk
NUT looks like quite active based on their website.
Microupsd daemon handles also some switches and leds for the end user, I
mean user can press some switch on the device and daemon will perform an
action described in configuration file, so porting everything to NUT
would take more time that I actually got for this.
Thank You all. I will try to write some simple binary, place it in
/lib/systemd/system-shutdown/
and test it.
https://packages.debian.org/sid/amd64/nut-server/filelist
Thanks for hint.

Marek
Lennart Poettering
2017-08-09 17:20:01 UTC
Reply
Permalink
Raw Message
Post by Tilman Baumann
In my experience, the only place where you can hook in a non racy way is
in the kernel.
I fully agree with this btw. The only safe place if the kernel does
all this. Much like most other drivers UPS drivers should be in the
kernel. That way they can hook into the only really fully correct
place.

Using an initrd is the closest thing otherwise to close the race, but
actually it's still there then, as the kernel flushes ATA buffers and
such when reboot() is invoked, and any initrd-based userspace
implementation will ultimately still race against that...

Lennart
--
Lennart Poettering, Red Hat
Lennart Poettering
2017-08-09 17:15:00 UTC
Reply
Permalink
Raw Message
Post by Marek Floriańczyk
The question is, will my binary be able to open RS232 port eg. /dev/ttyACM0
when filesystem is Read-Only ?
Yes, /dev is unaffected. It's an API VFS, not a real file system, and
those won't be remounted r/o.
Post by Marek Floriańczyk
And if it is binary it will need to load some libs at least libc at the start.
As long as you use only libraries and other resources from the root fs
you should be fine. But you shouldn't reference /var, /home, /srv or /usr/local or
such, if you want to remain compatible with generic systems.
Post by Marek Floriańczyk
The man page you pointed to says the parameter is: "halt", "poweroff",
"reboot" or "kexec", so the first two should work for me.
"halt" just halts the system. It shouldn't result in power being
turned off. It will just make the system freeze eventually, that's all.

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