Wie soll ich prüfen, ob eine bestimmte PID läuft?

16

Ich schreibe ein Perl-Skript, das Protokolldateien analysiert, um PIDs zu sammeln, und dann prüft, ob diese PID ausgeführt wird. Ich versuche, mir den besten Weg zu überlegen, um diesen Scheck zu machen. Offensichtlich könnte ich etwas machen wie:

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

Ich würde es jedoch vorziehen, den Systemaufruf nach Möglichkeit zu vermeiden. Ich dachte daher, ich könnte das /procDateisystem verwenden (Portabilität ist kein Problem, dies wird immer auf einem Linux-System ausgeführt). Beispielsweise:

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

Ist das sicher? Kann ich immer davon ausgehen, dass /proc/$pid/die zugehörige PID nicht ausgeführt wird , wenn kein Verzeichnis vorhanden ist? Ich gehe davon aus, dass AFAIK psselbst /procsowieso seine Informationen erhält, aber da es sich um Seriencode handelt, möchte ich sicher gehen.

Kann es also Fälle geben, in denen ein laufender Prozess kein /proc/PIDVerzeichnis hat oder in denen ein /proc/PIDVerzeichnis existiert und der Prozess nicht läuft? Gibt es einen Grund, das Parsen der psÜberprüfung auf das Vorhandensein des Verzeichnisses vorzuziehen ?

terdon
quelle
2
Es gibt auch die Perl- killFunktion mit dem Signal 0, die keine Tötung durchführt, aber angibt, ob Sie dies tun könnten (dh Sie benötigen die Erlaubnis, diesen Prozess zu signalisieren).
Meuh
1
'/ proc / $ PID' sollte in Ordnung sein, wenn Sie dies unter Linux tun.
Likewhoa
7
@terdon Beachten Sie, dass unabhängig von der von Ihnen verwendeten (und kill -0der besten) Methode nur angezeigt wird, ob ein Prozess mit der angegebenen PID ausgeführt wird . Es sagt Ihnen nicht, ob der Prozess eine Millisekunde später noch ausgeführt wird, und es sagt Ihnen nicht, ob der Prozess derjenige ist, an dem Sie interessiert sind, oder ein nicht verwandter Prozess, dem nach dem Abbruch des interessanten Prozesses dieselbe PID zugewiesen wurde . Es ist fast immer ein Fehler zu testen, ob eine bestimmte PID ausgeführt wird : Es gibt nur sehr wenige Umstände, unter denen dies nicht für Rennbedingungen anfällig ist.
Gilles 'SO- hör auf böse zu sein'
1
@ Gilles in der Tat sollte ich auch den Prozessnamen überprüfen. In diesem Fall ist es mir jedoch egal, ob sich der Status eine Millisekunde später ändert. Ich habe Prozesse in einem dB als aktiv aufgelistet und eine entsprechende Datei mit den Pids. Ich muss nur überprüfen, ob etwas, von dem die DB denkt, dass es ausgeführt wird, tatsächlich nicht ausgeführt wird, und über ausreichend Kontrolle über das Setup verfügen, um zu wissen, dass es nicht zufällig neu gestartet werden kann.
Terdon
3
@ MickLH wow, das habe ich gesagt. Das wäre eigentlich ein nützlicher Kommentar gewesen, anstatt ein Fest Ihrer eigenen Brillanz zu feiern, hätten Sie sich die Mühe gemacht, zu erklären, was so schlimm und gefährlich ist. Ich bezweifle nicht, dass Sie Recht haben. Ich habe nie behauptet, ein Programmierer zu sein. Deshalb habe ich die Frage gestellt, aber Sie haben es geschafft, sowohl beleidigend als auch nicht hilfreich zu sein.
Terdon

Antworten:

20

Die Perl-Funktion kill(0,$pid)kann verwendet werden.

Wenn der Rückkehrcode 1 ist, ist die PID vorhanden und Sie können ein Signal an sie senden.

Wenn der Rückkehrcode 0 ist, müssen Sie $! Überprüfen. Es kann EPERM (Berechtigung verweigert) sein, was bedeutet, dass der Prozess existiert, oder ESRCH, in welchem ​​Fall der Prozess nicht existiert.

Wenn Ihr Überprüfungscode so läuft root, können Sie dies vereinfachen, indem Sie nur den Rückkehrcode von kill überprüfen. 0 => Fehler, 1 => ok

Beispielsweise:

% 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

Dies kann zu einer einfachen Funktion gemacht werden

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
quelle
FWIW, ich habe eine einfache Funktion hinzugefügt, die zeigt, wie Sie dies tun können.
Stephen Harris
Ja, ich denke, ich werde damit weitermachen. Ich habe meinen Kommentar gelöscht, da mir klar wurde, dass ich nur etwas if (!kill(0,$pid) && $! =~ /No such process/){ exit; }oder ähnliches brauchte . Ihre ErrnoLösung gefällt mir allerdings besser, danke. Während ich wahrscheinlich damit anfangen werde, werde ich eine Weile warten, falls jemand die zugrunde liegende Linux-Frage beantworten kann.
Terdon
2
Wenn /procgemountet ist, ist jede im Namespace sichtbare PID vorhanden, sodass Ihr -d /proc/$pidTest funktionieren würde. Dabei wird jedoch nicht über systemeigene Systemaufrufe auf das Dateisystem zugegriffen.
Stephen Harris
Welches ist genau das, was ich vermeiden wollte, ja.
Terdon
2
@terdon: Mir ist gerade aufgefallen, dass meine Verwirrung durch die Tatsache entstanden ist, dass Sie unter "Systemaufruf" eigentlich " systemAufruf" verstanden haben - also einen Aufruf der systemFunktion selbst, keinen "Systemaufruf" . Letzteres können Sie nicht vermeiden, Ersteres jedoch mit Sicherheit. Macht jetzt Sinn!
Mehrdad
6
  • Ich bin mir zu 99,9% sicher, dass die Überprüfung, ob vorhanden (und ein Verzeichnis) ist, zu 98% so zuverlässig ist wie die Technik. Der Grund, warum die 98% nicht 100% sind, ist ein Punkt, den Stephen Harris in einem Kommentar angerissen hat (und der abprallt) - das Dateisystem ist möglicherweise nicht gemountet. Es kann , dass ein Linux - System Anspruch gültig sein , ohne eine Beschädigung abgebaut System - nach allem, was gefällt , und wahrscheinlich wird nicht funktionieren - und so könnte dies kein Problem für ein Produktionssystem sein. Es ist jedoch (theoretisch) möglich, dass das System niemals gemountet wurde (obwohl dies möglicherweise verhindert, dass es sich in einem normalen Zustand befindet), dass es definitiv nicht gemountet werden kann (ich habe es getestet 1)/proc/PIDkill 0/proc/procpstoplsof), und ich glaube, dass es keine Garantie dafür gibt, dass es existieren wird (dh, es wird von POSIX nicht benötigt). Und wenn das System nicht komplett abgespritzt ist, killfunktioniert es.
  • In Stephens Kommentar geht es um das Thema „Auf das Dateisystem zugreifen“ und „native Systemaufrufe verwenden“. Ich glaube, dass dies größtenteils ein roter Hering ist.
    • Ja, jeder Zugriffsversuch /proc erfordert das Lesen des Stammverzeichnisses, um das /procDateisystem zu finden . Dies gilt für jeden Versuch den Zugriff auf alle von einer absoluten Pfaddatei, einschließlich solcher Dinge in /bin, /etcund /dev. Dies geschieht so oft, dass das Stammverzeichnis sicher für die gesamte Lebensdauer (Betriebszeit) des Systems im Arbeitsspeicher zwischengespeichert wird. Daher kann dieser Schritt ohne Datenträger-E / A ausgeführt werden. Und sobald Sie die Inode von haben /proc, ist alles andere, was passiert, in Erinnerung.
    • Wie greifen Sie zu /proc? Mit stat, open, readdir, usw., die native System wie jedes Bit so viel fordert kill.
  • Die Frage spricht von einem laufenden Prozess. Dies ist eine glatte Phrase. Wenn Sie tatsächlich testen wollen , ob der Prozess ausgeführt wird (dh in der Task - Liste, vielleicht den aktuellen Prozess auf einigen CPU, nicht schlafen, warten oder gestoppt), müssen Sie möglicherweise eine tun und lesen Sie die Ausgabe oder Blick auf . Aber ich sehe keinen Hinweis in Ihrer Frage oder Ihren Kommentaren, dass Sie sich damit befassen.ps PID /proc/PID/stat

    Der Elefant im Raum ist jedoch, dass es schwierig sein kann , einen Zombie- 2- Prozess von einem lebendigen und gesunden Prozess zu unterscheiden.  kill 0arbeitet an einem Zombie und existiert. Sie können Zombies mit den Techniken identifizieren, die im vorherigen Absatz aufgeführt sind ( die Ausgabe ausführen und lesen oder anschauen ). Meine sehr schnell & casual (dh nicht sehr gründlich) Tests legen nahe , dass Sie dies auch durch ein Tun tun können , oder auf , oder - diese auf Zombies scheitern. (Sie schlagen jedoch auch bei Prozessen fehl, die Sie nicht besitzen.)/proc/PIDps PID/proc/PID/statreadlinklstat/proc/PID/cwd/proc/PID/root/proc/PID/exe

____________
1  Wenn die Option -f( f orce) nicht funktioniert, versuchen Sie es mit -l( l azy).
2  dh ein Prozess, der beendet / gestorben / beendet wurde, dessen Eltern noch nicht a wait.

G-Man sagt, "Monica wiedereinsetzen"
quelle
Vielen Dank für Ihren Kommentar zu meiner Antwort, die ich gelöscht habe, weil sie falsch war. Ich glaube nicht, dass die kill(2)Manpage direkt das Verhalten anzeigt, auf das Sie hingewiesen haben, aber die perlfuncManpage tut es. Ich werde Michael Kerrisk eine E-Mail senden, um zu erfahren, was er zu der Manpage des Systems zu sagen hat.
jrw32982 unterstützt Monica
Ich habe einen Fehlerbericht eingereicht, um die Manpage kill(2)bezüglich der Berechtigungen zum "Senden" von Signal 0 zu
klären
@ jrw32982: Nun, die Manpage sagt Dinge wie: "Das Sig- Argument ... kann 0 sein, in diesem Fall wird eine Fehlerprüfung durchgeführt ..." und " FEHLER - Der Systemaufruf kill () schlägt fehl und es wird kein Signal gesendet, wenn: … Der sendende Prozess ist nicht der Superuser und seine effektive Benutzer-ID stimmt nicht mit der effektiven Benutzer-ID des empfangenden Prozesses überein. … “Nun, da Sie es erwähnen, kann das wohl auf mehr als eine Weise interpretiert werden, aber leider sind viele Unix-Manpages in diesem Stil geschrieben, so dass Sie zwischen den Zeilen lesen müssen. Michael kann glauben, dass es klar genug ist, wie es ist.
G-Man sagt, dass Monica
Michael hat die kill(2)Manpage geändert (ich sehe sie noch nicht online): "Wenn sig 0 ist, wird kein Signal gesendet, aber es werden noch Existenz- und Berechtigungsprüfungen durchgeführt. Dies kann verwendet werden, um die Existenz von a zu überprüfen Prozess-ID oder Prozessgruppen-ID, die der Anrufer signalisieren darf. "
jrw32982 unterstützt Monica