inotify
demo
main program
(**
\brief Sample program showing inotify events.
\version @0x5A4EEB4C
\author Kai Burghardt <wiz at KaiBurghardt.de>
\date 2018
\copyright All rights reserved.
This program prints a readable representation of caught inotify events.
It is non-interactive and does only watch a directory/file specified
at compile-time.
*)
program inotifytst(input, output, stderr);
{$mode objfpc}
{$modeswitch classicprocvars on}
{$typedAddress on}
uses
baseunix, linux, gettext, sysutils;
const
(**
\brief directory/file to be monitored by inotify
\note Not yet at run-time existing files are not treat specially.
This program does not test whether watchedPath is a valid path.
However, inotify does not add watches to non-existing paths.
So inotify_add_watch may raise an error.
*)
watchedPath = '/tmp/abc';
/// \brief holds size of largest expected inotify_event size
maxExpEventSize = sizeof(inotify_event) + name_max;
// resource strings {}
var
/// \brief inotify file descriptor
infd: cint;
/// \brief inotify watch descriptor
inwd: cint;
/// \brief buffer for reading inotify events
inEventQueueBuffer: PChar;
bytesReadCount, bytesProcessedCount: TsSize;
/// \brief a pointer to handle a single inotify_event
inEvent: PInotify_event;
/// \brief pointer to a signal action record
newAction: PSigActionRec;
(**
\brief Closes inotify file descriptor.
closeInFd closes the inotify file descriptor by invoking fpClose.
It prints a warning on stderr if it went wrong but does not abort.
*)
procedure closeInFD;
begin
// when all fds referring to an inotify-instance have been closed,
// the underlying object and its resources are automatically freed
if fpClose(infd) <> 0 then
begin
writeln(stderr, warning + closeInotifyFDfailed);
end;
end;
(**
\brief Removes inotify watch
cleanUpInWdNFd removes the only installed inotify watch
from (the only) inotify watch descriptor.
*)
procedure cleanUpInWD;
begin
if inotify_rm_watch(infd, inwd) <> 0 then
begin
writeln(stderr, warning + disassocInwdFrInfdFailed);
end;
end;
(**
\brief frees reserved memory
cleanUpEverything frees allocated memory which is reserved for
operations in the main loop.
\sa sigHandler
*)
procedure cleanUpMemory;
begin
freeMem(inEventQueueBuffer, maxExpEventSize);
end;
(**
\brief procedure-wrapper for intended termination by signals
sigHandler calls cleanUpEverything.
It writes a final newline and halts program execution.
*)
procedure sigHandler(
signal: longInt;
info: PSigInfo;
context: PSigContext
); noreturn;
begin
writeln;
halt(0);
end;
(* *)
(* M A I N *)
(* *)
begin
//translateResourcestrings('/usr/share/locale/%s/LC_MESSAGES/' +
// applicationName() + '.mo');
translateResourcestrings(applicationName() + '.%s.mo');
// function inotify_init() initializes a new inotify instance and
// returns a file descriptor associated with its inotify event queue
infd := inotify_init();
if infd < 0 then
begin
writeln(stderr, error + initializingInotifyFDfailed);
// optional: further error analysis with fpgeterrno()
halt(1);
end;
addExitProc(closeInFD);
// next step: adding a watch to a previously initialized inotify instance
inwd := inotify_add_watch(infd, watchedPath, in_all_events);
if inwd < 0 then
begin
writeln(stderr, error +
format(addingWatchedPathToInotifyWatchListFailed, [watchedPath]));
// optional: retrieve errno with fpgeterrno()
halt(2);
end;
addExitProc(cleanUpInWD);
// avoid a run-time error on getMem-failure
returnNilIfGrowHeapFails := true;
// let's occupy some more more heap!
inEventQueueBuffer := getMem(maxExpEventSize);
// check on nil-pointer (failure)
if not assigned(inEventQueueBuffer) then
begin
writeln(stderr, error + couldNotAllocateMemForInotifyEvents);
halt(3);
end;
addExitProc(cleanUpMemory);
// install a signal handler for several signals
new(newAction);
if not assigned(newAction) then
begin
writeln(stderr, error + preparingOfSignalHandlerInstallFailed);
halt(4);
end;
// preparing signal action record
// save address of sigHandler procedure
newAction^.sa_handler := sigActionHandler(@sigHandler);
fillchar(newAction^.sa_mask, sizeof(newAction^.sa_mask), #0);
newAction^.sa_flags := 0;
// pass sigActionRec to sigaction(2) syscall
if fpSigAction(SigHup or SigInt or SigQuit or SigAbrt or SigTerm or
SigTStp, newAction, nil) <> 0 then
begin
writeln(stderr, error + couldNotInstallSignalHandlerForSigint);
halt(5);
end;
// get rid of unused newAction
dispose(newAction);
// TODO: find something better than
// a while-true-loop and signal handling
while true do
begin
// read() returns the amount of bytes have been read.
// read() reads at most maxExpEventSize bytes to the memory position
// specified by inEventQueueBuffer.
// It's only possible to read whole inotify events,
// but no fractions even though
// the _beginning_ of the next event may fit into remaining space.
bytesReadCount := fpRead(infd, inEventQueueBuffer, maxExpEventSize);
if bytesReadCount < 0 then
begin
writeln(stderr, error + readingFromInotifyFDfailed);
halt(6);
end;
// as there may be multiple inotify_events saved at inEventQueueBuffer
// we have to keep a counter how much has been processed
bytesProcessedCount := 0;
// reset inEvent
// typecast PChar to use it as a PInotify_event as such allows the
// usage of dot-fieldname-designators
inEvent := PInotify_event(inEventQueueBuffer);
while bytesProcessedCount < bytesReadCount do
begin
// print a readable representation of current inotify_event
writeln('inotify_event:');
with inEvent^ do
begin
writeln(' wd: ', wd);
writeln(' mask: %', binStr(mask, 32));
// several tests on the mask {}
writeln(' cookie: $', hexStr(cookie, 8));
// note: len does not contain the actual length of the name but
// also counts any following null-characters needed for well
// address-alignment
writeln(' len: ', len);
// The record's name field has been declared
// to be a /single/ character.
// Indeed we know it is a (dynamic) array of char
// what corresponds to C's null-terminated strings.
// Meanwhile writeln() is capable of
// printing null-terminated strings, too.
// All it needs is the information a given argument is such one.
// Referring to inEvent^.name (single char) does not
// but following typecasted pointer:
writeln(' name: ', PChar(@inEvent^.name));
// end of with-inEvent^-do statement
end;
// inotify(7) says the size of an inotify_event is
// sizeof(inotify_event) + len. but wait! it's a trap!
// it's true for C, but in Pascal you got an off-by-one-error:
// the inotify_event-record already
// includes the first character of the name-field.
inc(bytesProcessedCount, sizeof(inotify_event)-1 + inEvent^.len);
inEvent := PInotify_event(@inEventQueueBuffer[sizeof(inotify_event)-1 +
inEvent^.len]);
// end of while-loop over every read inotify event
end;
// end of main-loop while true
end;
end.
// vim: set tw=78 ts=4 noet bs=eol,start,indent fdm=marker fdc=1:translations
inotifytst.de.po:
#: inotifytst:warning
msgid "warning: "
msgstr "Warnung: "
#: inotifytst:error
msgid "error: "
msgstr "Fehler: "
#: inotifytst:closeinotifyfdfailed
msgid "closing inotify file descriptor failed"
msgstr "inotify Dateideskriptor schließen fehlgeschlagen"
#: inotifytst:disassocinwdfrinfdfailed
msgid "disassociating inwd from infd failed"
msgstr "Trennung von inwd und infd fehlgeschlagen"
#: inotifytst:initializinginotifyfdfailed
msgid "initializing inotify file descriptor failed"
msgstr "inotify Dateideskritpor initialisiieren fehlgeschlagen"
#: inotifytst:addingwatchedpathtoinotifywatchlistfailed
msgid "adding '%s' to inotify watch list failed"
msgstr "hinzufügen von '%s' zur inotify Beobachtungsliste fehlgeschlagen"
#: inotifytst:couldnotallocatememforinotifyevents
msgid "could not allocate memory for inotify events"
msgstr "konnte kein Speicher für inotify Ereignisse reservieren"
#: inotifytst:preparingofsignalhandlerinstallfailed
msgid "preparing of signal-handler install failed"
msgstr "vorbereiten des Signalbehandlers Installation fehlgeschlagen"
#: inotifytst:couldnotinstallsignalhandlerforsigint
msgid "could not install signal handler for sigint"
msgstr "konnte den Signalbehandler für das Unterbrechungssignal nicht installieren"
#: inotifytst:readingfrominotifyfdfailed
msgid "reading from inotify file descriptor failed"
msgstr "vom inotify Dateideskriptor lesen fehlgeschlagen"inotifytst.en.po:
#: inotifytst:warning
msgid "warning: "
msgstr "warning: "
#: inotifytst:error
msgid "error: "
msgstr "error: "
#: inotifytst:closeinotifyfdfailed
msgid "closing inotify file descriptor failed"
msgstr "closing inotify file descriptor failed"
#: inotifytst:disassocinwdfrinfdfailed
msgid "disassociating inwd from infd failed"
msgstr "disassociating inwd from infd failed"
#: inotifytst:initializinginotifyfdfailed
msgid "initializing inotify file descriptor failed"
msgstr "initializing inotify file descriptor failed"
#: inotifytst:addingwatchedpathtoinotifywatchlistfailed
msgid "adding '%s' to inotify watch list failed"
msgstr "adding '%s' to inotify watch list failed"
#: inotifytst:couldnotallocatememforinotifyevents
msgid "could not allocate memory for inotify events"
msgstr "could not allocate memory for inotify events"
#: inotifytst:preparingofsignalhandlerinstallfailed
msgid "preparing of signal-handler install failed"
msgstr "preparing of signal-handler install failed"
#: inotifytst:couldnotinstallsignalhandlerforsigint
msgid "could not install signal handler for sigint"
msgstr "could not install signal handler for sigint"
#: inotifytst:readingfrominotifyfdfailed
msgid "reading from inotify file descriptor failed"
msgstr "reading from inotify file descriptor failed"From the Free Pascal wiki, page "inotify", as it stood on 2020-05-06 after a change by Kai Burghardt, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.
Talk about this page
Nobody has opened a bench for this page yet. Sign in to open one.
