3

Right now I have the following:

# this function is meant for future script expansions
# its purpose is clear, i.e. to clean up some temp files
# now, it is doing nothing, just a special null command
cleanup_on_signal() { :; }

# define functions to handle signals
# treat them as errors with appropriate messages
# example calls:
#    kill -15   this_script_name    # POSIX, all shells compatible
#    kill -TERM this_script_name    # Bash and alike - newer shells
signal_handler_HUP()   {  cleanup_on_signal; print_error_and_exit "\\ntrap()" "Caught SIGHUP (1).\\n\\tClean-up finished.\\n\\tTerminating. Bye!";    }
signal_handler_INT()   {  cleanup_on_signal; print_error_and_exit "\\ntrap()" "Caught SIGINT (2).\\n\\tClean-up finished.\\n\\tTerminating. Bye!";    }
signal_handler_QUIT()  {  cleanup_on_signal; print_error_and_exit "\\ntrap()" "Caught SIGQUIT (3).\\n\\tClean-up finished.\\n\\tTerminating. Bye!";   }
signal_handler_ABRT()  {  cleanup_on_signal; print_error_and_exit "\\ntrap()" "Caught SIGABRT (6).\\n\\tClean-up finished.\\n\\tTerminating. Bye!";   }
signal_handler_TERM()  {  cleanup_on_signal; print_error_and_exit "\\ntrap()" "Caught SIGTERM (15).\\n\\tClean-up finished.\\n\\tTerminating. Bye!";  }

# use the above functions as signal handlers;
# note that the SIG* constants are undefined in POSIX,
# and numbers are to be used for the signals instead
trap 'signal_handler_HUP' 1; trap 'signal_handler_INT' 2; trap 'signal_handler_QUIT' 3; trap 'signal_handler_ABRT' 6; trap 'signal_handler_TERM' 15

I want the script to terminate tidily on shutdown, which right now it does.

But I opened one suggestion of a colleague to issue a question on CTRL+C instead of quitting to shell.

I don't want to turn off the machine, I don't do that often, anyway:

What signal is sent to running programs / scripts on shutdown?

  • It is SIGTERM. see unix.stackexchange.com/questions/10231/… – Rui F Ribeiro Feb 10 at 11:43
  • I think, when the init manager (systemd/whatever) does not do their job on some process, then the remaining processes get a SIGTERM. The ones that do not obey SIGTERM, are then sent a SIGKILL. The system makes an effort to shutdown as cleanly as possible. – Rui F Ribeiro Feb 10 at 11:49
  • It is a pleasure too, enjoy your day. – Rui F Ribeiro Feb 10 at 12:19
  • Added some shutdown() snippet source. – Rui F Ribeiro Feb 10 at 12:25
7

While on shutdown the running processes are first told to stop by init(from sendsigs on old implementations, according to @JdeBP)/systemd.

The remaining processes, if any, are sent a SIGTERM. The ones that ignore SIGTERM or do not finish on time, are shortly thereafter sent a SIGKILL by init/systemd.

Those actions are meant to guarantee a stable/clean shutdown (as possible).

Out of curiosity, see the report of a related (old) systemd bug:

Bug 1352264 - systemd immediately sends SIGKILL after SIGTERM during shutdown

systemd immediately sends SIGKILL after SIGTERM during shutdown, there's no window of opportunity for processes to terminate

Also from shutdown.c/main():

    disable_coredumps();

    log_info("Sending SIGTERM to remaining processes...");
    broadcast_signal(SIGTERM, true, true, arg_timeout);

    log_info("Sending SIGKILL to remaining processes...");
    broadcast_signal(SIGKILL, true, false, arg_timeout);

Also from sysvinit 2.94 sources/init.c, here is the code around a SIGTERM round. If any process(es) were sent a SIGTERM, test each second during 5 seconds to see if there are any processes remaining. Leave the wait if in one of those tests none process is found, or send SIGKILL to the remaining process(es) after the 5 seconds are up.

        switch(round) { 
                case 0: /* Send TERM signal */
                        if (talk)
                                initlog(L_CO,
                                        "Sending processes configured via /etc/inittab the TERM signal");
                        kill(-(ch->pid), SIGTERM);
                        foundOne = 1;
                        break;
                case 1: /* Send KILL signal and collect status */
                        if (talk)
                                initlog(L_CO,
                                        "Sending processes configured via /etc/inittab the KILL signal");
                        kill(-(ch->pid), SIGKILL);
                        break;
        }
        talk = 0;

    }
    /*
     *  See if we have to wait 5 seconds
     */
    if (foundOne && round == 0) {
        /*
         *      Yup, but check every second if we still have children.
         */
        for(f = 0; f < sleep_time; f++) {
                for(ch = family; ch; ch = ch->next) {
                        if (!(ch->flags & KILLME)) continue;
                        if ((ch->flags & RUNNING) && !(ch->flags & ZOMBIE))
                                break;
                }
                if (ch == NULL) {
                        /*
                         *      No running children, skip SIGKILL
                         */
                        round = 1;
                        foundOne = 0; /* Skip the sleep below. */
                        break;
                }
                do_sleep(1);
        }
    }
  }

  /*
   *    Now give all processes the chance to die and collect exit statuses.
   */
  if (foundOne) do_sleep(1)
  for(ch = family; ch; ch = ch->next)
        if (ch->flags & KILLME) {
                if (!(ch->flags & ZOMBIE))
                    initlog(L_CO, "Pid %d [id %s] seems to hang", ch->pid,
                                ch->id);
                else {
                    INITDBG(L_VB, "Updating utmp for pid %d [id %s]",
                                ch->pid, ch->id);
                    ch->flags &= ~RUNNING;
                    if (ch->process[0] != '+')
                        write_utmp_wtmp("", ch->id, ch->pid, DEAD_PROCESS, NULL);
                }
        }

  /*
   *    Both rounds done; clean up the list.
   */
  • It's sendsigs, not init, in the van Smoorenburg system. – JdeBP Feb 10 at 15:18
  • @JdeBP Thanks, will check it better later on. – Rui F Ribeiro Feb 10 at 15:25
  • 1
    I love the details, great answer! – Vlastimil Feb 10 at 16:31
  • Ah, I also gained something from it, know I know when had problems in some situations, why it did take longer to shutdown. (edit the answer about the sysV code) – Rui F Ribeiro Feb 10 at 16:45
  • 1
    If you need more than 5 seconds to shutdown, make your program an systemd service, this allows up to 90 seconds with the default settings – Ferrybig Feb 10 at 20:03

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.