geoip-shell icon indicating copy to clipboard operation
geoip-shell copied to clipboard

Add documentation for manual persistence

Open superjamie opened this issue 1 year ago • 9 comments

As the script says, Busybox crond doesn't support @reboot.

It could be helpful to advise users how they can implement persistence themselves.

I presume the main place such an environment will be encountered is Alpine Linux, which has OpenRC and its local service to run arbitrary scripts at startup, so instructions could be like:

  • Create a script at /etc/local.d/90-geoip-shell-restore.start with contents:
#!/bin/sh
/path/to/geoip-shell/geoip-shell-run.sh restore -a 1>/dev/null 2>/dev/null
  • Set the script executable: chmod +x /etc/local.d/90-geoip-shell-restore.start
  • Enable the local script service: rc-update add local

I thought of implementing this in the script directly but I wasn't sure if you wanted to specifically detect OpenRC init and tie the script to that.

Maybe there are other environments where Busybox cron is used but OpenRC is not present. Such a feature would not be useful in those environments.

If you would like that feature, I'm happy to write it and send a PR for your review.

superjamie avatar Aug 15 '24 04:08 superjamie

Hi

There are numerous distributions based on Busybox, including some embedded distributions. So I can not really provide a detailed guide in the manual for each one. I will add some basic info on how to call the -run script from a custom init script.

Generally I'm open to implementing support for init systems which need it. I will gladly review your PR. The code should be tied to OpenRC because then additional potential systems using OpenRC would benefit from it. Note that the code related to init system detection and persistence implementation (and subsequent checks) is somewhat convoluted and several scripts will require changes (out the top of my head: -install, -uninstall, -lib-common, -lib-status). So to save you the trouble, I could implement this feature by myself, but I'll need you to test the implementation.

friendly-bits avatar Aug 15 '24 08:08 friendly-bits

The init system detection is done by detect_init() in the -install script. It tries to make the detection as accurate as possible, so there are several steps with each step falling back to the next one. The relevant steps for this case are checking the /sbin/init strings and checking the process with pid 1.

So the first thing to do in order to implement OpenRC detection is to see the output of these commands:

awk 'match($0, /(upstart|systemd|OpenRC|procd|sysvinit|busybox)/) { print substr($0, RSTART, RLENGTH);exit; }' /sbin/init

ls -l /proc/1/exe

Ideally both commands should produce an OpenRC-specific string which can be used for detection. If not, some more tinkering may be needed.

friendly-bits avatar Aug 15 '24 09:08 friendly-bits

Also I've been planning for some time to implement native init-based persistence support for Systemd, so I could as well use this opportunity to add a generic framework for handling init scripts installation, checks and uninstallation. Just saying this before you started your implementation (in case you want to implement this feature by yourself) because there may be an upcoming change in related code structure.

friendly-bits avatar Aug 15 '24 09:08 friendly-bits

Thanks for the quick reply and tips!

Alpine's /sbin/init is busybox, it calls OpenRC through /etc/inittab, and there isn't an openrc daemon left running.

I guess one option is to re-detect busybox init and see if busybox is actually openrc, eg:

case "$initsys" in
  busybox) if [ "$(grep -Ec "::sysinit::/sbin/openrc sysinit" /etc/inittab 2>/dev/null)" -gt 0 ]; then initsys="openrc"; fi ;;

Your existing systemd detection works for me on Debian 12. I think the systemd-native way to implement this would be a few oneshot systemd units which run the required existing scripts at the right time.

Restoring existing rules without update would be ordered Before=network-pre.target and After=nftables.service. Fetching an update would need to be After=network-online.target.

superjamie avatar Aug 15 '24 10:08 superjamie

An untested first attempt on this branch:

https://github.com/superjamie/geoip-shell/tree/openrc-persistence

I'll test tomorrow or over the weekend.

TODO: make local_d_script common, and use the p_name variable in it

I tried to adhere to your existing style. Any feedback welcome.

superjamie avatar Aug 15 '24 11:08 superjamie

Thank you, I'll take a look at this hopefully later today. In the meantime, it would be helpful if you could post the output of these commands

awk 'match($0, /(upstart|systemd|OpenRC|procd|sysvinit|busybox)/) { print substr($0, RSTART, RLENGTH);exit; }' /sbin/init

ls -l /proc/1/exe

These are run by detect_init() regardless, and further execution depends on the output, so it'll help if we know what the output is on your system, to figure out which branch the code is currently taking - then we can amend it in an informed way.

friendly-bits avatar Aug 15 '24 12:08 friendly-bits

Never mind, just tested with an iso of Alpine - both commands indicate busybox.

friendly-bits avatar Aug 15 '24 14:08 friendly-bits

So far I've come up with this method which detects OpenRC on both Alpine and Gentoo:

{
	rc_service_f="$(command -v 'rc-service')" && 
		awk 'match($0, /(OpenRC|openrc)/) { print substr($0, RSTART, RLENGTH);exit; }' "$rc_service_f" |
			grep . && initsys=openrc
} 1>/dev/null 2>/dev/null

Your method with /etc/inittab could work as well, with a slight modification:

grep 'sysinit:/sbin/openrc sysinit' /etc/inittab 1>/dev/null 2>/dev/null && initsys=openrc

Probably your method is better because the rc-service binary could be present in the system regardless of the actual init used in it.

friendly-bits avatar Aug 15 '24 15:08 friendly-bits

Yes, that was my intention. OpenRC might be installed but not necessarily the init system.

superjamie avatar Aug 16 '24 11:08 superjamie

Hi @superjamie , thanks again for raising this issue. I've been quite busy recently, sorry that it took a long time to address it.

Current version 0.5.8 supports running the -install script with the option -F true which forces geoip-shell to use cron-based persistence on Busybox systems. Not all Busybox systems support this (it depends on how the distro configures Busybox), but the Alpine Linux Busybox does - at least in the version I'm testing with. So if you prefer, you could use this feature rather than custom init script.

I also updated SETUP.md with basic information about how to call geoip-shell from a custom init script.

Does this solve this issue?

P.s. I am still planning to implement OpenRC init script. OpenRC init detection has been implemented already.

friendly-bits avatar Oct 09 '24 01:10 friendly-bits

Hello!

Yes that's great, the last few doc comments (below) do solve this.

I close this issue as it's complete. Thank you very much!

  • https://github.com/friendly-bits/geoip-shell/commit/0f116e60f6dd6ae17b3270cc67525a6f641dff26
  • https://github.com/friendly-bits/geoip-shell/commit/b1f1184f2af7d82baca956f4c9c08293108f0874
  • https://github.com/friendly-bits/geoip-shell/commit/d745298b91012d7f32e294b47f2827d0d3556a98
  • https://github.com/friendly-bits/geoip-shell/commit/9aab4c7445944dddc1107f475f91e92b4a13a262

superjamie avatar Oct 10 '24 08:10 superjamie