0

I'm trying to systemctl stop a shell script that runs a few subcommands. However, because the shell script traps several signals, the script itself won't stop on SIGTERM and systemd will stop the process with SIGKILL after the 90 second waiting period. I can understand that: trap is only executed after the child has exited.

Now I'm trying to understand why systemctl stop does not send SIGTERM to the children. man systemd.kill tells me that all remaining processes in the control group of this unit will be killed on unit stop (for services: after the stop command is executed, as configured with ExecStop=).

A basic example of my problem is the following: a systemd unit file, let's call it unitdemo:

[Unit]
Description=test
After=graphical.target systemd-user-sessions.service

[Service]
User=ubuntu
WorkingDirectory=~

PAMName=login
UnsetEnvironment=TERM

StandardOutput=journal
ExecStart=/tmp/mainscript
Restart=always

[Install]
WantedBy=graphical.target

A main script:

#!/bin/bash
function trapme() {
echo SIGTERM sent to main script, trapped but exiting now...
exit 0
}
echo starting main script
trap trapme SIGTERM
echo now starting child script /tmp/childscript
/tmp/childscript
echo child script exited...

And a child script:

#!/bin/bash
function trapme() {
echo childscript has been killed by SIGTERM...
exit 0
}
trap trapme SIGTERM
while true; do sleep 1; done

Issueing systemctl stop unitdemo will only stop after the 90 second wait time, no SIGTERM sent to childscript - no messages in the journal saying "childscript has been killed...".

edit man systemd.exec has more information. Under PAMName there is an entry telling:

           Note that when this option is used for a unit it is very likely
           (depending on PAM configuration) that the main unit process will be
           migrated to its own session scope unit when it is activated. This
           process will hence be associated with two units: the unit it was
           originally started from (and for which PAMName= was configured),
           and the session scope unit. Any child processes of that process
           will however be associated with the session scope unit only.

That explains why the children do not receive a SIGTERM. Now the question becomes: how to terminate this session? I.e. I'm starting a service, but it becomes a session and stopping the service does not stop the session.

BTW I found my way around stopping childscript by using

trap "kill \`cat $xkillerfile\`; ..... "
/tmp/childscript &
echo $! > $killerfile
wait

... but it feels wrong to do it this way. Is there a way to have systemd stop the PIDs in a session - thus end the session - when the main process is stopped? If so, how?

5
  • Unfortunately there is not much useful information in your question. With such a problem you should provide the script (or a minimal version of it which reproduces the problem) and the Systemd unit content (systemctl cat script.service). Besides that the obvious question is: Does the child process terminate (quickly) on SIGTERM? Have you sent SIGTERM directly to that process (i.e. with kill, not with systemctl)? Jun 12, 2023 at 18:35
  • Thanks for your comment, I edited my question - I hope it is clearer now. The child exits immediately when I send it a TERM signal. Jun 12, 2023 at 19:27
  • A user session can be closed by setting KillUserProcesses in logind.conf - which is "no" by default. It's not possible to override that from a unit file, or is it? Jun 13, 2023 at 7:37
  • Why are you starting a user session from the service if you don't want the effects of a session? Jun 14, 2023 at 8:28
  • It runs Xorg, which needs a session (as far as I know). It just seems rather weird that you can start a session by essentially starting a service, but should then stop the session by stopping the session stuff. Jun 14, 2023 at 12:12

1 Answer 1

0

This behaviour would be expected if the Systemd unit has the setting

KillMode=mixed

or

KillMode=process

This is strange as the code you showed in your question does not contain such an entry, and the default is

KillMode=control-group

You may add this default setting to the [Service] section, though. Before you do that (and the obvious systemctl daemon-reload) you can check the state of this setting:

systemctl show unitdemo | grep -i KillMode
3
  • 1
    The unit runs with KillMode=control-group, but it gets worse: if I remove the trap from mainscript, systemd will kill mainscript, but childscript keeps running - i.e. the child does not receive any signals. And there it is: man systemd.exec tells us: Note that when this option is used for a unit it is very likely (depending on PAM configuration) that the main unit process will be migrated to its own session scope unit when it is activated. I'll change my question accordingly. Jun 13, 2023 at 7:01
  • So removing PAMName= solves the problem? Jun 13, 2023 at 21:22
  • Removing PAMName in the demonstration files removes the problem. However, the real system runs Xorg, which needs a session (AFAIK). Jun 14, 2023 at 12:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .