Package: runit
Version: 2.1.2-39.1
Severity: normal
Tags: upstream

Hi,

runsv(8) says:

CUSTOMIZE CONTROL
       For each control character c sent to the control pipe, runsv first
       checks if service/control/c exists and is executable. If so, it
       starts service/control/c and waits for it to terminate, before
       interpreting the command. If the program exits with return code 0,
       runsv refrains from sending the service the corresponding signal. The
       command o is always considered as command u. On command d first
       service/control/t is checked, and then service/control/d. On command
       x first service/control/t is checked, and then service/control/x. The
       control of the optional log service cannot be customized.

This is, however, not what the code actually does.

For the 'd' control character 
(https://github.com/vulk-archive/runit/blob/master/src/runsv.c#L324):

  case 'd': /* down */
    s->want =W_DOWN;
    update_status(s);
    if (s->state == S_RUN) stopservice(s);
    break;

'x' is handled analogously.

The stopservice() function 
(https://github.com/vulk-archive/runit/blob/master/src/runsv.c#L246) looks like 
this:

void stopservice(struct svdir *s) {
  if (s->pid && ! custom(s, 't')) {
    kill(s->pid, SIGTERM);
    s->ctrl |=C_TERM;
    update_status(s);
  }
  if (s->want == W_DOWN) {
    kill(s->pid, SIGCONT);
    custom(s, 'd'); return;
  }
  if (s->want == W_EXIT) {
    kill(s->pid, SIGCONT);
    custom(s, 'x');
  }
}

i.e. the control/d or control/x script is only run after runsv sent its child a 
SIGTERM, not before as the manpage suggests.

I would suggest that the code should be changed to reflect the documented 
behaviour, not vice versa. Perhaps the following code would work (but I have 
not tested it):

void stopservice(struct svdir *s) {
  if (s->pid) {
    if (s->want == W_DOWN) {
      kill(s->pid, SIGCONT);
      if (custom(s, 'd')) return;
    }
    if (s->want == W_EXIT) {
      kill(s->pid, SIGCONT);
      if (custom(s, 'x')) return;
    }
    if (! custom(s, 't')) {
      kill(s->pid, SIGTERM);
      s->ctrl |=C_TERM;
      update_status(s);
    }
  }
}

Credits to https://serverfault.com/users/135556/keith for pointing the bug out.

Best regards,

AndrĂ¡s

-- System Information:
Debian Release: bullseye/sid
  APT prefers unstable
  APT policy: (350, 'unstable'), (350, 'stable')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 5.10.0-3-amd64 (SMP w/8 CPU threads)
Kernel taint flags: TAINT_PROPRIETARY_MODULE, TAINT_OOT_MODULE, 
TAINT_UNSIGNED_MODULE
Locale: LANG=en_US.UTF-8, LC_CTYPE=hu_HU.UTF-8 (charmap=UTF-8), 
LANGUAGE=en_US.UTF-8
Shell: /bin/sh linked to /bin/bash
Init: runit (via /run/runit.stopit)
LSM: AppArmor: enabled

Versions of packages runit depends on:
ii  libc6           2.31-9
ii  sysuser-helper  1.3.5.1

Versions of packages runit recommends:
ii  runit-init  2.1.2-39.1

Versions of packages runit suggests:
ii  socklog  2.1.0+repack-4+b1

-- Configuration Files:
/etc/runit/1 changed [not included]
/etc/runit/2 changed [not included]
/etc/runit/3 changed [not included]

-- no debconf information

-- 
                Laughing stock: cattle with a sense of humour.

Reply via email to