Zabić proces i zmusić go do zwrócenia 0 w systemie Linux?

16

Jak w środowisku Linux mogę wysłać sygnał zabicia do procesu, upewniając się, że kod wyjścia zwrócony z tego procesu wynosi 0? Czy musiałbym wykonać w tym celu jakąś fantazyjną magię GDB, czy może jest jakiś fantazyjny sygnał zabicia, którego nie jestem świadomy?

Przypadek testowy:

cat; echo $?

killall cat

Próbowanie różnych sygnałów zabicia oferuje tylko różne sygnały powrotu, takie jak 129, 137 i 143. Moim celem jest zabicie procesu uruchamianego przez skrypt, ale sprawienie, by skrypt uznał, że się powiódł.

sega01
źródło

Odpowiedzi:

20

Możesz dołączyć do procesu za pomocą GDB i identyfikatora procesu, a następnie wydać callpolecenie exit(0)jako argument.

callpozwala na wywoływanie funkcji w ramach uruchomionego programu. Wywołanie exit(0)kończy pracę z kodem powrotu 0.

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

Program exited normally.

Jako narzędzie jednowierszowe:

gdb --batch --eval-command 'call exit(0)' --pid <process id>
LeStarke
źródło
To nie będzie działać, jeśli program nie korzysta (g) libc, na przykład program napisany w montażu: No symbol table is loaded. Use the "file" command. Chociaż jest to bardzo mało prawdopodobne.
Cristian Ciupitu
Pracowałem nad skryptem rubinowym :-D
Michaił
1
@CristianCiupitu Istnieje sposób na obejście tego problemu. Po wejściu do następnego wywołania systemowego wystarczy zmodyfikować odpowiednie rejestry, aby program docelowy wywołał wywołanie _exitsystemowe 0jako argument. Będzie to działać na każdym procesie, który nie jest po prostu zapętleniem i spaleniem cykli procesora. Jeśli proces nie utknie w nieskończonej pętli, nadal możesz zastosować to samo podejście, jeśli możesz znaleźć niezbędne instrukcje gdzieś w jego pliku wykonywalnym i wskazać tam wskaźnik instrukcji.
kasperd
@ Michaił działał na „skrypcie ruby”, ponieważ GDB był połączony z procesem interpretera ruby, którego plik binarny był powiązany z glibc.
Daniel
@kasperd, tak, tak myślałem, ale bardziej dokładne instrukcje byłyby fajne.
Cristian Ciupitu,
8

Nie. Gdy powłoka zostanie złapana SIGCHLD, bezwarunkowo ustawia wartość zwracaną odpowiednio na wartość niezerową, więc wymagałoby to modyfikacji skryptu lub powłoki.

Ignacio Vazquez-Abrams
źródło
3

Nie jestem pewien, ale to zakończy się z 0, jeśli którykolwiek z wymienionych sygnałów zostanie odebrany. Możesz wykonywać inne czynności, w tym wywoływać funkcję itp.

#!/bin/bash 
trap 'exit 0' SIGINT SIGQUIT SIGTERM
TBI Infotech
źródło
3

Ten liner działał dla mnie:

/bin/bash -c '/usr/bin/killall -q process_name; exit 0'
Landon Thomas
źródło
Nie sądzę, że zrozumiałeś pytanie. Nie ma mowy, aby to polecenie osiągnęło to, o co proszono. To co mam z użyciem polecenia: $ cat; echo $? Terminated 143.
kasperd
2
@Landon Thomas, twoja linia kodu pokazana tutaj faktycznie zwraca 0. Jednak nazwa_procesu, która została zabita, NIE zwraca 0, czego chciał OP.
Daniel
2

Trochę hacky sposób, ale ...

Możesz utworzyć opakowanie dla swojego procesu, zastępując moduł obsługi SIGCHLD. Na przykład:

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

Następnie możesz ustawić skrypt uruchamiający to opakowanie zamiast procesu, umieszczając go wcześniej w $ PATH i zmieniając jego nazwę na tę samą nazwę.

DukeLion
źródło