Bug#1022837: /lib/runit/run_sysv_scripts uses wrong test to skip initscripts
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 bre
Bug#1022837: /lib/runit/run_sysv_scripts uses wrong test to skip initscripts
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 th
Bug#1022837: /lib/runit/run_sysv_scripts uses wrong test to skip initscripts
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
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
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
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 may
Bug#1022837: /lib/runit/run_sysv_scripts uses wrong test to skip initscripts
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
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 /etc/sv/open
Bug#1022837: /lib/runit/run_sysv_scripts uses wrong test to skip initscripts
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
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.