SYNOPSIS
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct flock *lock);
DESCRIPTION
fcntl führt eine von vielen unterschiedlichen Operationen auf dem File-Deskriptor fd aus. Die jeweilige Operation wird durch den Parameter cmd angegeben.Schließen beim Ausführen (close-on-exec)
- F_DUPFD
-
Sucht den verfügbaren File-Deskriptor mit der niedrigsten Nummer
größer oder gleich
arg
und legt in
fd
eine Kopie davon an. Im Gegensatz dazu verwendet
dup2(2)
exakt den angegebenen Deskriptor.
Die alten und neuen Deskriptoren können ausgetauscht werden. Sie verwenden beide die gleichen Locks, Positionszeiger und Flags. Wenn beispielsweise die Dateiposition des einen Deskriptors mit lseek geändert wird, dann ist sie gleichzeitig auch beim anderen Deskriptor geändert.
Die beiden Deskriptoren teilen sich jedoch nicht das close-on-exec-Flag. In der Kopie ist das Flag abgeschaltet, so dass der neue Deskriptor beim Ausführen nicht geschlossen wird.
Bei Erfolg wird der neue Deskriptor zurückgegeben.
- F_GETFD
- Liest das close-on-exec-Flag. Ist das FD_CLOEXEC-Bit 0, so bleibt die Datei bei einem exec geöffnet, ansonsten wird sie geschlossen.
- F_SETFD
- Setzt das close-on-exec-Flag auf den Wert, des FD_CLOEXEC-Bits in arg.
Die Statusflags einer Datei
Jedem File-Deskriptor sind verschiedene Flags zugeordnet, die beim Aufruf von open(2) initialisiert und später durch fcntl(2) verändert werden können. Kopien eines File-Deskriptors, die mit dup2(2) oder fork(2), etc. erzeugt wurden, besitzen identische Flags.Die einzelnen Flags und ihre Bedeutung sind in open(2) beschrieben.
- F_GETFL
- Liest die Flags des Deskriptors.
- F_SETFL
- Setzt die Flags des Deskriptors, die sich auf den Dateistatus beziehen, auf die in arg angegebenen Werte. Die weiteren Bits für Zugriffsmodus und Dateierzeugung werden ignoriert. Unter Linux lassen sich auf diese Weise nur die Flags O_APPEND, O_NONBLOCK, O_ASYNC und O_DIRECT verändern.
Empfehlendes (advisory) Locking
- Man benutzt
-
F_GETLK, F_SETLK und F_SETLKW,
um Locks für bestimmte Segmente in einer Datei anzufordern, aufzugeben oder
zu testen. Das dritte Argument
lock
verweist auf eine Struktur, die zumindest die folgenden Einträge enthält
(die Reihenfolge ist nicht festgelegt):
struct flock { ... short l_type; /* Typ des Locks: F_RDLCK, F_WRLCK, F_UNLCK */ short l_whence; /* Wie ist l_start zu verstehen: SEEK_SET, SEEK_CUR, SEEK_END */ off_t l_start; /* Startposition des Locks */ off_t l_len; /* Lock für l_len Bytes anfordern */ pid_t l_pid; /* PID des Prozesses, der das Lock blockiert (nur F_GETLK) */ ... };
Die Einträge l_whence, l_start, und l_len bestimmen den Bereich, für den das Lock angefordert werden soll. l_start gibt den Anfang des Bereichs an, und zwar relativ zum Anfang der Datei (falls l_whence auf SEEK_SET gesetzt ist), relativ zur aktuellen Position in der Datei (falls l_whence auf SEEK_CUR gesetzt ist), bzw. relativ zum Dateiende (falls l_whence auf SEEK_END gesetzt ist). In den beiden zuletzt genannten Fällen kann l_start auch negativ sein, sofern es dadurch nicht über den Beginn der Datei hinaus verweist. Das Lock wird für die in l_len angegebene Anzahl von Bytes angefordert. Sie darf nicht negativ sein. (Man beachte jedoch auch die ANMERKUNGEN unten.) Der Bereich darf über das Dateiende hinausweisen, nicht aber vor den Dateianfang. Der Wert 0 hat eine spezielle Bedeutung: So fordert man ein Lock an, das an der durch l_whence und l_start bestimmten Position beginnt und bis zum Dateiende reicht, gleichgültig auf welche Größe die Datei noch anwächst.
Der Eintrag l_type wird benutzt, um entweder ein Lock für lesenden (F_RDLCK) oder schreibenden (F_WDLCK) Zugriff auf die Datei anzufordern. Beliebig viele Prozesse dürfen ein Lock zum Lesen besitzen (geteiltes Lock), aber nur ein Prozess gleichzeitig darf ein Lock zum Schreiben erhalten (ausschließendes Lock). Ein ausschließendes Lock schließt sämtliche anderen Locks aus, also sowohl lesende, als auch andere schreibende. Ein einzelner Prozess darf für ein bestimmtes Dateisegment nur einen einzigen Typ von Lock besitzen; wird ein neues Lock für einen Bereich angefordert, für den bereits ein anderes Lock existiert, so wird das bestehende Lock auf den Typ des neuen Locks umgestellt. (Stimmen die Bereiche der beiden Locks nicht exakt überein, können sie dadurch aufgeteilt, verkleinert oder mit anderen Locks vereinigt werden.)
- F_SETLK
- Fordert ein Lock an, falls l_type auf F_RDLCKoderF_WRLCK gesetzt ist. Gibt ein Lock auf, falls l_type auf F_UNLCK gesetzt ist. Der angeforderte Bereich wird durch die Einträge l_whence, l_start und l_len in lock angegeben. Falls ein anderer Prozess ein konkurrierendes Lock hält, gibt dieser Aufruf -1 zurück und setzt errno auf EACCESS oder EAGAIN.
- F_SETLKW
- Unterscheidet sich nur dann von F_SETLK, wenn ein anderer Prozess ein konkurrierendes Lock hält. In diesem Fall wartet F_SETLKW auf die Freigabe. Der Aufruf kann durch ein Signal unterbrochen werden. Dann wird zunächst der Signalhandler abgearbeitet. Direkt im Anschluss wird fcntl() mit Rückgabewert -1 beendet und errno auf EINTR gesetzt.
- F_GETLK
- Beim Aufruf beschreibt lock ein zu testendes Lock auf eine Datei. Könnte es erfolgreich gesetzt werden, so setzt fcntl() den Eintrag l_type in lock auf F_UNLCK und lässt die übrigen Felder unverändert. Sind bereits ein oder mehrere konkurrierende Locks gesetzt, werden die Felder l_type, l_whence, l_start und l_len in lock mit Informationen über eines der Locks gefüllt. Die PID des zugehörigen Prozesses wird in l_pid zurückgegeben.
Um ein Lock für Lesezugriff anzufordern, muss der Deskriptor zum Lesen geöffnet sein. Ein Lock für Schreibzugriff erfordert, dass der Deskriptor zum Schreiben geöffnet ist. Ist der Deskriptor zum Lesen und Schreiben geöffnet, können beliebige Locks angefordert werden.
Zusätzlich zum expliziten F_UNLCK werden die Locks auch dann aufgegeben, wenn der Prozess endet oder wenn er einen beliebigen Deskriptor der Datei schließt, auf die die Locks verweisen. Das ist schlecht: Es bedeutet, dass ein Prozess beispielsweise seine Locks auf /etc/passwd oder /etc/mtab verlieren kann, wenn eine Bibliotheksfunktion aus irgendeinem Grund die Datei öffnen und schließen muss.
Die Locks werden nicht über fork(2), wohl aber über execve(2) hinweg weitergereicht. Aufgrund der gepufferten Ein-/Ausgabe in der stdio(3)-Bibliothek sollten ihre Funktionen nicht zusammen mit Locks verwendet werden. Statt dessen sind read(2) und write(2) zu benutzen.
Verpflichtende (mandatory) Locks
(Nicht im POSIX-Standard spezifiziert.) Die oben beschriebenen Locks können sowohl empfehlend oder verpflichtend verwendet werden. Ohne zusätzliche Schritte sind sie empfehlend. Um verpflichtende Locks verwenden zu können, müssen sie für ein Dateisystem mit der Option "-o mand" beim Aufruf von mount(8) zugelassen und zusätzlich für jede Datei aktiviert werden (indem in den Zugriffsrechten für die Gruppe das Ausführungsbit gelöscht und das Set-GID-Bit gesetzt wird).Empfehlende Locks werden nicht erzwungen, sondern sind nur nützlich zwischen kooperierenden Prozessen. Verpflichtende Locks werden für sämtliche Prozesse erzwungen.
Signalkontrolle
F_GETOWN, F_SETOWN, F_GETSIG und F_SETSIG werden benutzt, um Signale zu kontrollieren, die die Verfügbarkeit von Ein- und Ausgaben anzeigen:- F_GETOWN
- Gibt die PID (oder Prozessgruppen-ID) eines Prozesses zurück der im Augenblick ein SIGIO- oder SIGURG-Signal für ein Ereignis auf dem Deskriptor fd erhält. Prozessgruppen werden als negative Werte zurückgegeben.
- F_SETOWN
-
Setzt die PID (oder Prozessgruppen-ID) für einen Prozess, der
bei Ereignissen auf dem Deskriptor
fd
ein SIGIO- oder SIGURG-Signal übermittelt bekommen soll.
Prozessgruppen werden als negative Werte angegeben.
(Mit Hilfe von
F_SETSIG
kann auch ein anderes Signal als SIGIO angefordert werden.)
Das SIGIO-Signal wird ausgesandt, falls über den Dateideskriptor neue Eingabedaten gelesen oder weitere Ausgabedaten geschrieben werden können. Als Voraussetzung dafür muss weiterhin das Statusflag O_ASYNC für den Deskriptor gesetzt sein (entweder als Flag beim Aufruf von open(2) oder später über das Kommando F_SETFL von fcntl).
Welcher Prozess oder welche Prozessgruppe das Signal erhält, wird mit Hilfe des Kommandos F_SETOWN von fcntl gesteuert. Handelt es sich bei dem Deskriptor um einen Socket, legt der Aufruf gleichzeitig auch den Empfänger von SIGURG-Signalen fest. Derartige Signale werden ausgesandt, wenn ein Paket außerhalb der normalen Reihenfolge eintrifft. (SIGURG wird immer dann ausgesandt, wenn select(2) anzeigen würde, dass sich der Socket in einem "außergewöhnlichen Zustand" befindet.) Bezeichnet der Deskriptor ein Dateneingabegerät, wird das SIGIO-Signal an die zugehörige Vordergrundprozessgruppe geschickt. geschickt.
- F_GETSIG
- Gibt die Nummer des Signals zurück, das verwendet wird, um Ein- und Ausgabeereignisse anzuzeigen. Ein Wert von null bedeutet, dass SIGIO benutzt wird. Jeder andere Wert (einschließlich SIGIO) entspricht der verwendeten Signalnummer. In diesem Fall können weitere Informationen über die Signalverarbeitungsroutine abgerufen werden, sofern sie mit SA_SIGINFO installiert wurde.
- F_SETSIG
-
Setzt die Nummer des Signals, das verwendet wird, um Ein- und
Ausgabeereignisse anzuzeigen. Ein Wert von null bedeutet, dass
SIGIO benutzt wird. Jeder andere Wert (einschließlich SIGIO) bezeichnet
die verwendende Signalnummer. In diesem Fall können weitere Informationen
über die Signalverarbeitungsroutine abgerufen werden, sofern sie mit
SA_SIGINFO installiert wurde.
Durch Kombination von F_SETSIG mit von Null verschiedenen Werten und SA_SIGINFO für die Signalverarbeitungsroutine (siehe sigaction(2)), erhält die Routine in der Struktur siginfo_t Zusatzinformationen über das Ein-/Ausgabeereignis. Zeigt das Feld si_code an, dass die Quelle SI_SIGIO ist, enthält Feld si_fd den zugehörigen Dateideskriptor. Andernfalls stehen keine weiteren Informationen zur Verfügung, an welchem Deskriptor Ein-/Ausgaben anliegen, und man sollte auf die gewöhnlichen Mechanismen (select(2), poll(2), read(2) in Verbindung mit O_NONBLOCK, etc.) zurückgreifen, um sie zu ermitteln.
Wird ein POSIX.1b-Echtzeitsignal (Signalnummer >= SIGRTMIN) ausgewählt, können mehrere Ein-/Ausgabeereignisse unter derselben Signalnummer aufgereiht werden. (Das Aufreihen hängt ab vom verfügbaren Speicher.) Wie oben stehen auch hier weitere Informationen bereit, falls SA_SIGINFO für die Signalverarbeitungsroutine gesetzt ist.
Mit Hilfe dieser Mechanismen ist es möglich, voll asynchrone Ein-/Ausgabe zu implementieren, ohne signifikant auf select(2) oder poll(2) zurückzugreifen.
Die Verwendung von O_ASYNC, F_GETOWN, F_SETOWN ist spezifisch für BSD und Linux. F_GETSIG und F_SETSIG sind Linux-spezifisch. Ähnliches lässt sich im Rahmen des POSIX-Standards durch asynchrone Ein-/Ausgabe und die Struktur aio_sigevent erreichen; sie sind auch unter Linux als Teil der GNU-C-Bibliothek (glibc) verfügbar.
Leases
F_SETLEASE und F_GETLEASE (seit Linux 2.4) werden benutzt, um die aktuellen Einstellungen eines Leases zu setzen beziehungsweise abzufragen, das der aufrufende Prozess auf die durch den Deskriptor fd beschriebene Datei besitzt. Mittels eines Dateileases kann sich ein Prozess (der Lease-Inhaber) durch ein Signal benachrichtigen lassen, falls ein anderer Prozess (der Mitbewerber) versucht, mit open(2) oder truncate(2) auf die Datei zuzugreifen.- F_SETLEASE
-
Setzt oder entfernt ein Dateilease, abhängig vom Wert in
arg:
-
- F_RDLCK
- Erwirbt ein lesendes Lease. Der Prozess erhält dann Nachricht, sobald ein anderer Prozess die Datei für Schreibzugriff öffnet oder sie verkürzen will.
- F_WRLCK
- Erwirbt ein schreibendes Lease. Der Prozess erhält Nachricht, sobald ein anderer Prozess die Datei öffnet (für Schreib- oder Lesezugriff) oder sie verkürzen will. Ein schreibendes Lease kann nur erworben werden, kein anderer Prozess die Datei augenblicklich geöffnet hat.
- F_UNLCK
- Entfernt das Lease von der Datei.
-
Ein Prozess kann nur einen Typ von Lease auf eine bestimmte Datei besitzen.
Leases können nur für gewöhnliche Dateien erworben werden. Ein Prozess ohne Sonderprivilegien darf nur Leases auf Dateien erwerben, deren Dateisystem-UID der UID des Prozesses entspricht.
- F_GETLEASE
- Zeigt den Typ des Leases an für die durch den Deskriptor fd beschriebene Datei. Der Rückgabewert ist F_RDLCK, F_WRLCK oder F_UNLCK, je nachdem, ob der Prozess ein lesendes, schreibendes oder kein Lease auf die Datei besitzt. (Das dritte Argument zu fcntl() wird ausgelassen.)
Wenn der Mitbewerber einen open()- oder truncate()-Aufruf ausführt, der mit dem über F_SETLEASE erworbenen Lease in Konflikt steht, wird der Systemaufruf durch den Kernel angehalten. (Ausgenommen, der hat beim Öffnen der Datei mit open() das Flag O_NONBLOCK angegeben. In diesem Fall kehrt der Aufruf sofort mit dem Fehler EWOULDBLOCK zurück.) Der Kernel benachrichtigt den Lease-Inhaber durch ein Signal (für gewöhnlich SIGIO). Der Lease-Inhaber sollte daraufhin alle nötigen Aufräumarbeiten veranlassen (beispielsweise zwischengespeicherte Daten schreiben), um die Datei auf den Zugriff durch einen anderen Prozess vorzubereiten und anschließend sein Lease entfernen, indem er das Kommando F_SETLEASE mit F_UNLCK in arg ausführt.
Versäumt es der Inhaber, das Lease innerhalb der in /proc/sys/fs/lease-break-time genannten Anzahl von Sekunden zu entfernen, dann bricht der Kernel gewaltsam das Lease. Das gilt nicht, falls der Systemaufruf des Mitbewerbers bereits zuvor abgebrochen worden ist, das heißt, wenn der Mitbewerber die Datei mit O_NONBLOCK geöffnet hatte oder in der Zwischenzeit ein Signal empfangen hat.
Sobald das Lease freiwillig oder gewaltsam entfernt wurde und falls der Systemaufruf des Mitbewerbers nach wie vor blockiert ist, gibt der Kernel den Aufruf nun wieder frei.
SIGIO ist das Standardsignal, mit dem der Lease-Inhaber benachrichtigt wird. Es kann jedoch mit Hilfe des Kommandos F_SETSIG für fcntl() verändert werden. Wird ein F_SETSIG-Kommando ausgeführt (selbst eines, das SIGIO angibt) und wurde die Signalverarbeitungsroutine mit SA_SIGINFO angelegt, dann erhält die Routine als zweites Argument die Struktur siginfo_t übergeben. Deren Eintrag si_fd enthält den Deskriptor auf die geleaste Datei, auf die ein anderer Prozess zugreifen will. (Das ist dann sinnvoll, wenn der Prozess Leases auf mehrere Dateien besitzt.)
Benachrichtigungen über Veränderungen an Dateien und Verzeichnissen
- F_NOTIFY
-
(seit Linux 2.4)
Erteilt eine Nachricht, sobald ein durch Deskriptor
fd
beschriebenes Verzeichnis oder eine der enthaltenen Dateien verändert wird.
Die mitzuteilenden Ereignisse sind in
arg
zu bestimmen, und zwar als Bitmaske, gebildet aus bitweisem Oder von keinem
oder beliebig vielen der folgenden Bits:
Bit Beschreibung (Ereignis im Verzeichnis) DN_ACCESS pread, readv) DN_MODIFY Eine Datei wurde verändert (write, pwrite, writev, truncate, ftruncate) DN_CREATE Eine Datei wurde erstellt (open, creat, mknod, mkdir, link, symlink, rename) DN_DELETE Eine Datei wurde entfernt (unlink, Umbenennen in ein anderes Verzeichnis, rmdir) DN_RENAME Eine Datei in diesem Verzeichnis wurde umbenannt (rename) DN_ATTRIB Die Attribute eine Datei wurden verändert (chown, chmod, utime[s]) (Um diese Definitionen zu erhalten, muss vor Einbinden von <fcntl.h> das Makro _GNU_SOURCE definiert sein.)
Normalerweise handelt es sich um "Einweg"-Benachrichtigungen, so dass die Anwendung sich für jede weitere Mitteilung stets neu registrieren muss. Alternativ dazu kann DN_MULTISHOT angegeben werden, und die Benachrichtigungen werden solange gesendet, bis sie explizit abbestellt werden.
Eine Serie von F_NOTIFY-Anforderungen ist kumulativ, die Ereignisse in arg werden zu den bereits angeforderten hinzugefügt. Um Benachrichtigungen über sämtliche Ereignisse abzubestellen, ist F_NOTIFY mit 0 als arg auszuführen.
Benachrichtigt wird duch Übermittlung eines Signals. Das Standardsignal ist SIGIO, es kann jedoch durch das F_SETSIG-Kommando zu fcntl() geändert werden. In diesem Fall erhält die Signalverarbeitungsroutine als zweites Argument die Struktur siginfo_t übergeben (sofern die Routine mit SA_SIGINFO angelegt wurde). Deren Eintrag si_fd enthält den Dateideskriptor, der die Benachrichtigung ausgelöst hat (nützlich, falls mehrere Verzeichnisse überwacht werden).
Speziell in Verbindung mit DN_MULTISHOT sollten POSIX.1b-Echtzeitsignale für die Benachrichtigung verwendet werden, so dass mehrere Nachrichten aufgereiht werden können.
RÜCKGABEWERTE
Für einen erfolgreichen Aufruf hängt der Rückgabewert von der ausgeführten Operation ab:- F_DUPFD
- Der neue File-Deskriptor.
- F_GETFD
- Der Inhalt des Flags.
- F_GETFL
- Der Inhalt der Flags.
- F_GETOWN
- Der Besitzer des Deskriptors.
- F_GETSIG
- Wert des Signals zur Anzeige möglicher Ein-/Ausgabe oder null für gewöhnliches SIGIO-Verhalten.
- Alle anderen Kommandos
- Null.
Bei einem Fehler wird -1 zurückgegeben und errno entsprechend gesetzt.
FEHLER
- EACCES or EAGAIN
- Aktion ist aufgrund von Locks anderer Prozesse nicht möglich oder weil ein anderer Prozess die Datei in seinen Speicher gespiegelt hat.
- EBADF
- fd ist kein geöffneter Dateideskriptor oder der Zugriffsmodus stimmt nicht mit dem Typ des angeforderten Locks überein (für F_SETLK und F_SETLKW).
- EDEADLK
- Es wurde erkannt, dass das angeforderte F_SETLKW-Kommando zu einem Deadlock führen würde.
- EFAULT
- lock verweist außerhalb des verfügbaren Adressraums.
- EINTR
- Kommando wurde durch ein Signal unterbrochen (für F_SETLKW). Oder Kommando wurde durch ein Signal unterbrochen, bevor das Lock überprüft und erworben werden konnte (für F_GETLK Und F_SETLK). Tritt vor allem auf, wenn ein Lock auf entfernte Dateien (etwa über NFS) angefordert wird, ist jedoch auch auf lokalen Dateisystemen möglich.
- EINVAL
- arg ist negativ oder größer als der maximal erlaubte Wert (für F_DUPFD) oder arg ist keine erlaubte Signalnummer (für F_SETSIG).
- EMFILE
- Der Prozeß hat bereits das Maximum an Dateideskriptoren geöffnet (für F_DUPFD).
- ENOLCK
- Der Prozeß hat zu viele Locks auf gemeinsame Speichersegmente geöffnet, die Locktabelle ist voll oder es trat ein Fehler auf bei dem Versuch, ein Lock von einem anderen Rechner zu erhalten (etwa über NFS).
- EPERM
- Es wurde versucht, für eine Datei das Flag O_APPEND zu löschen, deren Zugriffsattribute nur das Anfügen von Daten erlauben.
BEMERKUNGEN
Die Fehler, die von dup2(2) zurückgegeben werden, sind anders als die von F_DUPFD.Seit Kernelversion 2.0 werden die durch flock(2) und fcntl(2) gesetzten Locks nicht mehr gegeneinander abgeglichen.
POSIX 1003.1-2001 erlaubt negative Längenangaben in l_len. In diesem Fall umfaßt das Lock den Bereich von l_start+l_len bis einschließlich l_start-1. Unter Linux wird das seit den Versionen 2.4.21 beziehungsweise 2.5.49 unterstützt.
Verschiedene Systeme definieren in struct flock weitere Felder wie zum Beispiel l_sysid. Denn offensichtlich ist l_pid nicht übermäßig sinnvoll, falls der Prozeß, der ein Lock hält, auf einer anderen Maschine laufen kann.
ABGESTIMMT MIT
SVr4, SVID, POSIX, X/OPEN, BSD 4.3. In POSIX.1 sind lediglich die Operationen F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_SETFL, F_GETLK, F_SETLK und F_SETLKW spezifiziert. F_GETOWN und F_SETOWN stammen aus der BSD-Welt und werden in SVr4 nicht unterstützt; F_GETSIG und F_SETSIG sind Linux-spezifisch. Auch F_NOTIFY, F_GETLEASE und F_SETLEASE gibt es nur unter Linux. Um ihre Definitionen zu erhalten, muß zusätzlich noch das Makro _GNU_SOURCE definiert werden, bevor <fcntl.h> eingebunden wird. Die gültigen Flags F_GETFL und F_SETFL entsprechen den von open(2) unterstützten und unterscheiden sich zwischen verschiedenen Systemen; O_APPEND, O_NONBLOCK, O_RDONLY und O_RDWR sind in POSIX.1 festgelegt. SVr4 unterstützt verschiedene weitere Optionen und Flags, die hier nicht aufgeführt sind.Unter SVr4 sind EIO, ENOLINK und EOVERFLOW als zusätzliche mögliche Fehler dokumentiert.