Sign in Join
Wiki copytemporary

inotify: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: inotify

OldNewLine
1+## demo
2+
3+### main program
4+
5+``` pascal
6+(**
7+ \brief Sample program showing inotify events.
8+ \version @0x5A4EEB4C
9+ \author Kai Burghardt <wiz at KaiBurghardt.de>
10+ \date 2018
11+ \copyright All rights reserved.
12+
13+ This program prints a readable representation of caught inotify events.
14+ It is non-interactive and does only watch a directory/file specified
15+ at compile-time.
16+*)
17+program inotifytst(input, output, stderr);
18+
19+{$mode objfpc}
20+
21+{$modeswitch classicprocvars on}
22+
23+{$typedAddress on}
24+
25+uses
26+ baseunix, linux, gettext, sysutils;
27+
28+const
29+ (**
30+ \brief directory/file to be monitored by inotify
31+
32+ \note Not yet at run-time existing files are not treat specially.
33+ This program does not test whether watchedPath is a valid path.
34+ However, inotify does not add watches to non-existing paths.
35+ So inotify_add_watch may raise an error.
36+ *)
37+ watchedPath = '/tmp/abc';
38+ /// \brief holds size of largest expected inotify_event size
39+ maxExpEventSize = sizeof(inotify_event) + name_max;
40+
41+// resource strings {}
42+
43+var
44+ /// \brief inotify file descriptor
45+ infd: cint;
46+ /// \brief inotify watch descriptor
47+ inwd: cint;
48+ /// \brief buffer for reading inotify events
49+ inEventQueueBuffer: PChar;
50+ bytesReadCount, bytesProcessedCount: TsSize;
51+ /// \brief a pointer to handle a single inotify_event
52+ inEvent: PInotify_event;
53+ /// \brief pointer to a signal action record
54+ newAction: PSigActionRec;
55+
56+(**
57+ \brief Closes inotify file descriptor.
58+
59+ closeInFd closes the inotify file descriptor by invoking fpClose.
60+ It prints a warning on stderr if it went wrong but does not abort.
61+*)
62+procedure closeInFD;
63+begin
64+ // when all fds referring to an inotify-instance have been closed,
65+ // the underlying object and its resources are automatically freed
66+ if fpClose(infd) <> 0 then
67+ begin
68+ writeln(stderr, warning + closeInotifyFDfailed);
69+ end;
70+end;
71+
72+(**
73+ \brief Removes inotify watch
74+
75+ cleanUpInWdNFd removes the only installed inotify watch
76+ from (the only) inotify watch descriptor.
77+*)
78+procedure cleanUpInWD;
79+begin
80+ if inotify_rm_watch(infd, inwd) <> 0 then
81+ begin
82+ writeln(stderr, warning + disassocInwdFrInfdFailed);
83+ end;
84+end;
85+
86+(**
87+ \brief frees reserved memory
88+
89+ cleanUpEverything frees allocated memory which is reserved for
90+ operations in the main loop.
91+
92+ \sa sigHandler
93+*)
94+procedure cleanUpMemory;
95+begin
96+ freeMem(inEventQueueBuffer, maxExpEventSize);
97+end;
98+
99+(**
100+ \brief procedure-wrapper for intended termination by signals
101+
102+ sigHandler calls cleanUpEverything.
103+ It writes a final newline and halts program execution.
104+*)
105+procedure sigHandler(
106+ signal: longInt;
107+ info: PSigInfo;
108+ context: PSigContext
109+ ); noreturn;
110+begin
111+ writeln;
112+ halt(0);
113+end;
114+
115+(* *)
116+(* M A I N *)
117+(* *)
118+
119+begin
120+ //translateResourcestrings('/usr/share/locale/%s/LC_MESSAGES/' +
121+ // applicationName() + '.mo');
122+ translateResourcestrings(applicationName() + '.%s.mo');
123+
124+ // function inotify_init() initializes a new inotify instance and
125+ // returns a file descriptor associated with its inotify event queue
126+ infd := inotify_init();
127+ if infd < 0 then
128+ begin
129+ writeln(stderr, error + initializingInotifyFDfailed);
130+ // optional: further error analysis with fpgeterrno()
131+ halt(1);
132+ end;
133+ addExitProc(closeInFD);
134+
135+ // next step: adding a watch to a previously initialized inotify instance
136+ inwd := inotify_add_watch(infd, watchedPath, in_all_events);
137+ if inwd < 0 then
138+ begin
139+ writeln(stderr, error +
140+ format(addingWatchedPathToInotifyWatchListFailed, [watchedPath]));
141+ // optional: retrieve errno with fpgeterrno()
142+ halt(2);
143+ end;
144+ addExitProc(cleanUpInWD);
145+
146+ // avoid a run-time error on getMem-failure
147+ returnNilIfGrowHeapFails := true;
148+ // let's occupy some more more heap!
149+ inEventQueueBuffer := getMem(maxExpEventSize);
150+ // check on nil-pointer (failure)
151+ if not assigned(inEventQueueBuffer) then
152+ begin
153+ writeln(stderr, error + couldNotAllocateMemForInotifyEvents);
154+ halt(3);
155+ end;
156+ addExitProc(cleanUpMemory);
157+
158+ // install a signal handler for several signals
159+ new(newAction);
160+ if not assigned(newAction) then
161+ begin
162+ writeln(stderr, error + preparingOfSignalHandlerInstallFailed);
163+ halt(4);
164+ end;
165+
166+ // preparing signal action record
167+ // save address of sigHandler procedure
168+ newAction^.sa_handler := sigActionHandler(@sigHandler);
169+ fillchar(newAction^.sa_mask, sizeof(newAction^.sa_mask), #0);
170+ newAction^.sa_flags := 0;
171+
172+ // pass sigActionRec to sigaction(2) syscall
173+ if fpSigAction(SigHup or SigInt or SigQuit or SigAbrt or SigTerm or
174+ SigTStp, newAction, nil) <> 0 then
175+ begin
176+ writeln(stderr, error + couldNotInstallSignalHandlerForSigint);
177+ halt(5);
178+ end;
179+
180+ // get rid of unused newAction
181+ dispose(newAction);
182+
183+ // TODO: find something better than
184+ // a while-true-loop and signal handling
185+ while true do
186+ begin
187+ // read() returns the amount of bytes have been read.
188+ // read() reads at most maxExpEventSize bytes to the memory position
189+ // specified by inEventQueueBuffer.
190+ // It's only possible to read whole inotify events,
191+ // but no fractions even though
192+ // the _beginning_ of the next event may fit into remaining space.
193+ bytesReadCount := fpRead(infd, inEventQueueBuffer, maxExpEventSize);
194+ if bytesReadCount < 0 then
195+ begin
196+ writeln(stderr, error + readingFromInotifyFDfailed);
197+ halt(6);
198+ end;
199+
200+ // as there may be multiple inotify_events saved at inEventQueueBuffer
201+ // we have to keep a counter how much has been processed
202+ bytesProcessedCount := 0;
203+
204+ // reset inEvent
205+ // typecast PChar to use it as a PInotify_event as such allows the
206+ // usage of dot-fieldname-designators
207+ inEvent := PInotify_event(inEventQueueBuffer);
208+
209+ while bytesProcessedCount < bytesReadCount do
210+ begin
211+ // print a readable representation of current inotify_event
212+ writeln('inotify_event:');
213+ with inEvent^ do
214+ begin
215+ writeln(' wd: ', wd);
216+
217+ writeln(' mask: %', binStr(mask, 32));
218+ // several tests on the mask {}
219+
220+ writeln(' cookie: $', hexStr(cookie, 8));
221+
222+ // note: len does not contain the actual length of the name but
223+ // also counts any following null-characters needed for well
224+ // address-alignment
225+ writeln(' len: ', len);
226+
227+ // The record's name field has been declared
228+ // to be a /single/ character.
229+ // Indeed we know it is a (dynamic) array of char
230+ // what corresponds to C's null-terminated strings.
231+ // Meanwhile writeln() is capable of
232+ // printing null-terminated strings, too.
233+ // All it needs is the information a given argument is such one.
234+ // Referring to inEvent^.name (single char) does not
235+ // but following typecasted pointer:
236+ writeln(' name: ', PChar(@inEvent^.name));
237+ // end of with-inEvent^-do statement
238+ end;
239+
240+ // inotify(7) says the size of an inotify_event is
241+ // sizeof(inotify_event) + len. but wait! it's a trap!
242+ // it's true for C, but in Pascal you got an off-by-one-error:
243+ // the inotify_event-record already
244+ // includes the first character of the name-field.
245+ inc(bytesProcessedCount, sizeof(inotify_event)-1 + inEvent^.len);
246+ inEvent := PInotify_event(@inEventQueueBuffer[sizeof(inotify_event)-1 +
247+ inEvent^.len]);
248+ // end of while-loop over every read inotify event
249+ end;
250+ // end of main-loop while true
251+ end;
252+end.
253+// vim: set tw=78 ts=4 noet bs=eol,start,indent fdm=marker fdc=1:
254+```
255+
256+### translations
257+
258+`inotifytst.de.po`:
259+
260+```gettext
261+#: inotifytst:warning
262+msgid "warning: "
263+msgstr "Warnung: "
264+
265+#: inotifytst:error
266+msgid "error: "
267+msgstr "Fehler: "
268+
269+#: inotifytst:closeinotifyfdfailed
270+msgid "closing inotify file descriptor failed"
271+msgstr "inotify Dateideskriptor schließen fehlgeschlagen"
272+
273+#: inotifytst:disassocinwdfrinfdfailed
274+msgid "disassociating inwd from infd failed"
275+msgstr "Trennung von inwd und infd fehlgeschlagen"
276+
277+#: inotifytst:initializinginotifyfdfailed
278+msgid "initializing inotify file descriptor failed"
279+msgstr "inotify Dateideskritpor initialisiieren fehlgeschlagen"
280+
281+#: inotifytst:addingwatchedpathtoinotifywatchlistfailed
282+msgid "adding '%s' to inotify watch list failed"
283+msgstr "hinzufügen von '%s' zur inotify Beobachtungsliste fehlgeschlagen"
284+
285+#: inotifytst:couldnotallocatememforinotifyevents
286+msgid "could not allocate memory for inotify events"
287+msgstr "konnte kein Speicher für inotify Ereignisse reservieren"
288+
289+#: inotifytst:preparingofsignalhandlerinstallfailed
290+msgid "preparing of signal-handler install failed"
291+msgstr "vorbereiten des Signalbehandlers Installation fehlgeschlagen"
292+
293+#: inotifytst:couldnotinstallsignalhandlerforsigint
294+msgid "could not install signal handler for sigint"
295+msgstr "konnte den Signalbehandler für das Unterbrechungssignal nicht installieren"
296+
297+#: inotifytst:readingfrominotifyfdfailed
298+msgid "reading from inotify file descriptor failed"
299+msgstr "vom inotify Dateideskriptor lesen fehlgeschlagen"
300+```
301+
302+`inotifytst.en.po`:
303+
304+```gettext
305+#: inotifytst:warning
306+msgid "warning: "
307+msgstr "warning: "
308+
309+#: inotifytst:error
310+msgid "error: "
311+msgstr "error: "
312+
313+#: inotifytst:closeinotifyfdfailed
314+msgid "closing inotify file descriptor failed"
315+msgstr "closing inotify file descriptor failed"
316+
317+#: inotifytst:disassocinwdfrinfdfailed
318+msgid "disassociating inwd from infd failed"
319+msgstr "disassociating inwd from infd failed"
320+
321+#: inotifytst:initializinginotifyfdfailed
322+msgid "initializing inotify file descriptor failed"
323+msgstr "initializing inotify file descriptor failed"
324+
325+#: inotifytst:addingwatchedpathtoinotifywatchlistfailed
326+msgid "adding '%s' to inotify watch list failed"
327+msgstr "adding '%s' to inotify watch list failed"
328+
329+#: inotifytst:couldnotallocatememforinotifyevents
330+msgid "could not allocate memory for inotify events"
331+msgstr "could not allocate memory for inotify events"
332+
333+#: inotifytst:preparingofsignalhandlerinstallfailed
334+msgid "preparing of signal-handler install failed"
335+msgstr "preparing of signal-handler install failed"
336+
337+#: inotifytst:couldnotinstallsignalhandlerforsigint
338+msgid "could not install signal handler for sigint"
339+msgstr "could not install signal handler for sigint"
340+
341+#: inotifytst:readingfrominotifyfdfailed
342+msgid "reading from inotify file descriptor failed"
343+msgstr "reading from inotify file descriptor failed"
344+```
345+
346+---
347+*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](/wiki-contact).*
348+Category: Code

Back to history