2

How would I create a script that does not respond to Ctrl-C? This should also prevent any processes launched by the script from being killed (I'm trying to keep apt-get upgrade from being killed).

(I have done some Internet searching, but I only found questions about how to kill rogue processes.)

Context: I'm creating Linux master VHDs for an academic VM cluster. When a machine is created, it will log in as root on the console and execute my script, which will update the machine, create a new user, and enable SSH. If someone logs into the console before it finishes updating, I want to prevent them from (accidentally or intentionally) canceling the update process with Ctrl-C.

  • How about just trap '' INT? – Celada Mar 19 '15 at 1:51
  • Could you instead disable such "parasitic" logins while the initialization script is running? – dhag Mar 19 '15 at 2:13
  • The script will also interactively create a new account and enable ssh for that account, so the image logs in as root on the console and runs the script. – stephenwade Mar 19 '15 at 2:34
  • Prevent them from logging in while updating the VM. In my view the question is too narrow. You focus on how to prevent ending a script by pressing CTRL-C. I think it should be: how to make sure that the apt-get update script is completely executed. – SPRBRN Mar 19 '15 at 8:29
  • 1
    Do you want to prevent interrupts from killing a script, or do you want to prevent users from canceling the update? The latter is more general and has simpler solutions, so you're going to end up getting answers for that even if you asked for the former – Michael Mrozek Mar 19 '15 at 13:38
1

Set the INT signal to be ignored:

trap '' INT

This will cause SIGINT, which is what Ctrl-C sends, to do nothing to your script.

The user experience consequences of doing this are a bit unclear to me; this could be annoying if the script gets stuck in a operation that takes a long time to complete. It may be best to warn the user that the script should not (and cannot easily) be interrupted before ignoring the signal.

  • This doesn't appear to work. It looks like this traps the interrupt for the script but not for apt-get update which is launched by the script. – stephenwade Mar 19 '15 at 2:03
  • This is a one-time script that will run inside a newly-created VM to update it and set up a new user – stephenwade Mar 19 '15 at 2:07
  • Weird. In my tests, a script running apt-get update after calling trap as above doesn't pass Ctrl-C to a new process started by the shell. (The way I understand it, signal handlers are inherited by child processes.) – dhag Mar 19 '15 at 2:10
  • Just tested with sudo apt-get update in a script and hitting Ctrl-C. Without trap, the update just drops me back to the terminal. With trap, the update stops with some weird errors. Gist link – stephenwade Mar 19 '15 at 2:32
1

With a perl script, it's as easy as:

#!/usr/bin/perl
use strict;
use warnings;

$SIG{'INT'} = "IGNORE"; 

#do stuff. 

I'd suggest though, rather than a script - have you consider an 'at' job?

echo "sudo apt-get upgrade >> /tmp/upgrade.log" | at now

Which will kick it off as task within the scheduler.

0

Why don't you run your program as a background job, so there is no terminal to issue the ctrl + c interrupt.

Then the only way to kill the process is by issuing sudo kill PID which would require root privileges. But if the person has root privileges than you are just out of luck in my opinion... If they have root and want to end the process they will...

  • I also wanted the script to prompt for a username before creating the new user. I mainly want to protect against someone who doesn't know what's going on and hits Ctrl-C, rather than someone who deliberately wants to stop the script. – stephenwade Mar 19 '15 at 3:57
  • Why dont you have a terminal open, ask for user name and password, save it to a temp file or env variable, close and then continue processing in another process without an open terminal? – Dylan Mar 19 '15 at 3:59
  • Or better yet why dont you run all of your apt-get commands before opening a terminal and asking for input. As part of rc.local or something along those lines? Or just an an updated image when the machine is created, so no need to update. – Dylan Mar 19 '15 at 4:01
0

Set the run level to 1 (single-user / minimal mode) with:
init 1
or
telinit 1

More info:
Red Hat
Debian

0

Depends on what and how you build it.

While trapping may be an interesting option, I imagine some environments may cause it to not work as expected.

On Rails for instance, rescuing Interrupt, as well as rescuing Exception (Which Interrupt extends) will cause the program to behave "abnormally" on Interrupt signals. On Java, catching Throwable wields similar behavior.

Trapping the Interrupt Signal may be a good option, but you have to consider when to start and when to stop trapping it, what may happen in between and how your application will respond to this "trapping" (i.e., will your application die anyway or throw an exception or some other error? Will it bypass your application but still kill the apt-get? and so on).

Also, kill pid may cause a different behavior, and as far as I know kill -9 pid will kill your process no matter what you do. I would consider running it as a background job that saves to a file, and monitoring said file for changes until update is finished (Maybe even showing it onscreen), possibly while rescuing/catching/etc SIGINTs. I'd also possibly look at something like setting run level or something to avoid a simple kill pid, since the need for a kill -9 pid may avoid honest mistakes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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