Um zu testen, ob sich ein Dateideskriptor auf eine reguläre Datei bezieht, die in keinem Verzeichnis des Dateisystems einen verbleibenden Link hat, könnten Sie einen fstat()
erstellen System rufen Sie darauf auf und überprüfen Sie die Anzahl der Links (st_nlink
Feld) in der zurückgegebenen Struktur.
Mit zsh
, könnten Sie es mit seinem stat
tun eingebaut:
zmodload zsh/stat
fd=3
if
stat -s -H st -f $fd && # can be fstat'ed (is an opened fd)
[[ $st[mode] = -* ]] && # is a regular file
((st[nlink] == 0)) # has no link on the filesystem
then
print fd $fd is open on a regular file that has no link in the filessystem
fi
bash
(die GNU-Shell) hat kein Äquivalent, aber wenn Sie sich auf einem GNU-System befinden, haben Sie möglicherweise GNU stat
In diesem Fall sollten Sie in der Lage sein, Folgendes zu tun:
fd=3
if [ "$(LC_ALL=C stat -c %F:%h - <&"$fd")" = 'regular file:0' ]; then
printf '%s\n' "fd $fd is open on a regular file that has no link in the filessystem"
fi
Wenn Ihr Betriebssystem-Kernel Linux ist, ist ein portablerer Ansatz (für die Betriebssysteme, die nicht über zsh
und wo die Kerndienstprogramme nicht von GNU stammen), vorausgesetzt, das proc-Dateisystem ist auf /proc
gemountet könnte sein, ls
zu verwenden auf /proc/self/fd/$fd
:
if
LC_ALL=C TZ=UTC0 ls -nLd /proc/self/fd/0 <&"$fd" |
LC_ALL=C awk -v ret=1 '
NF {if ($1 ~ /^-/ && $2 == 0) ret=0; exit}
END {exit(ret)}'
then
printf '%s\n' "fd $fd is open on a regular file that has no link in the filessystem"
fi
Hier wird fd wie in der vorherigen Lösung auf 0 dupliziert, sodass es auch dann funktioniert, wenn fd das close-on-exec-Flag hat (vorausgesetzt, fd ist von vornherein nicht 0, aber fd 0 hätte normalerweise kein close-on-exec Flagge).
Diese Art von Ansatz funktioniert nicht mit dem gefälschten Dateisystem, das die procfs von Linux sind, um zu prüfen, ob ein fd auf /proc/<some-pid>/cmdline
geöffnet ist bezieht sich auf einen Live-Prozess:
$ zsh -c 'zmodload zsh/stat; (sleep 1; stat -f0 +nlink; cat) < /proc/$$/cmdline &'
$ 1
cat: -: No such process
Siehe wie fstat().st_nlink
gab oben 1 zurück (was bedeuten würde, dass die Datei noch einen Link zu einem Verzeichnis hatte), während cat
ist read()
auf dem fd gab einen Fehler zurück. Das ist keine übliche Dateisystem-Semantik.
In jedem Fall können Sie überprüfen, ob Ihr Elternteil noch läuft, indem Sie getppid()
anrufen was 1 oder die PID des untergeordneten Subreapers zurückgeben würde, wenn der Elternteil starb. In zsh
, würden Sie $sysparams[ppid]
verwenden (im zsh/system
Modul).
$ sh -c 'zsh -c '\''zmodload zsh/system
print $PPID $sysparams[ppid]
sleep 2; print $PPID $sysparams[ppid]
'\'' & sleep 1'
14585 14585
$ 14585 1
In bash
, könnten Sie ps -o ppid= -p "$BASHPID"
verwenden stattdessen.
Ein anderer Ansatz wäre, eine Pipe zwischen Eltern und Kind zu erstellen und mit select
zu überprüfen /poll
(oder read -t0
in bash
), dass es noch läuft.
Könnte mit einem coproc
erfolgen (erst kürzlich zu bash
hinzugefügt ) statt &
.
background_with_pipe() {
coproc "[email protected]" {PARENT_FD}<&0 <&3 3<&- >&4 4>&-
} 3<&0 4>&1
parent_gone() {
local ignore
read -t0 -u "$PARENT_FD" ignore
}
background_with_pipe eval '
parent_gone || echo parent still there
sleep 2
parent_gone && echo parent gone
'
sleep 1
exit
Welche geben:
$ bash ./that-script
parent still there
$ parent gone
Bauen Sie auf Ihrem geplanten Ansatz auf und gehen Sie wieder von einem Linux-Kernel mit procfs
aus montiert auf /proc
, könnten Sie auch Folgendes tun:
exec {PARENT_CANARY}< /proc/self/cmdline; PARENT_PID=$BASHPID
parent_gone() {
! [[ /proc/$PARENT_PID/cmdline -ef /proc/self/fd/$PARENT_CANARY ]]
}
(
parent_gone || echo parent still there
sleep 2
parent_gone && echo parent gone
) &
sleep 1
Mit [[ file1 -ef file2 ]]
die prüfen, ob die Too-Dateien die gleiche Dev- und Inode-Nummer haben (st_dev
und st_ino
zurückgegeben von stat()
).
Das scheint mit 5.6.0 zu funktionieren, aber wie wir oben gesehen haben, /proc
die übliche Dateisystem-Semantik nicht beachtet, ich kann nicht garantieren, dass es rassenfrei ist (PID und Inode-Nummer könnten möglicherweise wiederverwendet worden sein) oder dass es in zukünftigen Linux-Versionen funktionieren würde.
Ihre Originaldatei existiert vollständig unverändert.
Sobald eine Datei namentlich geöffnet wurde, zählt der Dateideskriptor, den Ihr Prozess enthält, als Link zu der Datei. Das System gibt die Datei oder ihren Speicherplatz nicht frei, bis alle Verknüpfungen gelöscht wurden:Dies können beliebig viele Prozesse sein, die eine Dateibeschreibung dafür geöffnet haben, plus eine beliebige Anzahl fester Links.
Sie könnten die Datei zum Zeitpunkt des Öffnens und die aktuelle Datei nach Namen angeben. Wenn es sich um unterschiedliche Inodes oder ein unterschiedliches Änderungsdatum handelt, haben Sie eine gelöschte Datei und eine neue Datei. Oder Sie stellen fest, dass Sie eine gelöschte Datei haben, aber keine neue existiert.