Hacking with runit and sv ( sv – control and manage services monitored by runsv(8) ) commands

ABOUT runit

runit is a cross-platform Unix init scheme with service supervision, a replacement for sysvinit, and other init schemes. It runs on GNU/Linux, *BSD, MacOSX, Solaris, and can easily be adapted to other Unix operating systems

ABOUT sv

The sv program reports the current status and controls the state of services monitored by the runsv(8) supervisor.
services consists of one or more arguments, each argument naming a directory service used by runsv(8). If service doesn’t start with a dot or slash and doesn’t end with a slash, it is searched in the default services directory /service/, otherwise relative to the current directory.

A TYPICAL SHELL EXPOSURE
[bash]
$pwd
/etc/service
$ls
hello.sh
$mkdir new
mkdir: cannot create directory ‘new’: Permission denied
$sudo mkdir new
$mv hello.sh new/run
mv: cannot move ‘hello.sh’ to ‘new/run’: Permission denied
$sudo mv hello.sh new/run
$ls
new
$cd new/
$ls
run supervise
$ls -l
total 8
-rw-r–r– 1 root root 11 Oct 24 18:55 run
drwx—— 2 root root 4096 Oct 24 18:57 supervise
$cd supervise/
bash: cd: supervise/: Permission denied
$sudo cd supervise/
sudo: cd: command not found
$sudo sv start /etc/service/new
timeout: down: /etc/service/new: 1s, normally up, want up
$sudo sv status /etc/service/new
down: /etc/service/new: 0s, normally up, want up
$sudo sv restart /etc/service/new
timeout: down: /etc/service/new: 0s, normally up, want up
$sudo emacs /etc/service/new/run
$sudo sv restart /etc/service/new
timeout: down: /etc/service/new: 0s, normally up, want up
$sudo sv stop /etc/service/new
ok: down: /etc/service/new: 0s, normally up, want up
$sudo chmod +x /etc/service/new/run
$sudo sv start /etc/service/new
timeout: down: /etc/service/new: 0s, normally up, want up
$sudo sv start /etc/service/new/
timeout: down: /etc/service/new/: 1s, normally up, want up
$su
Password:
root>sv start /etc/service/new/
run run~ supervise/
root>sv start /etc/service/new/run
fail: /etc/service/new/run: unable to change to service directory: not a directory
root>sv start /etc/service/new/
timeout: down: /etc/service/new/: 1s, normally up, want up
root>exit
$echo $?
1
$sudo sv stop /etc/service/new/
ok: down: /etc/service/new/: 1s, normally up, want up
$echo $?
0
$sudo runit
– runit: fatal: must be run as process no 1.
$sudo runit enable
– runit: fatal: must be run as process no 1.
$

[/bash]
TYPICAL SOURCE CODE EXPOSURE
[c]

int main(int argc, char **argv) {
unsigned int i, done;
char *x;

progname =*argv;
for (i =str_len(*argv); i; –i) if ((*argv)[i -1] == ‘/’) break;
*argv +=i;
optprogname =progname =*argv;
service =argv;
services =1;
lsb =(str_diff(progname, "sv"));
if ((x =env_get("SVDIR"))) varservice =x;
if ((x =env_get("SVWAIT"))) scan_ulong(x, &wait);
while ((i =getopt(argc, (const char* const*)argv, "w:vV")) != opteof) {
switch(i) {
case ‘w’: scan_ulong(optarg, &wait);
case ‘v’: verbose =1; break;
case ‘V’: strerr_warn1(VERSION, 0);
case ‘?’: usage();
}
}
argv +=optind; argc -=optind;
if (!(action =*argv++)) usage(); –argc;
if (!lsb) { service =argv; services =argc; }
if (!*service) usage();

taia_now(&tnow); tstart =tnow;
if ((curdir =open_read(".")) == -1)
fatal("unable to open current directory");

act =&control; acts ="s";
if (verbose) cbk =✓
switch (*action) {
case ‘x’: case ‘e’:
acts ="x"; break;
case ‘X’: case ‘E’:
acts ="x"; kll =1; cbk =✓ break;
case ‘D’:
acts ="d"; kll =1; cbk =✓ break;
case ‘T’:
acts ="tc"; kll =1; cbk =✓ break;
case ‘t’:
if (!str_diff(action, "try-restart")) { acts ="tc"; cbk =✓ break; }
case ‘c’:
if (!str_diff(action, "check")) { act =0; acts ="C"; cbk =✓ break; }
case ‘u’: case ‘d’: case ‘o’: case ‘p’: case ‘h’:
case ‘a’: case ‘i’: case ‘k’: case ‘q’: case ‘1’: case ‘2’:
action[1] =0; acts =action; break;
case ‘s’:
if (!str_diff(action, "shutdown")) { acts ="x"; cbk =✓ break; }
if (!str_diff(action, "start")) { acts ="u"; cbk =✓ break; }
if (!str_diff(action, "stop")) { acts ="d"; cbk =✓ break; }
if (lsb && str_diff(action, "status")) usage();
act =&status; cbk =0; break;
case ‘r’:
if (!str_diff(action, "restart")) { acts ="tcu"; cbk =✓ break; }
if (!str_diff(action, "reload")) { acts ="h"; cbk =✓ break; }
usage();
case ‘f’:
if (!str_diff(action, "force-reload"))
{ acts ="tc"; kll =1; cbk =✓ break; }
if (!str_diff(action, "force-restart"))
{ acts ="tcu"; kll =1; cbk =✓ break; }
if (!str_diff(action, "force-shutdown"))
{ acts ="x"; kll =1; cbk =✓ break; }
if (!str_diff(action, "force-stop"))
{ acts ="d"; kll =1; cbk =✓ break; }
default:
usage();
}

servicex =service;
for (i =0; i < services; ++i) {
if ((**service != ‘/’) && (**service != ‘.’) && **service &&
((*service)[str_len(*service) -1] != ‘/’)) {
if ((chdir(varservice) == -1) || (chdir(*service) == -1)) {
fail("unable to change to service directory");
*service =0;
}
}
else
if (chdir(*service) == -1) {
fail("unable to change to service directory");
*service =0;
}
if (*service) if (act && (act(acts) == -1)) *service =0;
if (fchdir(curdir) == -1) fatal("unable to change to original directory");
service++;
}

[/c]

SOURCE CODE TAKEN FROM DEBIAN SOURCE PACKAGE NAMED runit

RELATED LINKS
http://smarden.org/runit/
http://smarden.org/runit/sv.8.html
https://en.wikipedia.org/wiki/Runit
https://docs.ansible.com/ansible/2.5/modules/runit_module.html