Jak mam sprawdzić, czy dany PID działa?

16

Piszę skrypt Perla, który analizuje pliki dziennika w celu zebrania PID, a następnie sprawdza, czy ten PID jest uruchomiony. Próbuję wymyślić najlepszy sposób na sprawdzenie tego. Oczywiście mógłbym zrobić coś takiego:

system("ps $pid > /dev/null") && print "Not running\n";

Jednak wolę unikać połączenia systemowego, jeśli to możliwe. Dlatego pomyślałem, że mogę użyć /procsystemu plików (przenośność nie stanowi problemu, zawsze będzie działał w systemie Linux). Na przykład:

if(! -d "/proc/$pid"){
    print "Not running\n";
}

Czy to jest bezpieczne? Czy zawsze mogę założyć, że jeśli nie ma /proc/$pid/katalogu, powiązany PID nie jest uruchomiony? Spodziewam się tego, skoro i tak AFAIK pssam otrzymuje informacje, /procale ponieważ dotyczy to kodu produkcyjnego, chcę być pewien.

Czy mogą więc wystąpić przypadki, w których uruchomiony proces nie ma /proc/PIDkatalogu lub /proc/PIDkatalog istnieje, a proces nie jest uruchomiony? Czy istnieje powód, dla którego wolisz parsowanie psniż sprawdzanie istnienia katalogu?

terdon
źródło
2
jest też killfunkcja perla wykorzystująca sygnał 0, który nie zabija, ale mówi, czy możesz to zrobić (tzn. potrzebujesz zgody na sygnalizowanie tego procesu).
Meuh
1
'/ proc / $ PID' powinno być w porządku, jeśli robisz to w Linuksie.
likewhoa,
7
@terdon Zauważ, że bez względu na to, jakiej metody użyjesz (i która kill -0jest najlepsza), to powie ci tylko, czy jest uruchomiony proces z danym PID . Nie mówi ci, czy proces będzie nadal działał o jedną milisekundę później, ani nie mówi, czy jest to proces, który Cię interesuje, czy proces niepowiązany, któremu przypisano ten sam PID po śmierci interesującego procesu . Prawie zawsze błędem jest sprawdzenie, czy dany PID działa : jest bardzo niewiele okoliczności, w których nie jest to podatne na warunki wyścigowe.
Gilles „SO- przestań być zły”,
1
@Gilles rzeczywiście powinienem również sprawdzić nazwę procesu. Jednak w tym przypadku nie obchodzi mnie, czy zmiana stanu nastąpi milisekundę później. Mam procesy wymienione jako aktywne w dB i odpowiednim pliku z pidami. Muszę tylko sprawdzić, czy coś, co według DB nie działa, i mam wystarczającą kontrolę nad konfiguracją, aby wiedzieć, że nie można jej uruchomić ponownie losowo.
terdon
3
@ MickLH wow, to mi powiedziano. Byłby to użyteczny komentarz zamiast świętowania własnego blasku, gdybyś próbował wyjaśnić, co jest tak złe i niebezpieczne. Nie wątpię, że masz rację, nigdy nie twierdziłem, że jestem programistą, dlatego zadałem to pytanie, ale udało ci się być zarówno obraźliwym, jak i nieprzydatnym.
terdon

Odpowiedzi:

20

kill(0,$pid)Można użyć funkcji perla .

Jeśli kod powrotu to 1, wówczas istnieje PID i można do niego wysłać sygnał.

Jeśli kod powrotu to 0, musisz sprawdzić $ !. Może to być EPERM (odmowa dostępu), co oznacza, że ​​proces istnieje lub ESRCH, w którym to przypadku proces nie istnieje.

Jeśli Twój kod sprawdzający jest uruchomiony, rootmożesz to uprościć, sprawdzając tylko kod powrotu kill; 0 => błąd, 1 => ok

Na przykład:

% perl -d -e 0

Loading DB routines from perl5db.pl version 1.37
Editor support available.

Enter h or 'h h' for help, or 'man perldebug' for more help.

main::(-e:1):   0
  DB<1> print kill(0,500)
0
  DB<2> print $!
No such process
  DB<3> print kill(0,1)
0
  DB<4> print $!
Operation not permitted
  DB<5> print kill(0,$$)
1

Można to zrobić w prostą funkcję

use Errno;

sub test_pid($)
{
  my ($pid)=@_;

  my $not_present=(!kill(0,$pid) && $! == Errno::ESRCH);

  return($not_present);
}

print "PID 500 not present\n" if test_pid(500);
print "PID 1 not present\n" if test_pid(1);
print "PID $$ not present\n" if test_pid($$);
Stephen Harris
źródło
FWIW, dodałem prostą funkcję pokazującą, jak możesz to zrobić.
Stephen Harris,
Tak, chyba pójdę z tym. Usunąłem swój komentarz, ponieważ zdałem sobie sprawę, że wszystko, czego potrzebowałem, to if (!kill(0,$pid) && $! =~ /No such process/){ exit; }coś podobnego. Bardziej podoba mi się twoje Errnorozwiązanie, dzięki. Chociaż prawdopodobnie pójdę z tym, poczekam chwilę, aby ktokolwiek mógł odpowiedzieć na podstawowe pytanie dotyczące Linuksa.
terdon
2
Jeśli /procjest zamontowany, to każdy PID widoczny w przestrzeni nazw będzie obecny, więc -d /proc/$pidtest będzie działał ... ale wymaga wyjścia do systemu plików zamiast używania rodzimych wywołań systemowych.
Stephen Harris,
Właśnie tego chciałem uniknąć, tak.
terdon
2
@terdon: Właśnie zdałem sobie sprawę, że moje zamieszanie wynika z faktu, że przez „wywołanie systemowe” miałeś na myśli „ systemwywołanie” - tj. wywołanie systemsamej funkcji, a nie „wywołanie systemowe” . Tego drugiego nie da się uniknąć, ale pierwszego z pewnością można. Ma to teraz sens!
user541686,
6
  • Jestem 99,9% pewien, że sprawdzenie, czy istnieje (i jest katalogiem) jest 98% tak wiarygodne jak technika. Powodem, dla którego 98% nie jest 100%, jest kwestia, na którą Stephen Harris poruszył (i odbił się) w komentarzu - mianowicie, system plików może nie zostać zamontowany. To może być ważne zastrzeżenia, że system Linux bez jest uszkodzony system zdegradowany - wszak rzeczy podoba ,/proc/PIDkill 0/proc/procpstop i lsofprawdopodobnie nie będzie działać - i tak to może nie być problemem dla systemu produkcyjnego. Ale (teoretycznie) jest możliwe, że nigdy nie został zamontowany (chociaż może to uniemożliwić przywrócenie systemu do normalnego stanu), z pewnością jest możliwe odmontowanie go (przetestowałem go 1) i uważam, że nie ma żadnej gwarancji, że będzie istnieć (tj. nie jest wymagana przez POSIX). I, chyba że system jest całkowicie zamknięty, killbędzie działał.
  • Komentarz Stephena mówi o „wyjściu do systemu plików” i „korzystaniu z natywnych wywołań systemowych”. Uważam, że w dużej mierze jest to czerwony śledź.
    • Tak, każda próba dostępu /proc wymaga czytania katalogu root znaleźć się /procsystem plików. Dotyczy to każda próba dostępu do dowolnego pliku bezwzględną ścieżkę, w tym rzeczy w /bin, /etci /dev. Zdarza się to tak często, że katalog główny jest z pewnością buforowany w pamięci przez cały okres życia (czas działania) systemu, więc ten krok można wykonać bez żadnego wejścia / wyjścia dysku. A kiedy już będziesz miał igłę /proc, wszystko, co się wydarzy, jest w pamięci.
    • Jak uzyskać dostęp /proc? Z stat, open, readdir, itd., Które są rodzimym systemem nazywa każdy kawałek jak kill.
  • Pytanie dotyczy trwającego procesu. To jest śliskie zdanie. Jeśli naprawdę chcesz przetestować, czy proces jest uruchomiony (tj. W kolejce uruchomieniowej; może bieżący proces na jakimś procesorze; nie śpi, nie czeka lub nie jest zatrzymany), może być konieczne wykonanie a i odczytanie wyniku lub spojrzenie na . Ale nie widzę żadnej wskazówki w twoim pytaniu lub komentarzach, że zajmujesz się tym.ps PID /proc/PID/stat

    Słoń w pokoju jest jednak taki, że proces zombie 2 może być trudny do odróżnienia od procesu, który jest żywy i ma się dobrze.  kill 0działa na zombie i istnieje. Możesz zidentyfikować zombie za pomocą technik wymienionych w poprzednim akapicie (robienie i czytanie wyników lub patrzenie ). My bardzo szybkie i dorywczo (czyli niezbyt dokładny) badanie sugeruje, że można to zrobić także przez robi lub na , lub - to nie powiedzie się na zombie. (Zawiodą jednak również w przypadku procesów, których nie posiadasz)./proc/PIDps PID/proc/PID/statreadlinklstat/proc/PID/cwd/proc/PID/root/proc/PID/exe

____________
1  gdy -f( m rozwiązaniem Orce) nie pomoże, -l( l azy).
2  tj. Proces, który zakończył / zmarł / zakończył, ale którego rodzic jeszcze nie zrobił wait.

G-Man mówi „Przywróć Monikę”
źródło
Dziękuję za komentarz do mojej odpowiedzi, którą usunąłem, ponieważ była niepoprawna. Nie sądzę, że strona kill(2)wskazuje bezpośrednio na zachowanie, które wskazałeś, ale tak perlfuncjest. Wyślę do Michaela Kerriska e-maila, aby zobaczyć, co ma on do powiedzenia na stronie systemowej.
jrw32982 obsługuje Monikę
kill(2)
Złożyłem
@ jrw32982: Cóż, strona podręcznika mówi: „ Argument sig … może wynosić 0, w takim przypadku sprawdzanie błędów jest wykonywane…” i „ BŁĘDY - wywołanie systemowe kill () zakończy się niepowodzeniem i nie zostanie wysłany żaden sygnał, jeśli: … Proces wysyłania nie jest superużytkownikiem, a jego efektywny identyfikator użytkownika nie odpowiada efektywnemu identyfikatorowi użytkownika procesu odbierającego. … ”Teraz, gdy o tym wspominasz, przypuszczam, że można to interpretować na więcej niż jeden sposób, ale niestety wiele stron podręcznika uniksowego jest napisanych w tym stylu, co wymaga czytania między wierszami. Michael może wierzyć, że jest wystarczająco jasny.
G-Man mówi „Reinstate Monica”
Michael zmienił stronę kill(2)podręcznika (nie widzę go jeszcze online): „Jeśli sig ma wartość 0, to nie jest wysyłany żaden sygnał, ale nadal wykonywane są kontrole istnienia i uprawnień; można tego użyć do sprawdzenia istnienia identyfikator procesu lub identyfikator grupy procesów, które osoba dzwoniąca może zasygnalizować. ”
jrw32982 obsługuje Monikę