Discussion:
Single-user actions on reboot
(too old to reply)
Jason Bacon
2023-09-29 13:21:39 UTC
Permalink
I'm wondering if there's a canonical way to schedule a command to run
automatically during the next boot cycle, but before going multiuser.

This would be useful, for example, to run certain tunefs commands on /,
which can only be done in single-user mode, on remotely managed systems.

Running things after going multiuser is easy, of course, but not
sufficient for tunefs commands that cannot be performed on a filesystem
mounted rw.

Thanks...
--
Life is a game. Play hard. Play fair. Have fun.


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Guido Falsi
2023-09-29 13:49:17 UTC
Permalink
Post by Jason Bacon
I'm wondering if there's a canonical way to schedule a command to run
automatically during the next boot cycle, but before going multiuser.
This would be useful, for example, to run certain tunefs commands on /,
which can only be done in single-user mode, on remotely managed systems.
Running things after going multiuser is easy, of course, but not
sufficient for tunefs commands that cannot be performed on a filesystem
mounted rw.
Thanks...
AFAIK there is no ready made tool in base (or ports) for that.

But ezjail uses this trick with rc scripts (removing itself):

https://erdgeist.org/gitweb/ezjail/tree/examples/example/etc/rc.d/ezjail.flavour.example

This is effective but requires the disk mounted r/w which maybe is not
enough for you.

Problem is, without any writable media mounted, how can any script
register it has already ran?

One idea that comes to mind is adding some hook to the main rc script,
before mounting disk r/w, and a second script that removes existing
hooks once disks are r/w.
--
Guido Falsi <***@madpilot.net>



--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Jamie Landeg-Jones
2023-09-29 14:34:10 UTC
Permalink
Post by Guido Falsi
This is effective but requires the disk mounted r/w which maybe is not
enough for you.
Problem is, without any writable media mounted, how can any script
register it has already ran?
To get around that (and I know it's not the same thing, but it does the job
for me), I have a script that checks for a marker file in /etc and if it
exists, only runs if the file timestamp is newer than the current time.

I then have various helper scripts to set the date on that file to (e.g.)
15 minutes in the future.

This shuld really be made more generic (having the commands to be run
within the so called flag file), but as it stands, I just use this as
an added file to /etc/rc.d/

This particular example is based on /etc/rc.d/fsck but is added (don't
replace it!), and just forces a full fsck on all filesystems on boot.

It's not clean, and really should be merged into /etc/rc.d/fsck , to
avoid the double-fsck for one thing, but it was a quick and dirty hack
that does the job.

I have a script "force-fsck" that simply does this:

#!/bin/sh
/usr/bin/touch -t "$(/bin/date -v +15M '+%Y%m%d%H%M.%S')" /etc/.force-fsck-expire

which i run prior to doing the reboot. The drop-in script,
/etc/rc.d/fsck_force_full is here if anyone is interested:

https://www.dyslexicfish.com/jamie/freebsd/etc_rc.d_fsck__force__full

Though the meat of it is this:

| flagfile="/etc/.force-fsck-expire"
|
| # We have to make sure we only use commands here that exist on the root partition,
| # as "/usr" and other partitions won't be mounted at this point. Also, we can't use
| # a marker file that gets removed as the mount at this stage is read-only!
|
| if [ -f "$flagfile" ] && # If the flagfile exists,
| expire_time_1="$(/bin/ls -lD '%s' "$flagfile")" && # read it's "mtime", in seconds since epoch
| [ "$expire_time_1" ] && # If we get a result,
| expire_time_2="${expire_time_1% $flagfile}" && # strip the filename off the end of the string.
| [ "x$expire_time_2" != "x$expire_time_1" ] && # If this operation is successful,
| expire_time_1="${expire_time_2##* }" && # strip the rest of the cruft from beginning of the string.
| [ "x$expire_time_2" != "x$expire_time_1" ] && # If this operation is successful,
| [ "${expire_time_1%%*[!0-9]*}" ] && # and if the result is a valid integer,
| [ "$expire_time_1" -gt "$(/bin/date +%s)" ] # and if the result is older than the current date, then.....
| then
| ........
| fi

Jason, the script could easily be modified by replacing the fsck command with whatever you want to run..

Cheers, Jamie


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Chris
2023-09-29 16:12:00 UTC
Permalink
Post by Guido Falsi
Post by Jason Bacon
I'm wondering if there's a canonical way to schedule a command to run
automatically during the next boot cycle, but before going multiuser.
This would be useful, for example, to run certain tunefs commands on /,
which can only be done in single-user mode, on remotely managed systems.
Running things after going multiuser is easy, of course, but not sufficient
for tunefs commands that cannot be performed on a filesystem mounted rw.
Thanks...
AFAIK there is no ready made tool in base (or ports) for that.
https://erdgeist.org/gitweb/ezjail/tree/examples/example/etc/rc.d/ezjail.flavour.example
This is effective but requires the disk mounted r/w which maybe is not
enough for you.
Problem is, without any writable media mounted, how can any script register
it has
already ran?
One idea that comes to mind is adding some hook to the main rc script,
before
mounting disk r/w, and a second script that removes existing hooks once
disks are
r/w.
Indeed. Maybe at the same point the system tastes the disk(s) to see if
they've been dismounted
properly and then running fsck(8) if not. Using the same method to perform
your task(s)?

--Chris


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Warner Losh
2023-09-29 16:56:53 UTC
Permalink
Post by Jason Bacon
Post by Guido Falsi
Post by Jason Bacon
I'm wondering if there's a canonical way to schedule a command to run
automatically during the next boot cycle, but before going multiuser.
This would be useful, for example, to run certain tunefs commands on /,
which can only be done in single-user mode, on remotely managed systems.
Running things after going multiuser is easy, of course, but not
sufficient
Post by Guido Falsi
Post by Jason Bacon
for tunefs commands that cannot be performed on a filesystem mounted rw.
Thanks...
AFAIK there is no ready made tool in base (or ports) for that.
https://erdgeist.org/gitweb/ezjail/tree/examples/example/etc/rc.d/ezjail.flavour.example
Post by Guido Falsi
This is effective but requires the disk mounted r/w which maybe is not
enough for you.
Problem is, without any writable media mounted, how can any script
register
Post by Guido Falsi
it has
already ran?
One idea that comes to mind is adding some hook to the main rc script,
before
mounting disk r/w, and a second script that removes existing hooks once
disks are
r/w.
Indeed. Maybe at the same point the system tastes the disk(s) to see if
they've been dismounted
properly and then running fsck(8) if not. Using the same method to perform
your task(s)?
At work we just have a custom rc script to do that for all our content
disks (only os disks are in fstab).

As for writable media... you could set a uefi variable... or create a small
MD partition (call it /once) that an rc script in a later phase could use
to mop up and then free. The latter is easier, but in many environments the
former is more durable and reliable if there's an early crash that happens
before mopup and you can really only run something once...

Warner
Jason Bacon
2023-09-29 21:32:46 UTC
Permalink
Post by Jason Bacon
Post by Guido Falsi
Post by Jason Bacon
I'm wondering if there's a canonical way to schedule a command
to run
Post by Guido Falsi
Post by Jason Bacon
automatically during the next boot cycle, but before going
multiuser.
Post by Guido Falsi
Post by Jason Bacon
This would be useful, for example, to run certain tunefs
commands on /,
Post by Guido Falsi
Post by Jason Bacon
which can only be done in single-user mode, on remotely managed
systems.
Post by Guido Falsi
Post by Jason Bacon
Running things after going multiuser is easy, of course, but not
sufficient
Post by Guido Falsi
Post by Jason Bacon
for tunefs commands that cannot be performed on a filesystem
mounted rw.
Post by Guido Falsi
Post by Jason Bacon
Thanks...
AFAIK there is no ready made tool in base (or ports) for that.
https://erdgeist.org/gitweb/ezjail/tree/examples/example/etc/rc.d/ezjail.flavour.example <https://erdgeist.org/gitweb/ezjail/tree/examples/example/etc/rc.d/ezjail.flavour.example>
Post by Guido Falsi
This is effective but requires the disk mounted r/w which maybe
is not
Post by Guido Falsi
enough for you.
Problem is, without any writable media mounted, how can any
script register
Post by Guido Falsi
it has
already ran?
One idea that comes to mind is adding some hook to the main rc
script,
Post by Guido Falsi
before
mounting disk r/w, and a second script that removes existing
hooks once
Post by Guido Falsi
disks are
r/w.
Indeed. Maybe at the same point the system tastes the disk(s) to see if
they've been dismounted
properly and then running fsck(8) if not. Using the same method to perform
your task(s)?
At work we just have a custom rc script to do that for all our content
disks (only os disks are in fstab).
As for writable media... you could set a uefi variable... or create a
small MD partition (call it /once) that an rc script in a later phase
could use to mop up and then free. The latter is easier, but in many
environments the former is more durable and reliable if there's an early
crash that happens before mopup and you can really only run something
once...
Warner
Thanks for the brainstorming, guys. This is about what I expected to
hear. What I had done to automate completion of base upgrades after the
required reboot is add the following to /etc/rc.local:

# Would be nice if this were added to the default rc.local
rc_dir=/etc/rc.local.d
for script in $rc_dir/*; do
/bin/sh $script
done

Then drop a very simple self-removing script into
/etc/rc.local.d/freebsd-update-install.sh:

#!/bin/sh -e

/usr/sbin/freebsd-update install
/usr/sbin/pkg upgrade -y
rm -f $rc_dir/freebsd-update-install.sh

I just realized I could do the same thing by creating a new rc script
such as /etc/rc.d/local.single, modeled on /etc/rc.d/local, but running
earlier and using a different script and directory, e.g.
/etc/rc.local.single and /etc/rc.local.single.d/.

Cheers,

J
--
Life is a game. Play hard. Play fair. Have fun.



--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Jason Bacon
2023-09-30 14:48:51 UTC
Permalink
Post by Guido Falsi
Post by Jason Bacon
I'm wondering if there's a canonical way to schedule a command to run
automatically during the next boot cycle, but before going multiuser.
This would be useful, for example, to run certain tunefs commands on
/, which can only be done in single-user mode, on remotely managed
systems.
Running things after going multiuser is easy, of course, but not
sufficient for tunefs commands that cannot be performed on a
filesystem mounted rw.
Thanks...
AFAIK there is no ready made tool in base (or ports) for that.
https://erdgeist.org/gitweb/ezjail/tree/examples/example/etc/rc.d/ezjail.flavour.example
This is effective but requires the disk mounted r/w which maybe is not
enough for you.
Problem is, without any writable media mounted, how can any script
register it has already ran?
One idea that comes to mind is adding some hook to the main rc script,
before mounting disk r/w, and a second script that removes existing
hooks once disks are r/w.
Thanks for the brainstorming, gents. This helped narrow my direction,
and I implemented what I need by creating a /etc/rc.d/local_early based
on the standard /etc/rc.d/local:

https://github.com/outpaddling/auto-admin/blob/master/Data/local_early
https://github.com/outpaddling/auto-admin/blob/master/Data/rc.local_early

The only real difference is when it runs.

As an example of how to use it, to toggle the soft-updates journal using
tunefs, I generate a script like the following and drop it in
/etc/rc.local_early.d. It runs on the next reboot and removes itself.

for fs in /dev/ada0s1a /dev/da0p1; do
tunefs -j disable $fs
mount -u -o rw /
rm -f /etc/rc.local_early.d/auto-su+j-toggle.sh
done
reboot

This is now integrated into auto-su+j-toggle (WIP version), part of
sysutils/auto-admin.
--
Life is a game. Play hard. Play fair. Have fun.



--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Loading...