Ausgabe eines laufenden Prozesses umleiten

Ich hatte ja neulich schon einmal das “/proc”-Filesystem erwähnt, und natürlich kann man in Linux damit noch andere Sachen machen - z.B. STDOUT oder STDERR eines laufenden Prozesses umleiten (ein bißchen Hilfe braucht man allerdings dabei schon).

Schauen wir uns mal ein Beispiel an: Der folgende Prozess schreibt STDERR in das Terminal, indem wir ihn gestartet haben, und STDOUT nach /tmp/foo:

nc -l 8080 > /tmp/foo &
[1] 4767

Hilfreicherweise zeigt mir die Shell auch gleich die Prozess-ID an, so daß es ein leichtes ist, herauszufinden, wohin STDOUT (FD 1) und STDERR (FD 2) zeigen:

ls -l /proc/4767/fd/[12]
l-wx------ 1 cite cite 64 Apr  4 19:53 /proc/4767/fd/1 -> /tmp/foo
lrwx------ 1 cite cite 64 Apr  4 19:53 /proc/4767/fd/2 -> /dev/pts/1

Es ist jetzt an der Zeit, den GNU Debugger zu bemühen. Wir “attachen” uns an die Prozess-ID 4767 und geben dem Debugger als “Hint” auch gleich noch mit, welches das Binary ist, das den Prozess erzeugt hat (wir kanonisieren diesen Namen hier noch, da nc unter Debian über eine Kette von Symlinks auf verschiedene Binaries zeigen kann):

gdb -p 4767 $(readlink -f $(which nc))
GNU gdb (GDB) 7.0.1-debian
[Copyright-Kram weggeschnitten]
Reading symbols from /bin/nc.openbsd...(no debugging symbols found)...done.
Attaching to program: /bin/nc.openbsd, process 4767
[Library-Kram weggeschnitten]
(gdb)

Unser Ziel ist es nun, STDOUT zuerst zu schließen - worfür wir close(2) benutzen - und danach mit neuem Ziel zu öffnen - wofür wir creat(2) nutzen werden. Das geht eigentlich relativ einfach:

(gdb) p close(1)
$1 = 0
(gdb) p creat("/tmp/bar", 0644)
$2 = 1
(gdb) quit
A debugging session is active.

  Inferior 1 [process 4767] will be detached.

  Quit anyway? (y or n) y
  Detaching from program: /bin/nc.openbsd, process 4767

Mit der “p”-Funktion lassen wir uns den Rückgabewert von close auf den FD 1 - also STDOUT - anzeigen. Hier wird eine 0 zurück geliefert, es hat also alles funktioniert. Danach verwenden wir den gleichen Mechanismus, um die Datei /tmp/bar zu erzeugen, mit den Rechten 0644. Und tatsächlich:

ls -l /proc/4767/fd/[12]
l-wx------ 1 cite cite 64 Apr  4 19:53 /proc/4767/fd/1 -> /tmp/bar
lrwx------ 1 cite cite 64 Apr  4 19:53 /proc/4767/fd/2 -> /dev/pts/1

Wenn wir schonmal im Debugger sind hätten wir übrigens noch Dutzend andere Sachen machen können - aus aktuellem Anlass sei hier mal gezeigt wie man herausfindet, welche umask ein laufender Prozess hat:

(gdb) p umask(0)
$1 = 18
(gdb) p umask(18)
$2 = 0

Der erste Aufruf von umask gibt uns als Ergebnis den Wert an, der bis zu diesem Aufruf aktuell war. In diesem Fall war das eine 18. Nach Oktal umgewandelt ergibt das 0022. Mit dem zweiten umask-Aufruf setzen wir übrigens wieder den alten Wert - das sollte man nicht vergessen.

In diesem Sinne!