Bug#1022837: /lib/runit/run_sysv_scripts uses wrong test to skip initscripts

2023-04-02 Thread Lorenzo
Hi,

On Tue, 28 Mar 2023 20:30:59 +0200
Andras Korn  wrote:

> On Tue, Mar 28, 2023 at 01:10:36AM +0200, Lorenzo wrote:
> > I propose the following:
> > 
> > * patch runit-helper, update-service and /lib/runit/trigger_sv so
> > that every (package provided) runit service is always represented
> > in /etc/service/, either with a foo symlink (enabled) or with a
> > .foo symlink (disabled).
> 
> OK, this works (although I don't see why it's necessary), as long as
> nothing gets confused by the existence of both symlinks. For example,
> under this scheme, I may have:
Both links should not happen, a service is either enabled or disabled

> 
> /service/ssh -> /some/dir/where/I/keep/my/services/ssh
> # created "manually"
ok this should already override the default link to /etc/sv, there is
no code that replaces your link with one to /etc/sv/

> /service/.ssh -> /etc/sv/ssh
> # created during container provisioning to prevent
> the ssh package from installing its version of the service (otherwise
> it creates /etc/service/ssh/ssh)
old bug, runit-helper code didn't check for the existance of the symlink
and there was an infinite loop of symlinks (it doesn't create problem
to the service, but in any case should not happen), I thought I already
fixed this, will have another look

> 
> If there is potential for confusion, then a mechanism to delete the
> .ssh symlink if/when the plain ssh symlink is present would also be
> needed.
> 
> >   This way I (as a packager) can test /etc/service/ to know if a
> > runscript exists in /etc/sv/.
> 
> You can, but I'm not sure I see why you have to. The /etc/sv location
> is not special per se; why does it matter whether there is anything
> there in particular?

Since I want to provide the nanny-automation (enable a service
when the package that ships the corresponding bin is installed and
disable it when such package is removed) I have to know where the stash
of available runit services is, to check if a native service exists and
to enable it by creating a symlink to it.
That's what other inits like Sysv and systemd do, and users that come
from those other inits expect such automation: that would be the case
for a large part of the ~350 runit-init users in Devuan.

> 
> >   For users that have their own runscripts collection somewhere in
> > the filesystem: they will enable their services by creating the foo
> > symlink, and they can have the sysv emulation skip certain services
> > (let's say a bar service) by creating a /etc/service/.bar symlink.
> 
> That's a needless extra hoop to jump through. When deciding whether
> to skip invoking /etc/init.d/bar, why is it better to check for the
> existence of "/etc/service/.bar" than "/etc/service/bar"? The latter
> needs to exist anyway, because that's what will cause runit to start
> the service.
Reason is that if none of the two link is there I'm sure that no
package provided runit service is available. For a use case on
user side, see at the bottom.

> > * turn the run_sysv_scripts into a runit service that test for
> > /etc/service/$name. Two main reason for this:
> 
> This needs to be thought through carefully (it would need to only run
> once, but finish before other services are started -- for example, it
> could do a runsvchdir in ./finish).

Not necessarily: by default in runit services are started asynchronously
so in principle there is no reason to run sysv scripts sequentially and
strictly before any runit service. Of course there are dependencies, my
bet is that no more than two maybe three loop are needed.
Of course there is an entire Debian cycle to prove me wrong.

> 
> >   1. users can disable it, or change it at their will, while any
> > change into /lib/runit/run_sysv_scripts is overwritten by the
> > package, so users are forced to change stage 2 and create their own
> > version of the script
> 
> You could also achieve this by preferring
> /etc/runit/lib/run_sysv_scripts if it is executable, and only running
> /lib/runit/run_sysv_scripts if not. Even more complex setups would
> also be possible, with /lib/runit/run_sysv_scripts relying on shell
> functions that a user-supplied sourced file could override, but I
> think that would go too far.
The point is that I would like to drop this sysv emulation; runit need
to be able to run scripts before runsvdir starts services, an it can be
done in stage2, but such scripts don't necessarily need to be sysv
scripts, and don't need to obey the sysv (insserv) order. For now I'm
just going to separate the two mechanism.

> 
> >   2. when runit services are mixed with sysv scripts in the start
> > sequence, the run_sysv_scripts can be RC-buggy, see #1024969 [1]
> > for an example
> 
> Yeah, that's a hard problem to solve cleanly.
> 
> Maybe you just shouldn't ship (or enable by default) runit services
> that initscript-based stuff frequently depends on. I'm not sure how
> much else there is, other than dbus.
I think there are syslog, rmnologin and dbus: the one that really

Bug#1022837: /lib/runit/run_sysv_scripts uses wrong test to skip initscripts

2023-03-28 Thread Andras Korn
On Tue, Mar 28, 2023 at 01:10:36AM +0200, Lorenzo wrote:

Hi,

> Please follow up and let me know if my idea would solve this issue or at 
> least improve the situation from your point of view:
> > 
> > Checking for /etc/sv/$name and skipping initscripts if those directories 
> > exist is wrong for two reasons:
> > 
> >  1. /etc/sv/$name may not be symlinked into /etc/service (false positive);
> > 
> >  2. /etc/service may contain a symlink to a service directory for this 
> > service that is elsewhere in the filesystem, not in /etc/sv (false 
> > negative).
> > 
> > As a minimum, I suggest the following: instead of /etc/sv/$name, check for 
> > /etc/service/$name (and $name-daemon if necessary), and not with "-d" but 
> > "-L" (because when running rcS.d, the target of the symlink may only appear 
> > later, for example when a new filesystem is mounted).
> 
> I propose the following:
> 
> * patch runit-helper, update-service and /lib/runit/trigger_sv so that every 
> (package provided) runit service is always represented in /etc/service/, 
> either with a foo symlink (enabled) or with a .foo symlink (disabled).

OK, this works (although I don't see why it's necessary), as long as nothing 
gets confused by the existence of both symlinks. For example, under this 
scheme, I may have:

/service/ssh -> /some/dir/where/I/keep/my/services/ssh  # created "manually"
/service/.ssh -> /etc/sv/ssh# created during 
container provisioning to prevent the ssh package from installing its version 
of the service (otherwise it creates /etc/service/ssh/ssh)

If there is potential for confusion, then a mechanism to delete the .ssh 
symlink if/when the plain ssh symlink is present would also be needed.

>   This way I (as a packager) can test /etc/service/ to know if a runscript 
> exists in /etc/sv/.

You can, but I'm not sure I see why you have to. The /etc/sv location is not 
special per se; why does it matter whether there is anything there in 
particular?

>   For users that have their own runscripts collection somewhere in the 
> filesystem: they will enable their services by creating the foo symlink, and 
> they can have the sysv emulation skip certain services (let's say a bar 
> service) by creating a /etc/service/.bar symlink.

That's a needless extra hoop to jump through. When deciding whether to skip 
invoking /etc/init.d/bar, why is it better to check for the existence of 
"/etc/service/.bar" than "/etc/service/bar"? The latter needs to exist anyway, 
because that's what will cause runit to start the service.

>   This would also prevent runit package (and runit-helper) to enable the bar 
> service, if any /etc/sv/bar exists, because the logic in runit-helper and 
> sv_trigger only test if the symlink (or dot-symlink) exists, but it doesn't 
> care where it points.

Again, to me it seems that the existence of /etc/service/bar should be 
sufficient. If it exists, the service is enabled. If it needs to be disabled in 
a way that it can be re-enabled later, you can rename the existing bar symlink 
to ".bar", regardless of where it points.

>   In any case runit/runit-helper only creates and remove links in the 
> /etc/runit/runsvdir/default directory, so if you point runsvdir to another 
> directory runit package doesn't enable or disable anything for you.

Perhaps it should be called debian-default; but it's good to know that using a 
differently-named runsvdir is a way of opting out of much of the 
nanny-automation I find so annoying. :)

> * turn the run_sysv_scripts into a runit service that test for 
> /etc/service/$name. Two main reason for this:

This needs to be thought through carefully (it would need to only run once, but 
finish before other services are started -- for example, it could do a 
runsvchdir in ./finish).

>   1. users can disable it, or change it at their will, while any change into 
> /lib/runit/run_sysv_scripts is overwritten by the package, so users are 
> forced to change stage 2 and create their own version of the script

You could also achieve this by preferring /etc/runit/lib/run_sysv_scripts if it 
is executable, and only running /lib/runit/run_sysv_scripts if not. Even more 
complex setups would also be possible, with /lib/runit/run_sysv_scripts relying 
on shell functions that a user-supplied sourced file could override, but I 
think that would go too far.

>   2. when runit services are mixed with sysv scripts in the start sequence, 
> the run_sysv_scripts can be RC-buggy, see #1024969 [1] for an example

Yeah, that's a hard problem to solve cleanly.

Maybe you just shouldn't ship (or enable by default) runit services that 
initscript-based stuff frequently depends on. I'm not sure how much else there 
is, other than dbus.

Alternatively, you could ship a one-shot runit service that depends on the dbus 
service and that invokes all initscripts that declare a dependency on dbus... 
Far from my idea of clean.

I also have another idea but it's so complex 

Bug#1022837: /lib/runit/run_sysv_scripts uses wrong test to skip initscripts

2023-03-27 Thread Lorenzo
Hi Andras,

Please follow up and let me know if my idea would solve this issue or
at least improve the situation from your point of view:
> 
> Checking for /etc/sv/$name and skipping initscripts if those
> directories exist is wrong for two reasons:
> 
>  1. /etc/sv/$name may not be symlinked into /etc/service (false
> positive);
> 
>  2. /etc/service may contain a symlink to a service directory for
> this service that is elsewhere in the filesystem, not in /etc/sv
> (false negative).
> 
> As a minimum, I suggest the following: instead of /etc/sv/$name,
> check for /etc/service/$name (and $name-daemon if necessary), and not
> with "-d" but "-L" (because when running rcS.d, the target of the
> symlink may only appear later, for example when a new filesystem is
> mounted).

I propose the following:

* patch runit-helper, update-service and /lib/runit/trigger_sv so
  that every (package provided) runit service is always represented in
  /etc/service/, either with a foo symlink (enabled) or with a .foo
  symlink (disabled).
  This way I (as a packager) can test /etc/service/ to know if a
  runscript exists in /etc/sv/.
  For users that have their own runscripts collection somewhere in the
  filesystem: they will enable their services by creating the foo
  symlink, and thay can have the sysv emulation skip certain services
  (let's say a bar service) by creating a /etc/service/.bar symlink.
  This would also prevent runit package (and runit-helper) to enable
  the bar service, if any /etc/sv/bar exists, because the logic in
  runit-helper and sv_trigger only test if the symlink (or
  dot-symlink) exists, but it doesn't care where it points.
  In any case runit/runit-helper only creates and remove links in the
  /etc/runit/runsvdir/default directory, so if you point runsvdir to
  another directory runit package doesn't enable or disable anything
  for you.

* turn the run_sysv_scripts into a runit service that test for
  /etc/service/$name. Two main reason for this:
  1. users can disable it, or change it at their will, while any change
  into /lib/runit/run_sysv_scripts is overwritten by the package, so
  users are forced to change stage 2 and create their own version of
  the script
  2. when runit services are mixed with sysv scripts in the start
  sequence, the run_sysv_scripts can be RC-buggy, see #1024969 [1] for
  an example
> 
> This is still imperfect during boot because /etc/service may point to
> some directory that is not the one we'll switch to with runsvdir in
> stage 2. I don't know what the best way of handling this (likely
> rare) case is, but the following solutions come to mind:

I think with the above solution this should be no longer a problem as
we run the sysv emulation from within runsvdir.
Hopefully this will make your "runit" life easier (?)

> András
> 

Lorenzo

[1] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%231024969



Bug#1022837: /lib/runit/run_sysv_scripts uses wrong test to skip initscripts

2022-11-16 Thread Lorenzo
Control: tags -1 moreinfo

I need more info to proceed with this bug

On Wed, 26 Oct 2022 18:26:02 +0200 Andras Korn
 wrote:

> 
> Checking for /etc/sv/$name and skipping initscripts if those
> directories exist is wrong for two reasons:
> 
>  1. /etc/sv/$name may not be symlinked into /etc/service (false
> positive);
> 
>  2. /etc/service may contain a symlink to a service directory for
> this service that is elsewhere in the filesystem, not in /etc/sv
> (false negative).
>

Please clarify if this is a problem for rc2.d scripts only or for both
rc2.d and rcS.d scrips. Also I fail to see why one would want to have a
native runit service in /etc/sv and still want to run the correspondent
sysv scripts instead.

Overall for stage1 I think I'm going to revert an old change a go back
to a plain for loop without any check for /etc/service nor /etc/sv/ (see
#1023358).

For stage2/3, assuming my "sysv-2-runscript generator" proposal made you
go away in total despair, here is another (hopefully simpler) idea:
I can add a loop that runs scripts in a certain directory in
lexicographical order, without any policy applied.
You can disable the run_sysv_script with the no.emulate.sysv flag file
and manage scripts in such directory on your own.
I am also fine to add an extra check for /etc/service/name and/or
/etc/service/.name (but in addition, not as a replacement for the
/etc/sv/name).
let me know if one or a mix of the above can help.
For a rationale of this, see below

> Maybe we should start from a statement of the particular problems
> that need solving? Do you have such a document?

The reason for recent changes of stage[1,2,3] is the following: I want
to move to (and ideally reach) a state where runit is able to init and
run a system without using/depending on facilities that are specific to
other init systems.

To simplify

A. (starting point): runit is able to init the system, using initscripts
from sysv, but the user has to write native services ( the system
starts and provides only 6 getties)

B. (transition): add a run_sysv_script interface that starts
   initscripts when a native runscript is missing, so that while
   runscript are gradually added the system is usable by non expert
   users. run_sysv_script uses the sysv order and the sysv convention
   for enable/disable a service: this is a little problem at the
   beginning, but the more runscripts are added, the less this is
   convenient. runscripts starts to conflict/interact with sysv and
   additional effort and layer are needed to keep the two system
   together.

C. (end point): runit init and run the system without relying on any
   interface specific to another init system. Enough runscripts and
   oneshots are available. There is a native mechanism that
   enable/disable and restarts services, that can be overriden by the
   user. The sysv layer is dropped, sysv script are masked ( so that
   maintainer scripts don't run them during upgrade)

We are now at B, and I'm preparing stage[1,2,3] for C, so there is the
maximum overhead because I'm adding stuff and retaining (for now) the
sysv compatibility. I'm not sure the package will ever reach a full C
stage, because I don't have enough resources (there are more than 1000
services in Debian packages). On the other hand if I made my
calculations right, knowledgeable users can customize the system and
downstreams can build extra packages on top of the Debian one without
the need to modify it.

The relevant question for me is what runit needs to provide in stage
[1,2,3] at C, I think roughly

1. (stage1) run tasks to initialize a base system
2. (stage2) provide a way to run oneshots tasks. I think run a set of
   sh scripts or having oneshots expressed as runscripts are both valid
   approach, it really depends on sysadmin preferences/needs
3  (stage 2) choose the directory for runsvchdir
4  (stage 2) start runsvdir
5  (stage3) provide a way to stop some selected services in
   some ordered way
6  (stage3) stop all remaining services with no particular order
7  (stage 3) run tasks to shutdown the system

the current status is
1 uses scripts from initscripts, and is possible to run an
alternative set of scripts, which is not optimal but acceptable;
2 is missing, but there is a 2.1 (run_sysv_scripts), hence my above
proposal to add 2.
3,4,5 and 6 are already in place;
7 is a wierd mix, it run initscripts using the run_sysv_script
interface, but is possible to run an alternative 'native' sequence.

Not sure if I am forgetting something or the list above can be
simplified. Hope that at least one or part of a solution proposed so
far is acceptable to you, I'm running out of ideas otherwise.

Lorenzo



Bug#1022837: /lib/runit/run_sysv_scripts uses wrong test to skip initscripts

2022-11-06 Thread Lorenzo
Hi,

> Ps. I appreciate all the work you're doing on the runit packages.
> Please don't take my occasionally vehement disagreement with some of
> your ideas personally.

Don't worry about this, feedback are useful to improve the package.
Thanks for taking the time to file bugs and followup, others probably
just don't bother.

>  1. openssh ships its /etc/sv/ssh directory, which gets symlinked to
> /etc/service during installation, but which never worked for me
> (unfortunately I didn't investigate, just replaced the symlink with
> one to my own /var/lib/svn-checkout/services/ssh);

(if I have to guess) please replace your /sbin/start-stop-daemon
(wrapper) with a symlink that points to
/lib/runit/start-stop-daemon.runit and try again the ssh service.
Invoke-run, in the attempt of replace the sysv instance and avoid
conflicts, calls /etc/init.d/foo stop. So when a wrapper is in place
the service down itself. The call is skipped when
/sbin/start-stop-daemon or /etc/init.d/foo are symlinks.

> neither will it pick up a syslogd that is not managed by runit. Maybe
> just try to see if something is listening on /dev/log in "check"?).

great idea, thanks. See
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1023476
in case you have better suggestion than 'lsof'

> If it were possible to disable the "default-syslog" service
> conclusively, permanently, by creating something somewhere during
> installation, or writing a line into a file, that would be great.

Just try
# update-service disable /etc/sv/default-syslog
( what it does is to remove the /etc/service/default-syslog link and
  creates /etc//service/.default-syslog
then reinstall runit, the 'default-syslog' service will stay disabled
until you purge 'runit' package or you remove the .default-syslog link

> Being able to opt out completely of all Debian specific runit glue
> would be even better; I accept that it's convenient for new or casual
> users, but for me in particular it's mostly just frustrating due to
> it being different from upstream runit

I understand this, but please be more specific about 'Debian specific
runit glue' : for stage 1 and 3, I have added switches to use
alternative set of scripts. The intention was to experiment with native
runit scripts[1], but you can also use it to avoid 'run_sysv_scripts'.
For stage 2, you can skip run_svsv_scripts with a
'/etc/runit/no.emulate.sysv' flag file; also, you can use
'/etc/runit/default.runsvdir'. This one will basically prevent any
automation (enable/disable) on a service by any debian package for runit
services; restart of services linked in /etc/service during upgrades
will still work. What else?
(maybe you hope for less switches? I'm well available to discuss this,
but please open a separate bug)

> My first impression is you're trying to solve what is not a problem,
> and introducing unneeded complexity, where part of runit's appeal (at
> least for me) is its simplicity and straightforwardness. You're
> building extra layers around runit so that people who are familiar
> with runit per se aren't able to use the Debian runit packages
> without jumping through hoops. There may be good reasons, but
> personally, I don't like this direction.
> 
> I would just as soon manage my /etc/service/* symlinks without any
> package automation.

Ok, I mentioned the new layout because I thought it could help to solve
your issue but it looks like it's not the case, so let's stop discussing
this here, otherwise the bug becomes hard to follow for readers.

Now, back to the main subject:
> For us, IIUC, the important question now is how to handle explicitly
> disabled services in the runit SysV emulation, right? I'd be fine
> with the following:
> 
> 1. if no /etc/service/foo symlink exists, the admin explicitly
> disabled runit management of service foo. (No argument there, I
> think?)

From your point of view, yes; from the package(r) point of view, a
missing link can be

1. the package that ships the runscript was never installed, so the
link has to be created (the default in Debian is usually to enable a
service at first install)

2. the package that ship the runscript is upgraded, and the admin
removed the link (it want it disabled).

In order to separate this two cases, and allow the admin to say "I
want this to stay disabled and the setting to persist untill purge" the
dot-link convention was created.

> 
> 2. to also explicitly disable SysV instances of foo being started,
> use whatever mechanism the sysvinit package provides to disable the
> sysv-style service startup as well, and have the runit SysV emulation
> honour this.

This is already the case: sysv uses "K-links" (like KNNname) to
mark a service as disabled, while run_sysv_scripts only loop over
"S-links". However this creates unexpected results:
* I disable a native runit service, because I don't want the service to
  run (the service goes down)
* then reboot the system
* now I have an unsupervised instance of the service running

So to really 

Bug#1022837: /lib/runit/run_sysv_scripts uses wrong test to skip initscripts

2022-11-04 Thread Andras Korn
On Wed, Nov 02, 2022 at 01:45:24PM +0100, Lorenzo wrote:

Hi,

> Am I correct that this is not a regression introduced with recent changes to 
> runit? [relevant to understand if I have to revert something in case I can't 
> fix this before the freeze]

Yes. I just started using the default config files (/etc/runit/1 mainly) that 
you ship, and noticed this problem due to that.

> Anyway, let me clarify this one first:
> > 
> > Uh, what runtime directory? /etc/sv is currently a repository for 
> > package-supplied and admin-provided service directories. Why would you move 
> > that to /run, which is volatile?
> >
> 
> A. package supplied
> B. admin-provided
> C. runtime directory ( the directory that is actually
> monitored by a runsv process when the service is enabled)
> 
> with the current setup, A,B and C are overlapped in /etc/sv/: what I plan to 
> do is to separate these in 3 different path, like
> 
> A. /usr/share/runit/sv/ (package supplied runscript, source format -->
> symlinks are missing)
> B. /etc/sv/ (reserved for local admin provided runscript)
> C. /run/runit/sv/ (runtime copy of services)
> 
> At system boot (see TODO comment in stage 2) a specialised cpsv(8) tool is 
> used to copy relevant runscript in C; when a 'name' runscript exists both in 
> A and B, the copy in B takes precedence. C is kept in sync with A and B 
> during runtime thanks to a trigger that is activated when a package that ship 
> a service is installed/ removed/ upgraded. To pick up changes to B, the local 
> admin will have to call cpsv (either with --sync or with -a).
> 
> Now, cpsv is still WIP, and I can make A and C somehow configurable, and make 
> run_sysv_script behave consistently with cpsv, but is this really usefull?

My first impression is you're trying to solve what is not a problem, and 
introducing unneeded complexity, where part of runit's appeal (at least for me) 
is its simplicity and straightforwardness. You're building extra layers around 
runit so that people who are familiar with runit per se aren't able to use the 
Debian runit packages without jumping through hoops. There may be good reasons, 
but personally, I don't like this direction.

I would just as soon manage my /etc/service/* symlinks without any package 
automation.

That said, I would be grateful for ways of getting rid of the following 
annoying behaviours:

 1. openssh ships its /etc/sv/ssh directory, which gets symlinked to 
/etc/service during installation, but which never worked for me (unfortunately 
I didn't investigate, just replaced the symlink with one to my own 
/var/lib/svn-checkout/services/ssh);
 2. a default-syslog service is created by something, and all it does on my 
systems is sleep indefinitely (I use socklog as my syslogd, but have my own 
service directory for that as well, and its name is just "socklog", so the 
magic "check" script won't pick it up -- and neither will it pick up a syslogd 
that is not managed by runit. Maybe just try to see if something is listening 
on /dev/log in "check"?).

If I could override /etc/sv/ssh with my own directory (e.g. if "B" were a 
configurable list of locations in order of precedence), that would solve #1.

If it were possible to disable the "default-syslog" service conclusively, 
permanently, by creating something somewhere during installation, or writing a 
line into a file, that would be great.

Being able to opt out completely of all Debian specific runit glue would be 
even better; I accept that it's convenient for new or casual users, but for me 
in particular it's mostly just frustrating due to it being different from 
upstream runit, which I started using in around 2004 (switching to it from 
daemontools).

> A: with the new layout, what would be the reason for you to checkout your svn 
> somewhere else than /etc/sv/ ?

 1. /etc is for configuration. /var/lib/svn-checkout/services is not 
configuration; it's more like your /usr/share/runit/sv (except it's not shipped 
by a package, but it might as well be).
 2. I see /etc/sv as a place to instantiate template-based services; like 
systemd has openvpn@foo, I have /etc/sv/openvpn-foo, whose run script is a 
symlink to my svn checkout's openvpn-template/run (and the script infers what 
openvpn config to use based on the "-foo" suffix of the runit service name).

Mixing local instantiations with upstream svn content would be hard to maintain 
(e.g. "svn status" output would be cluttered).

> C: to some extent is already configurable, because I need that for the 
> transition and I want to support user services (in /home/ ), but I'm not sure 
> there is a reasonable use case beyond that..

FWIW, user-template is another such service I instantiate separately for each 
user who needs to be able to have their own runit services. But you lost me 
again: what is already configurable to some extent?

> > > >  1. /etc/sv/$name may not be symlinked into /etc/service (false 
> > > > positive);
> > > >  2. /etc/service 

Bug#1022837: /lib/runit/run_sysv_scripts uses wrong test to skip initscripts

2022-11-02 Thread Lorenzo
Hi,

Am I correct that this is not a regression introduced with recent
changes to runit? [relevant to understand if I have to revert something
in case I can't fix this before the freeze]

Anyway, let me clarify this one first:
> 
> Uh, what runtime directory? /etc/sv is currently a repository for
> package-supplied and admin-provided service directories. Why would
> you move that to /run, which is volatile?
>

A. package supplied
B. admin-provided
C. runtime directory ( the directory that is actually
monitored by a runsv process when the service is enabled)

with the current setup, A,B and C are overlapped in /etc/sv/: what I
plan to do is to separate these in 3 different path, like

A. /usr/share/runit/sv/ (package supplied runscript, source format -->
symlinks are missing)
B. /etc/sv/ (reserved for local admin provided runscript)

C. /run/runit/sv/ (runtime copy of services)

At system boot (see TODO comment in stage 2) a specialised cpsv(8) tool
is used to copy relevant runscript in C; when a 'name' runscript exists
both in A and B, the copy in B takes precedence.
C is kept in sync with A and B during runtime thanks to a trigger that
is activated when a package that ship a service is installed/ removed/
upgraded.
To pick up changes to B, the local admin will have to call cpsv (either
with --sync or with -a).

Now, cpsv is still WIP, and I can make A and C somehow configurable,
and make run_sysv_script behave consistently with cpsv, but is this
really usefull?

A: with the new layout, what would be the reason for you to checkout
your svn somewhere else than /etc/sv/ ?
C: to some extent is already configurable, because I need that for the
transition and I want to support user services (in /home/ ), but I'm
not sure there is a reasonable use case beyond that..

(looking for comments/ reason for not doing the above)


> > >  1. /etc/sv/$name may not be symlinked into /etc/service (false
> > > positive);
> > 
> > > [...]
> > >  2. /etc/service may contain a symlink to a service directory for
> > > this service that is elsewhere in the filesystem, not in /etc/sv
> > > (false negative).

Thinking more about this, I suspect the problem is caused by an
inconsistent service layout: You have
B and C= /var/lib/svn-checkout/services/
but in some special cases (multi-instance openvpn) you have
B= /var/lib/svn-checkout/services/ and
C= /etc/sv/

Having links in /etc/service/ that point to different locations makes
heuristic on my side really hard and error prone: I think is reasonable
to ask the admin to use a unique path for C.
I am ok with some of the changes you suggested[1], but I have to support
the case where a runit service exists and it's disabled:

> I understand that you're thinking of /etc/sv/ as "configuration", but
> in this instance I would prefer configuration to be more explicit; if
> I want to disable a service I'll make sure it can't be started (e.g.
> by modifying its /etc/default file), not just refrain from creating a
> /etc/service/ symlink for it.
> 
> If I just want to disable automatic startups, I'll create
> /etc/service/servicename/down.

My concern is more with /etc/service/, right now to represent a
disabled service you have
1. missing link in /etc/service (implicit)
2. dot-link, like /etc/service/.name (explicit)

I don't consider /etc/defaults/name or the down file a proper way to
mark a service as permanently disabled: the former is not transparent to
runit and is also a RC but for Debian policy [2]; the latter has a cost
in term of a runsv process running for nothing.

I'm still open to other suggestions.

Lorenzo


[1] for rcS: only check for /etc/runit/override-init.d/

for rc2: [ -e /etc/runit/override-init.d/name ] && continue
 [ -L /etc/service/name ] && continue
 # remove name-daemon tests, useless
 [ -d /etc/sv/name ] && continue # /etc/sv/ path may be
  # configurable with some flag file, still have to
  # understand if is useful
 /etc/init.d/name start
 

[2] https://www.debian.org/doc/debian-policy/ch-opersys.html,
paragraph 9.3.3.1. "An older practice, which should not be used.."



Bug#1022837: /lib/runit/run_sysv_scripts uses wrong test to skip initscripts

2022-10-29 Thread Andras Korn
On Fri, Oct 28, 2022 at 03:07:07PM +0200, Lorenzo wrote:

Hi,

> > Package: runit
> > Version: 2.1.2-50
> > Severity: normal
> > 
> > Hi,
> > 
> > /lib/runit/run_sysv_scripts has this:
> > 
> > for script in "$initdir/$rX"* ; do
> > [ ! -x "$script" ] && continue
> > path=$(realpath "$script")
> > name=${path##*/}
> > # Special case for wicd. Runscript is called "wicd-daemon",
> > # to match binary package name.
> > [ -d "/etc/sv/$name" ] && continue
> > [ -d "/etc/sv/$name-daemon" ] && continue
> > "$script" "$rcommand"
> > done
> > 
> > Checking for /etc/sv/$name and skipping initscripts if those
> > directories exist is wrong for two reasons:
> > 
> >  1. /etc/sv/$name may not be symlinked into /etc/service (false
> > positive);
> 
> The runit service exists and is not enabled, so why one would want to
> start a sysv instance instead? 
> To me 1. looks correct, can you make an example when it causes
> unexpected/buggy results?

Our expectations are apparently different. I would expect 
/lib/runit/run_sysv_scripts to do what it says on the tin: run sysv scripts. 
The only reason to skip a script (as far as I'm concerned) is that running it 
would conflict with a runit service.

It's not just about starting services either: if /etc/sv/$name exists but the 
service is not managed by runit (that is, /etc/service/$name doesn't exist), 
and I start the service manually via the initscript, run_sysv_scripts will also 
fail to stop it.

I understand that you're thinking of /etc/sv/ as "configuration", but in this 
instance I would prefer configuration to be more explicit; if I want to disable 
a service I'll make sure it can't be started (e.g. by modifying its 
/etc/default file), not just refrain from creating a /etc/service/ symlink for 
it.

If I just want to disable automatic startups, I'll create 
/etc/service/servicename/down.

> >  2. /etc/service may contain a symlink to a service directory for this 
> > service that is elsewhere in the filesystem, not in /etc/sv (false 
> > negative).

Example:

lrwxrwxrwx 1 root root 34 Feb  9  2009 /etc/service/atd -> 
/var/lib/svn-checkout/services/atd

This isn't in /etc/sv, but it still means atd(8) is managed by runit.

> > As a minimum, I suggest the following: instead of /etc/sv/$name, check for 
> > /etc/service/$name (and $name-daemon if necessary), and not with "-d" but 
> > "-L" (because when running rcS.d, the target of the symlink may only appear 
> > later, for example when a new filesystem is mounted).
> > 
> > This is still imperfect during boot because /etc/service may point to some 
> > directory that is not the one we'll switch to with runsvdir in stage 2. I 
> > don't know what the best way of handling this (likely rare) case is, but 
> > the following solutions come to mind:
> 
> 2. is an issue, especially because I'm thinking of moving the runtime
> directory form /etc/sv/ --> /run/runit/sv/ : this move requires a
> long transition period where both the old and the new path are
> supported as runtime directories..

Uh, what runtime directory? /etc/sv is currently a repository for 
package-supplied and admin-provided service directories. Why would you move 
that to /run, which is volatile?

> On the other hand I don't know if with systemd or Sysvinit is even possible 
> to boot the system with a custom path for services; I don't want to make it 
> unnecessary hard to do it with runit, but I think it's reasonable to expect 
> some effort on admin side for such setup.

I'm sorry, you lost me completely (or maybe I lost you; see my example symlink 
above).

> >  1. have a /etc/runit/override-init.d/ directory. If $name exists in it, 
> > don't invoke the initscript in /lib/runit/run_sysv_scripts. This places the 
> > entire administration/configuration burden on the admin but is very simple 
> > to do, and easy enough for the admin to automate (e.g. your own service 
> > scripts can just create these files when they're first run).
> 
> I'm ok with adding this, but it's unclear to me if the above is theoretical 
> reasoning or you have an actual problem with your setup: in case of the 
> latter please add more detail to avoid the unhappy case where the fix that i 
> push doesn't solve your issue

Yes.

For example, I have an atd service whose service directory is 
/var/lib/svn-checkout/services/atd. This is symlinked into /etc/service. 
run_sysv_scritps doesn't detect it as a runit-supervised service, because the 
directory is different from /etc/sv/atd, and starts another instance via the 
initscript.

I have many such services. I keep my runit service directories in Subversion 
and have a checkout of the repository on all systems. I just symlink the 
appropriate directory from the checkout into /etc/service if I want to run a 
service.

I use /etc/sv to instantiate services that I have templates for; for example, I 
have an openvpn runit service template, so I'll create /etc/sv/openvpn-foobar 
and create a 

Bug#1022837: /lib/runit/run_sysv_scripts uses wrong test to skip initscripts

2022-10-28 Thread Lorenzo
Hi,

On Wed, 26 Oct 2022 18:26:02 +0200
Andras Korn  wrote:

> Package: runit
> Version: 2.1.2-50
> Severity: normal
> 
> Hi,
> 
> /lib/runit/run_sysv_scripts has this:
> 
> for script in "$initdir/$rX"* ; do
>   [ ! -x "$script" ] && continue
>   path=$(realpath "$script")
>   name=${path##*/}
>   # Special case for wicd. Runscript is called "wicd-daemon",
>   # to match binary package name.
>   [ -d "/etc/sv/$name" ] && continue
>   [ -d "/etc/sv/$name-daemon" ] && continue
>   "$script" "$rcommand"
> done
> 
> Checking for /etc/sv/$name and skipping initscripts if those
> directories exist is wrong for two reasons:
> 
>  1. /etc/sv/$name may not be symlinked into /etc/service (false
> positive);

The runit service exists and is not enabled, so why one would want to
start a sysv instance instead? 
To me 1. looks correct, can you make an example when it causes
unexpected/buggy results?

> 
>  2. /etc/service may contain a symlink to a service directory for
> this service that is elsewhere in the filesystem, not in /etc/sv
> (false negative).
> 
> As a minimum, I suggest the following: instead of /etc/sv/$name,
> check for /etc/service/$name (and $name-daemon if necessary), and not
> with "-d" but "-L" (because when running rcS.d, the target of the
> symlink may only appear later, for example when a new filesystem is
> mounted).
> 
> This is still imperfect during boot because /etc/service may point to
> some directory that is not the one we'll switch to with runsvdir in
> stage 2. I don't know what the best way of handling this (likely
> rare) case is, but the following solutions come to mind:
> 

2. is an issue, especially because I'm thinking of moving the runtime
directory form /etc/sv/ --> /run/runit/sv/ : this move requires a
long transition period where both the old and the new path are
supported as runtime directories..
On the other hand I don't know if with systemd or Sysvinit is even
possible to boot the system with a custom path for services; I don't
want to make it unnecessary hard to do it with runit, but I think it's
reasonable to expect some effort on admin side for such setup.

>  1. have a /etc/runit/override-init.d/ directory. If $name exists in
> it, don't invoke the initscript in /lib/runit/run_sysv_scripts. This
> places the entire administration/configuration burden on the admin
> but is very simple to do, and easy enough for the admin to automate
> (e.g. your own service scripts can just create these files when
> they're first run).

I'm ok with adding this, but it's unclear to me if the above is
theoretical reasoning or you have an actual problem with your setup: in
case of the latter please add more detail to avoid the unhappy case
where the fix that i push doesn't solve your issue

> 
>  2. pass the name of the /etc/runit/runsv directory that we expect to
> be used to /lib/runit/run_sysv_scripts somehow (for example, in an
> environment variable). This looks brittle (riddled with race
> conditions) and complicated to me, but it would require no effort
> from the admin.

> 
>  3. invoke runsvchdir earlier during boot. This is problematic on
> systems where / is read-only before some initscripts are run.
> 

I'm thinking of running boot scripts (rcS) in stage 1 unconditionally,
(or maybe only subjected to /etc/runit/override-init.d/): after all
runit is for supervise long run processes, while boot scripts are all
oneshots. This will make it harder to use oneshots for late boot
scripts, but will also avoid to break the boot sequence if one has,
let's say a /etc/sv/udev directory. Will this improve or worsen
your situation?

Lorenzo

>  4. [other kludges]
> 
> András
> 



Bug#1022837: /lib/runit/run_sysv_scripts uses wrong test to skip initscripts

2022-10-26 Thread Andras Korn
Package: runit
Version: 2.1.2-50
Severity: normal

Hi,

/lib/runit/run_sysv_scripts has this:

for script in "$initdir/$rX"* ; do
[ ! -x "$script" ] && continue
path=$(realpath "$script")
name=${path##*/}
# Special case for wicd. Runscript is called "wicd-daemon",
# to match binary package name.
[ -d "/etc/sv/$name" ] && continue
[ -d "/etc/sv/$name-daemon" ] && continue
"$script" "$rcommand"
done

Checking for /etc/sv/$name and skipping initscripts if those directories exist 
is wrong for two reasons:

 1. /etc/sv/$name may not be symlinked into /etc/service (false positive);

 2. /etc/service may contain a symlink to a service directory for this service 
that is elsewhere in the filesystem, not in /etc/sv (false negative).

As a minimum, I suggest the following: instead of /etc/sv/$name, check for 
/etc/service/$name (and $name-daemon if necessary), and not with "-d" but "-L" 
(because when running rcS.d, the target of the symlink may only appear later, 
for example when a new filesystem is mounted).

This is still imperfect during boot because /etc/service may point to some 
directory that is not the one we'll switch to with runsvdir in stage 2. I don't 
know what the best way of handling this (likely rare) case is, but the 
following solutions come to mind:

 1. have a /etc/runit/override-init.d/ directory. If $name exists in it, don't 
invoke the initscript in /lib/runit/run_sysv_scripts. This places the entire 
administration/configuration burden on the admin but is very simple to do, and 
easy enough for the admin to automate (e.g. your own service scripts can just 
create these files when they're first run).

 2. pass the name of the /etc/runit/runsv directory that we expect to be used 
to /lib/runit/run_sysv_scripts somehow (for example, in an environment 
variable). This looks brittle (riddled with race conditions) and complicated to 
me, but it would require no effort from the admin.

 3. invoke runsvchdir earlier during boot. This is problematic on systems where 
/ is read-only before some initscripts are run.

 4. [other kludges]

András

-- 
 Reality is merely an illusion, albeit a very persistent one.