[SOLVED] [PATCH] sysvinit-scripts: Fix a few sub-optimal corner cases
SlackwareThis Forum is for the discussion of Slackware Linux.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
[PATCH] sysvinit-scripts: Fix a few sub-optimal corner cases
A summary follows, no need to look inside the attachment only to see whats meant:
====
1) "rc.sysvinit" runs the "kill scripts" from the wrong (previous instead of current) runlevel directory.
This is a real issue mostly for "enterprice level" third party software packages, because they are often written for distributions where runlevel directories are the normal way. They then have issues on Slackware because they are not stopped cleanly.
A very simple example:
A service should run in runlevel 4 but not in runlevel 3, and should be stopped on shutdown/reboot. So a start (Sxx) link is placed in "rc4.d" and kill (Kxx) links in "rc0.d", "rc6.d" and "rc3.d". (Often more kill links are placed in the other runlevels too.)
In its current form this service is running in runlevel 4, but is not stopped on shutdown, reboot and also when switching to runlevel 3 because in "rc4.d" there is no stop link.
[Oh..., I acknowledge "rc.sysvinit" it's one of the oldest (1999!) original scripts of the distribution coming from the master himself. Sorry :-)]
====
2) Move the cleanup of the cleanup of "/var/lock/subsys" from
"rc.6" to "rc.S".
I remember having issues in the past after every power outage or abrupt shutdown...
Some services take the existance of the flag files too serious and are not started on the first following boot. The real cause was not easy to debug because it happened only a few times and after every regular restart, the service worked as expected...
====
The changes are actually very small and are easy to verify for every admin who was actually affected by these quirks in the past.
Hopefully it gets accepted for the coming Slackware 14.2...
Runlevel 3 and 4 are identical, but 4 is the DM startup.
To be fair, you could do it this way, but basically, rc.4 is just an add-on to rc.3. rc.3 is what really runs, even if rc.4 is activated. Calling rc.sysinit from rc.3 during halt is correct due to how the process tree is laid out.
During shutdown it basically goes in this order:
1. rc.local_shutdown kills all local services.
2. rc.sysinit kills any sysvinit compatibility scripts.
3. services started by rc.M are stopped.
4. services started by rc.S are stopped.
5. system is remounted read-only and halted.
1 and 2 will always be called first even if in runlevel 3 or 4, though rc.4 is not a true runlevel, it's mainly runlevel 3 executed with the addition of a display manager, so realistically it's still runlevel 3.
You have to kill the tree correctly in order to have a proper shutdown, or else the local disk won't be dismountable and you'll end up with a corrupted journal and need to run fsck.#### each startup.
I'm not so sure about clearing out the locks in rc.S. Speaking from experience as a sysadmin, you don't always want things to startup automatically after an abrupt halt. Sometimes there will be recovery actions to take and the locks may be useful in preventing things from restarting prematurely, but I guess it all depends on the thing being started and you can look at it both ways.
On the rc.sysvinit thing, OP is correct: it runs the wrong kill scripts. It sounds unintuitive but sysvinit should run the kill scripts for the runlevel it is switching to, not the run level it is switching from. I've noticed it before but as I've never actually seen anyone using it on slackware, I didn't bother raising the issue.
Your summary contains all the activities during shutdown.
And regarding runlevel 4 in my example, I stand corrected.
At startup:
# System initialization (runs when system boots).
si:S:sysinit:/etc/rc.d/rc.S
# Script to run when going multi user.
rc:2345:wait:/etc/rc.d/rc.M
First rc.S ist started once.
Then rc.M is started whenever going from a non-2,3,4,5 runlevel to a 2,3,4,5-runlevel.
And from within these scripts rc.sysvinit is called somewhere and it starts any sysv start scripts
in the RIGHT runlevel directory.
Afterwards when switching between runlevel 2,3,4,5 rc.M is never called again and so no rc.sysvinit is run.
This is not the complete sysv behavior, but for server processes it is good enough.
The existing situation is the best sysv emulation one can get using the existing framework.
So let's stop here, this is Slackware, we want to keep it so :-)
At shutdown/reboot:
# Runlevel 0 halts the system.
l0:0:wait:/etc/rc.d/rc.0
# Runlevel 6 reboots the system.
l6:6:wait:/etc/rc.d/rc.6
This is actually the same script for two different runlevels and so it is doing mostly the same.
From within this scripts rc.sysvinit is called again.
And here is the problem:
The existing rc.sysvinit DOES NOT run any sysv kill scripts in the RIGHT "rc$runlevel.d" directory!
Instead it DOES run some unwanted sysv kill scripts which happen to be placed in the "rc$prevlevel.d" directory!
My post (patch) wants to fix only this serious problem of rc.sysvinit.
All other listed activities are OK and I don't want to break them.
Never change a running system :-)
Stupid question: being sick about what happen on Runlevel 4 (i.e. frozen X and its merry friends), I manage to switch to console, and to invoke the Saint Init 3. That, right now, kill all the crap from runlevel 4 and give me a clean runlevel 3. I used no one time this way to "do a soft reset" of the desktop.
IF your thingie is implemented in Slackware, what happen with this "soft reset" style? It is possible?
Hi GazL, thank you for confirming my issue regarding rc.sysvinit.
Your arguments seem reasonable also.
So I tried to look inside a distributions using these subsystem locks.
It looks these locks are not actually checked by the rc.scripts of the installed packages itself.
They only create/clear the lock file like so:
Start: [ $RETVAL -eq 0 ] && touch /var/lock/subsys/<name>
Stop: rm -fr /var/lock/subsys/<name>
Then they are checked within the start/stop framework of the distribution before running the
rc.<name> script.
If a file with the subsystem name is found in the subsys directory:
When starting the framework prints "Subsystem already running" and does not run the sysv start script.
When stopping "Subsystem is not running" is printed and the sysv kill script is not run.
During writing this answer I was not able to find the location where /var/lock/subsys is cleared.
But I often heard /ver/lock and /var/run are placed in "tmpfs" ramdisks and so automagically empty at startup.
I think the clearing at start emulates this better then the existing undeterministic location only at normal shutdown.
In Slackware's inittab: runlevel 4 and the corresponding rc.4 script is mananged by initd, look at the "respawn"
The script should not terminate as long as your "display manager" (DM) is running.
This is in contrast to all the other runlevel scripts with "wait".
If yout desktop has problems you probably had noticed the flickering where initd is trying to "respawn"
the rc.4 script several times before giving up (this is a important feature of initd).
Also if the rc.4 script is not terminating even if everything is wrong within your desktop this is ok from
the view of the initd.
If you do "telinit 3" then initd kill the DM and all its child because rc.4 should run only in runlevel 4.
Then "telinit 4" restarts rc.4 again as you are entering runlevel 4 again.
This is repeatable and does not disturb e.g. the rc.M script as it is only run once upon entering one of the
runlevels 2,3,4,5 and never again when staying withi them.
I've got no problem with /var/run being on a tmpfs and /var/lock was originally intended for device lock files for things like callout devices (serial modems and what have you), so and again on boot clearing those out wouldn't be a problem as nothing will be using the devices. What I'm less clear on is /var/lock/subsys and whether it should be considered persistent or not, but after a quick read it seems its just for the init system, in which case I retract my previous comments. It looks like persistent locks such as I were considering need to be put elsewhere.
As for the rc.sysvinit script, it wouldn't be hard to make it run when swapping between runlevels. One would just need to remove its invocation from rc.M and add it to its own 'wait' line in inittab (one per runlevel) to run directly after rc.M. And do something similar but before l0/l6 to cover shutdown. In theory anyway, I haven't tried it.
In the way I've seen things done, rc.sysvinit is a separate startup done only for compatibility purposes for scripts that do not have an existence yet for Slackware. The amount of scripts has been greatly reduced to a handful thanks to efforts at SlackBuilds.org to create Slackware specific bsd-style rc scripts, but even then, most sysvinit scripts ran from /etc/rc.d/init.d have to have their configuration line edited as most I've seen traditionally call for something like /lib/lsb/init-function rather than /etc/rc.d/init.d/function as the resource script.
rc.sysvinit should be handling it's own start/stop affairs without the aid of rc.M, rc.S, or any other major Slackware system script unless the rc.sysvinit is called for that function.
I honestly haven't used the traditional Slackware scripts for a while now due to using OpenRC from SlackBuilds.org which offers it's own brand of scriptworks, and contains a huge plethora of scripts to utilize for any system.
I see it more from the sysadmin perspective. If there are more ways for things to do,
then I gladly give my users as much of them as I can make reasonable available.
And they also can expect that all these things work reasonable.
For my own part I will of course prefer the traditional ways.
And IMHO the sysv init scripts together with Slackware's init scripts are THE two traditional ways.
And this two of course don't need such modern crap^H^H^H^Hthings like lsb. They were here long before.
I'm am mostly satisfied with the way Slackware is doing things. But I also like the freedom to look at
these from more than one side.
I must admit, Slackware's very static design sometimes has its disadvantages:
The large start/stop "conglomerates"
/etc/rc.d/rc.M, /etc/rc.d/rc.K, /etc/rc.d/rc.6, /etc/rc.d/rc.S, /etc/rc.d/rc.4
were in fact very limiting every time I had to install additional low level system components.
An example from one of my servers where I had to integrate an external iSCSI storage system:
The iSCSI and multipath daemons must be started AND stopped at the exact right time,
not at the time rc.sysvinit or rc.local happens to run. And this was only one single step
in the whole start/stop process...
Slackware's rc.sysvinit is IMHO designed only for pure user space third party applications.
They are mostly only available as huge binary installers(!) and are designed for one of the
enterprise linux distributions.
Sp when the poor sysadmin is forced to install such a thing then he normally is taking precautions:
By trying it out on a test system and by backing up parts of the system to find out which files are
installed or modified he gets an overview what where this software package is touching his system.
So he knows what is going on finally on the production system.
During this boring process nothing is more frustrating than realizing after struggling with problems
that the only cause comes from such a very simple mistake inside rc.sysvinit of your own well known
distribution.
Stop, better back to the topic :-)
So let's fix it, not remove and/or replace it with unstable modern start/stop managers!
Tue Nov 24 03:31:43 UTC 2015
a/sysvinit-scripts-2.0-noarch-23.txz: Rebuilt.
rc.6: Don't clear /var/lock/subsys.
rc.S: Clear /var/lock/subsys here instead, so that the directory will be
cleared out on startup after a power failure.
rc.sysvinit: Run kill scripts for the current, not previous, runlevel.
Thanks to Sl4ck3ver.
Sorry for the hijack but since the original problem is solved and this thread is about init scripts i thought it is better to post here than in the desired updates.
In rc.S there is code for deleting stale mount information (mtab, mtab~, mtab.tmp files) and recreating mtab. However, it deletes it without checking if mtab is a symbolic link to /proc/self/mounts. Do you think the code should be changed to account for symlinks or having mtab as symlink is an obscure scenario that not many people use ?
Code:
diff --git a/rc.d/rc.S b/rc.d/rc.S
index 6607ce4..c3c09d0 100755
--- a/rc.d/rc.S
+++ b/rc.d/rc.S
@@ -264,7 +264,9 @@ fi # Done checking root filesystem
# Any /etc/mtab that exists here is old, so we start with a new one:
-/bin/rm -f /etc/mtab{,~,.tmp} && /bin/touch /etc/mtab
+if [ ! -L /etc/mtab ]; then
+ /bin/rm -f /etc/mtab{,~,.tmp} && /bin/touch /etc/mtab
+fi
# Add entry for / to /etc/mtab:
/sbin/mount -f -w /
As an example, i use the above change locally for some time and it seems to work fine.
My personal preference is for 'mtab' to remain a real file. I don't care for the symlinking idea at all, and I have noticed differences in behaviour in the past between the mtab file and /proc/self/mounts when dealing with automount(autofs).
Having said that, if rc.S were to check for a symlink before acting I have no objections to that.
P.S. Re your patch: if /etc/mtab is a symlink to /proc/mounts then you'd probably also want to pull the fake mounts (mount -f's) within your 'if' block as they only really make sense if its a file. mount will check if they're already in there anyway, so it won't hurt to leave them outside, but there not much point running it just for it to say "yeah, that's already in there".
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.