24

In the Linux environment, how can I send a kill signal to a process, while making sure that the exit code returned from that process is 0? Would I have to do some fancy GDB magic for this, or is there a fancy kill signal I'm unaware of?

Test case:

cat; echo $?

killall cat

Trying various kill signals only offers different return signals, such as 129, 137, and 143. My goal is to kill a process which a script runs, but make the script think it was successful.

user9517
  • 114,104
  • 20
  • 206
  • 289
sega01
  • 341
  • 1
  • 2
  • 3

6 Answers6

27

You can attach to the process using GDB and the process ID and then issue the call command with exit(0) as an argument.

call allows you to call functions within the running program. Calling exit(0) exits with a return code of 0.

gdb -p <process name>
....
.... Gdb output clipped
(gdb) call exit(0)

Program exited normally.

As a one-line tool:

gdb --batch --eval-command 'call exit(0)' --pid <process id>
Cristian Ciupitu
  • 6,226
  • 2
  • 41
  • 55
LeStarke
  • 271
  • 3
  • 2
  • 1
    This won't work if the program doesn't use (g)libc, for example a program written in assembly: `No symbol table is loaded. Use the "file" command`. Though this is highly unlikely. – Cristian Ciupitu Jul 24 '14 at 15:24
  • Worked on a ruby script :-D – Mikhail Nov 19 '14 at 19:08
  • 2
    @CristianCiupitu There is a way around that problem. On entry to the next system call simply modify the relevant registers to cause the target program to call the `_exit` system call with `0` as argument. That will work on any process that isn't simply looping and burning CPU cycles. If the process happens not to be stuck in an infinite loop, you can still use the same approach if you can find the necessary instructions somewhere in its executable and point the instruction pointer there. – kasperd Mar 03 '15 at 15:42
  • @Mikhail it worked on "a ruby script" because GDB was connected to the ruby interpreter process whose binary was linked with glibc. – Daniel Mar 03 '15 at 17:17
  • @kasperd, yeah, I though so, but more precise instructions would be nice. – Cristian Ciupitu Mar 03 '15 at 20:50
  • Worked well for Python 2.7 – nehem Mar 01 '16 at 22:43
  • I had a lost process spawned from ssh session - a gdb debugging another app. The only way to exit that process from reconnected ssh session was to debug gdb with a gdb))), and once inside a debugging session do a (gdb) call exit(0) – Mykola Mar 04 '20 at 21:02
  • For older glibc versions (at least up to glibc 2.12) I found I had to cast the exit call in gdb as call (int) exit(0) - without the cast I get the error: 'exit' has unknown return type; cast the call to its declared return type. – Pete Mar 07 '20 at 22:49
8

No. When the shell catches SIGCHLD it unconditionally sets the return value appropriately to a non-zero value, so this would require modification of either the script or of the shell.

Ignacio Vazquez-Abrams
  • 45,019
  • 5
  • 78
  • 84
4

This one-liner worked for me:

/bin/bash -c '/usr/bin/killall -q process_name; exit 0'
HBruijn
  • 72,524
  • 21
  • 127
  • 192
  • 2
    I don't think you understood the question. There is no way, that command is going to achieve what was being asked for. This is what I got from using your command: `$ cat; echo $?` `Terminated` `143`. – kasperd Mar 03 '15 at 15:37
  • 3
    @Landon Thomas your line of code shown here does in fact return 0. However the process_name which was killed does NOT return 0, which is what the OP wanted. – Daniel Mar 03 '15 at 17:18
  • 1
    I am exactly looking for this answer! I try to run `killall -q proc_name` and do not want it to return non-zero even if proc_name is not running! The -q option merely supresses warning message but does not affect exit code of killall – xrfang Jan 07 '21 at 02:20
3

A bit hacky way, but..

You can create a wrapper to your process, overriding SIGCHLD Handler. For example:

#!/bin/bash
set -o monitor
trap 'exit(0)' CHLD
/some/dir/yourcommand

After that you can make your script running this wrapper instead of your process by putting it earlier in $PATH and renaming to the same name.

DukeLion
  • 3,239
  • 1
  • 17
  • 19
3

I m not sure but this will exit with a 0 if any of the listed signals are received. You could perform other actions including calling a function, etc.

#!/bin/bash 
trap 'exit 0' SIGINT SIGQUIT SIGTERM
TBI Infotech
  • 1,536
  • 9
  • 15
0

To make sure the kill or killall command doesn't break the shell (like in a bash script with set -e), or make sure the line with kill exits with 0. We may try

killall <PROCESS_NAME> || /bin/true

or

kill <PROCESS_NAME> || /bin/true
socrates
  • 101
  • 1