Open gyakovlev opened 5 years ago
reported by user gmturner on irc
irc gmturner here :)
I wasn't 100% sure whether https://github.com/OpenRC/openrc/blob/master/sh/openrc-run.sh.in#L227-L229:
if ! sourcex -e "$_conf_d/$_c.$RC_RUNLEVEL"; then
sourcex -e "$_conf_d/$_c"
fi
and https://github.com/OpenRC/openrc/blob/master/sh/openrc-run.sh.in#L234-L236:
if ! sourcex -e "$_conf_d/$RC_SVCNAME.$RC_RUNLEVEL"; then
sourcex -e "$_conf_d/$RC_SVCNAME"
fi
are correct, absent any corner case? Put in concrete terms, in runlevel default, should the presence of conf.d/sshd.default prevent the evaluation of conf.d/sshd entirely, by design?
Then we have an ambiguity about a script like conf.d/net.default if we are working on behalf of init.d/net.default in the default runlevel. An argument could be made, assuming both that the above code is not totally wrong, and that there is a policy to resolve such ambiguities about the meaning of a conf.d/net.default in favor of treating it as a runlevel-specific script, that the current behavior is correct, specifically, something like:
If openrc finds a file conf.d/net.default in the default runlevel, it is going to treat that as the runlevel-targeted file, not the default-variant-targeted configuration for the multiplexed net script-family. Therefore, it must ignore conf.d/net.
I think it's pretty counterintuitive though. In my case, I didn't even know, until gyakovlev set me straight on IRC, that the runlevel-specific conf.d/ files were a thing, and was quite confused by this. Also that policy would strongly suggest we should be ignoring conf.d/net.default when we are not in the default runlevel, on any system which /has/ a default runlevel, which we clearly aren't actually doing.
I think the more intuitive policy would be the opposite one; we treat this file as the regular demultiplexed conf.d/ file specific to ${RC_SVCNAME}, regardless of runlevel, and if the user really wants a runlevel-specific multiplexed conf.d file, tough cookies (they could still put ${RC_RUNLEVEL}-conditional code into conf.d/${RC_SVCNAME}, after all and they can still put demultiplexed, runlevel-targeted settings in the usual place, i.e., conf.d/net.default.default, although they would need to unset variables from conf.d/net.default if they didn't want them to apply).
Then the behavior is totally buggy and this needs rewriting. If we are openrc-run trying to find conf.d scripts to source, all of:
these() {
case "${RC_SVCNAME}" in
*.*)
_family=${RC_SVCNAME%%.*}
# yes, the second one is just conf.d/${RC_SVCNAME}.
# spelled out this way for clarity
echo conf.d/${_family}
echo conf.d/${_family}.${RC_SVCNAME#${_family}.}
case "${RC_SVCNAME#${_family}.}" in
${RC_RUNLEVEL})
# no point in sourcing it twice...
:;
;;
*)
echo conf.d/${_family}.${RC_RUNLEVEL}
;;
esac
echo conf.d/${_family}.${RC_SVCNAME#${_family}.}.${RC_RUNLEVEL}
;;
*)
echo conf.d/${RC_SVCNAME}
echo conf.d/${RC_SVCNAME}.${RC_RUNLEVEL}
;;
esac
}
candidates=$(these)
need sourcing, which isn't at all what's happening since any time we find a suitable ${foo}.${RC_RUNLEVEL}
we fail to source ${foo}
, including when [ "${RC_RUNLEVEL}" = "${_family}" ]
In that case, it's possible the user doesn't know anything about all these quirks, but simply tried to make a conf.d file for their regular init.d/foo.bar script which happened to have a dot in the name (essentially a supported use-case, even though this may technically have created a multiplexed singleton script).
The existing behavior in the edge case where a runlevel shares a name with a multiplexed variant (i.e., runlevel eth0) seems at best extremely counter-intuitive -- but far more likely buggy.
This is perhaps a less obscure problem than it seems at first glance. For example, creating "lo" and "hi" runlevels could wreak havoc on a netifrc box that required extra addresses assigned to the "127/8" address-space. Less plausibly, but more inscrutably, an "idmapd" or "pipefs" runlevel could give an NFS sysadmin a very confusing several hours of head-scratching while all his users waited for services to be restored.
I hope all my pseudo-code is not too buggy and some of the foregoing was comprehensible :)
@gyakovlev and I discussed, as a potential solution to the underlying semantic deficiency, changing the .${RC_RUNLEVEL}
suffix to _${RC_RUNLEVEL}
, or making that character configurable, which might or might not create a big maintainability problem (and potentially creates a backward-incompatibility, if done unilaterally and without corresponding package-manager fixups).
https://github.com/OpenRC/openrc/blob/3eef6e91274f2e07bd566f206e89d9b0b9c45fb9/sh/openrc-run.sh.in#L223-L237
consider user having a file
/etc/init.d/app
and a symlink to above file ^/etc/init.d/app.default
and it's added to runlevel
default
openrc will try to source runlevel-specific config first, which will be
/etc/conf.d/app.default.default
and on next try will try to source/etc/conf.d/app
because bash string %% regex is greedy_c=${RC_SVCNAME%%.*}
so basically there need to be some logic handling this case.
or regex not as greedy (single
%
), but not sure how it will affect existing services or symlinks.as I understand intention is to load specific file first and fallback to generic one if it fails.
but there is funky behavior if user creates a postfix that clashes with runlevel name.