The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
Loading...
Searching...
No Matches
exfile.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/*
18 * $Id: 9602d7e7e2f0c584a973de5f978c63392f9a6f64 $
19 *
20 * @file exfile.c
21 * @brief Allow multiple threads to write to the same set of files.
22 *
23 * @author Alan DeKok (aland@freeradius.org)
24 * @copyright 2014 The FreeRADIUS server project
25 */
26#define _EXFILE_PRIVATE 1
27#include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
28#include <freeradius-devel/server/exfile.h>
29#include <freeradius-devel/server/trigger.h>
30
31#include <freeradius-devel/util/debug.h>
32#include <freeradius-devel/util/file.h>
33#include <freeradius-devel/util/misc.h>
34#include <freeradius-devel/util/perm.h>
35#include <freeradius-devel/util/syserror.h>
36
37#include <fcntl.h>
38
46
48 "open",
49 "close",
50 "reserve",
51 "release"
52};
53
54typedef struct {
55 int fd; //!< File descriptor associated with an entry.
56 uint32_t hash; //!< Hash for cheap comparison.
57 fr_time_t last_used; //!< Last time the entry was used.
58 dev_t st_dev; //!< device inode
59 ino_t st_ino; //!< inode number
60 char *filename; //!< Filename.
62
63
64struct exfile_s {
65 uint32_t max_entries; //!< How many file descriptors we keep track of.
66 fr_time_delta_t max_idle; //!< Maximum idle time for a descriptor.
67 ///< If this is zero, the descriptor will be closed
68 ///< immediately after it is unlocked.
70 pthread_mutex_t mutex;
72 bool locking;
73 CONF_SECTION *conf; //!< Conf section to search for triggers.
74 char const *trigger_prefix; //!< Trigger path in the global trigger section.
75 fr_pair_list_t trigger_args; //!< Arguments to pass to trigger.
76 bool trigger_undef[EXFILE_TRIGGER_MAX]; //!< Is the trigger undefined
77 CONF_PAIR *trigger_cp[EXFILE_TRIGGER_MAX]; //!< Cache of trigger CONF_PAIRs
78};
79
80#define MAX_TRY_LOCK 4 //!< How many times we attempt to acquire a lock
81 //!< before giving up.
82
83/** Send an exfile trigger.
84 *
85 * @param[in] ef to send trigger for.
86 * @param[in] entry for the file that the event occurred on.
87 * @param[in] ex_trigger to fire.
88 */
89static inline void exfile_trigger(exfile_t *ef, exfile_entry_t *entry, exfile_trigger_t ex_trigger)
90{
91 char name[128];
94 fr_dict_attr_t const *da;
95
96 if (ef->trigger_undef[ex_trigger]) return;
97
99 fr_assert(ef != NULL);
100 fr_assert(ex_trigger < EXFILE_TRIGGER_MAX);
101
102 if (!ef->trigger_prefix) return;
103
105 if (!da) {
106 ERROR("Incomplete internal dictionary: Missing definition for \"Exfile-Name\"");
107 return;
108 }
109
110 (void) fr_pair_list_copy(NULL, &args, &ef->trigger_args);
111
113 talloc_strlen(entry->filename), false);
114
115 snprintf(name, sizeof(name), "%s.%s", ef->trigger_prefix, exfile_trigger_names[ex_trigger]);
116 if (trigger(unlang_interpret_get_thread_default(), ef->conf, &ef->trigger_cp[ex_trigger], name, false, &args, NULL) == -1) {
117 ef->trigger_undef[ex_trigger] = true;
118 }
119
121}
122
123
125{
126 if (entry->fd >= 0) close(entry->fd);
127
128 entry->hash = 0;
129 entry->fd = -1;
130
131 /*
132 * Issue close trigger *after* we've closed the fd
133 */
135
136 /*
137 * Trigger still needs access to filename to populate Exfile-Name
138 */
139 TALLOC_FREE(entry->filename);
140}
141
142
143static int _exfile_free(exfile_t *ef)
144{
145 uint32_t i;
146
147 pthread_mutex_lock(&ef->mutex);
148
149 for (i = 0; i < ef->max_entries; i++) {
150 if (!ef->entries[i].filename) continue;
151
152 exfile_cleanup_entry(ef, &ef->entries[i]);
153 }
154
155 pthread_mutex_unlock(&ef->mutex);
156 pthread_mutex_destroy(&ef->mutex);
157
158 return 0;
159}
160
161/** Initialize a way for multiple threads to log to one or more files.
162 *
163 * @param ctx The talloc context
164 * @param max_entries Max file descriptors to cache, and manage locks for.
165 * @param max_idle Maximum time a file descriptor can be idle before it's closed.
166 * @param locking whether or not to lock the files.
167 * @return
168 * - new context.
169 * - NULL on error.
170 */
171exfile_t *exfile_init(TALLOC_CTX *ctx, uint32_t max_entries, fr_time_delta_t max_idle, bool locking)
172{
173 exfile_t *ef;
174
175 ef = talloc_zero(NULL, exfile_t);
176 if (!ef) return NULL;
178
179 talloc_link_ctx(ctx, ef);
180
181 ef->max_entries = max_entries;
182 ef->max_idle = max_idle;
183 ef->locking = locking;
184
185 /*
186 * If we're not locking the files, just return the
187 * handle. Each call to exfile_open() will just open a
188 * new file descriptor.
189 */
190 if (!ef->locking) return ef;
191
192 ef->entries = talloc_zero_array(ef, exfile_entry_t, max_entries);
193 if (!ef->entries) {
194 talloc_free(ef);
195 return NULL;
196 }
197
198 if (pthread_mutex_init(&ef->mutex, NULL) != 0) {
199 talloc_free(ef);
200 return NULL;
201 }
202
203 talloc_set_destructor(ef, _exfile_free);
204
205 return ef;
206}
207
208/** Enable triggers for an exfiles handle
209 *
210 * @param[in] ef to enable triggers for.
211 * @param[in] conf section to search for triggers in.
212 * @param[in] trigger_prefix prefix to prepend to all trigger names. Usually a path
213 * to the module's trigger configuration .e.g.
214 * @verbatim modules.<name>.file @endverbatim
215 * @verbatim <trigger name> @endverbatim is appended to form the complete path.
216 * @param[in] trigger_args to make available in any triggers executed by the exfile api.
217 * Exfile-File is automatically added to this list.
218 */
219void exfile_enable_triggers(exfile_t *ef, CONF_SECTION *conf, char const *trigger_prefix, fr_pair_list_t *trigger_args)
220{
222 MEM(ef->trigger_prefix = trigger_prefix ? talloc_strdup(ef, trigger_prefix) : talloc_strdup(ef, ""));
223
225
226 ef->conf = conf;
227
228 if (!trigger_args) return;
229
230 (void) fr_pair_list_copy(ef, &ef->trigger_args, trigger_args);
231}
232
233
234/*
235 * Try to open the file. It it doesn't exist, try to
236 * create it's parent directories.
237 */
238static int exfile_open_mkdir(char const *filename, mode_t permissions, int flags)
239{
240 int fd;
241
242 fd = open(filename, O_RDWR | O_CREAT | flags, permissions);
243 if (fd < 0) {
244 int dirfd;
245 mode_t dirperm;
246 char *p, *dir;
247
248 /*
249 * Maybe the directory doesn't exist. Try to
250 * create it.
251 */
252 dir = talloc_strdup(NULL, filename);
253 if (!dir) return -1;
254 p = strrchr(dir, FR_DIR_SEP);
255 if (!p) {
256 fr_strerror_printf("No '/' in '%s'", filename);
257 talloc_free(dir);
258 return -1;
259 }
260 *p = '\0';
261
262 /*
263 * Ensure that the 'x' bit is set, so that we can
264 * read the directory.
265 */
266 dirperm = permissions;
267 if ((dirperm & 0600) != 0) dirperm |= 0100;
268 if ((dirperm & 0060) != 0) dirperm |= 0010;
269 if ((dirperm & 0006) != 0) dirperm |= 0001;
270
271 if (fr_mkdir(&dirfd, dir, -1, dirperm, NULL, NULL) < 0) {
272 fr_strerror_printf("Failed to create directory %s: %s", dir, fr_syserror(errno));
273 talloc_free(dir);
274 return -1;
275 }
276
277 fd = openat(dirfd, p+1, O_RDWR | O_CREAT | flags, permissions);
278 talloc_free(dir);
279 close(dirfd);
280
281 if (fd < 0) {
282 fr_strerror_printf("Failed to open file %s: %s", filename, fr_syserror(errno));
283 return -1;
284 }
285 }
286
287 return fd;
288}
289
290/*
291 * exfile_open() calls exfile_open_lock() when ef->locking is true.
292 * exfile_open_lock() returns holding ef->mutex on success, and returns
293 * without holding ef->mutex on failure. exfile.h gives Coverity the
294 * same contract at each call site.
295 */
296static int exfile_open_lock(exfile_t *ef, char const *filename, mode_t permissions, int flags, off_t *offset)
297{
298 int i, tries, unused = -1, found = -1, oldest = -1;
299 bool do_cleanup = false;
301 fr_time_t now;
302 struct stat st;
303 off_t real_offset;
304
305 /*
306 * It's faster to do hash comparisons of a string than
307 * full string comparisons.
308 */
309 hash = fr_hash_string(filename);
310 now = fr_time();
311 unused = -1;
312
313 pthread_mutex_lock(&ef->mutex);
314
315 if (fr_time_gt(now, fr_time_add(ef->last_cleaned, fr_time_delta_from_sec(1)))) do_cleanup = true;
316
317 /*
318 * Find the matching entry, or an unused one.
319 *
320 * Also track which entry is the oldest, in case there
321 * are no unused entries.
322 */
323 for (i = 0; i < (int) ef->max_entries; i++) {
324 if (!ef->entries[i].filename) {
325 if (unused < 0) unused = i;
326 continue;
327 }
328
329 if ((oldest < 0) ||
330 (fr_time_lt(ef->entries[i].last_used, ef->entries[oldest].last_used))) {
331 oldest = i;
332 }
333
334 /*
335 * Hash comparisons are fast. String comparisons are slow.
336 *
337 * But we still need to do string comparisons if
338 * the hash matches, because 1/2^16 filenames
339 * will result in a hash collision. And that's
340 * enough filenames in a long-running server to
341 * ensure that it happens.
342 */
343 if ((found < 0) &&
344 (ef->entries[i].hash == hash) &&
345 (strcmp(ef->entries[i].filename, filename) == 0)) {
346 found = i;
347
348 /*
349 * If we're not cleaning up, stop now.
350 */
351 if (!do_cleanup) break;
352
353 /*
354 * If we are cleaning up, then clean up
355 * entries OTHER than the one we found,
356 * do so now.
357 */
358 } else if (do_cleanup) {
359 if (fr_time_gteq(fr_time_add(ef->entries[i].last_used, ef->max_idle), now)) continue;
360
361 exfile_cleanup_entry(ef, &ef->entries[i]);
362 }
363 }
364
365 if (do_cleanup) ef->last_cleaned = now;
366
367 /*
368 * We found an existing entry, return that.
369 */
370 if (found >= 0) {
371 i = found;
372
373 /*
374 * Stat the *filename*, not the file we opened.
375 * If that's not the file we opened, then go back
376 * and re-open the file.
377 */
378 if (stat(ef->entries[i].filename, &st) < 0) {
379 goto close_reopen;
380 }
381
382 if ((st.st_dev != ef->entries[i].st_dev) ||
383 (st.st_ino != ef->entries[i].st_ino)) {
384 close_reopen:
385 close(ef->entries[i].fd);
386 goto reopen_reset;
387 }
388
389 goto try_lock;
390 }
391
392 /*
393 * There are no unused entries, free the oldest one.
394 */
395 if (unused < 0) {
396 exfile_cleanup_entry(ef, &ef->entries[oldest]);
397 unused = oldest;
398 }
399
400 /*
401 * Create a new entry.
402 */
403 i = unused;
404
405 ef->entries[i].hash = hash;
406 ef->entries[i].filename = talloc_strdup(ef->entries, filename);
407
408reopen_reset:
409 ef->entries[i].fd = -1;
410
411 ef->entries[i].fd = exfile_open_mkdir(filename, permissions, flags);
412 if (ef->entries[i].fd < 0) goto error;
413
415
416try_lock:
417 /*
418 * Lock from the start of the file.
419 */
420 if (lseek(ef->entries[i].fd, 0, SEEK_SET) < 0) {
421 fr_strerror_printf("Failed to seek in file %s: %s", filename, fr_syserror(errno));
422
423 error:
424 exfile_cleanup_entry(ef, &ef->entries[i]);
425 pthread_mutex_unlock(&(ef->mutex));
426 return -1;
427 }
428
429 /*
430 * Try to lock it. If we can't lock it, it's because
431 * some reader has re-named the file to "foo.work" and
432 * locked it. So, we close the current file, re-open it,
433 * and try again/
434 */
435 for (tries = 0; tries < MAX_TRY_LOCK; tries++) {
436 if (rad_lockfd_nonblock(ef->entries[i].fd, 0) >= 0) break;
437
438 if (errno != EAGAIN) {
439 fr_strerror_printf("Failed to lock file %s: %s", filename, fr_syserror(errno));
440 goto error;
441 }
442
443 close(ef->entries[i].fd);
444 ef->entries[i].fd = open(filename, O_RDWR | O_CREAT | flags, permissions);
445 if (ef->entries[i].fd < 0) {
446 fr_strerror_printf("Failed to open file %s: %s", filename, fr_syserror(errno));
447 goto error;
448 }
449 }
450
451 if (tries >= MAX_TRY_LOCK) {
452 fr_strerror_printf("Failed to lock file %s: too many tries", filename);
453 goto error;
454 }
455
456 /*
457 * Maybe someone deleted the file while we were waiting
458 * for the lock. If so, re-open it.
459 */
460 if (fstat(ef->entries[i].fd, &st) < 0) goto close_reopen;
461
462 if (st.st_nlink == 0) goto close_reopen;
463
464 /*
465 * Remember which device and inode this file is
466 * for.
467 */
468 ef->entries[i].st_dev = st.st_dev;
469 ef->entries[i].st_ino = st.st_ino;
470
471 /*
472 * Sometimes the file permissions are changed externally.
473 * just be sure to update the permission if necessary.
474 */
475 if ((st.st_mode & ~S_IFMT) != permissions) {
476 char str_need[10], oct_need[5];
477 char str_have[10], oct_have[5];
478
479 fr_perm_mode_to_oct(oct_need, permissions);
480 fr_perm_mode_to_str(str_need, permissions);
481
482 fr_perm_mode_to_oct(oct_have, st.st_mode & ~S_IFMT);
483 fr_perm_mode_to_str(str_have, st.st_mode & ~S_IFMT);
484
485 WARN("File %s permissions are %s (%s) not %s (%s))", filename,
486 oct_have, str_have, oct_need, str_need);
487
488 if (((st.st_mode | permissions) != st.st_mode) &&
489 (fchmod(ef->entries[i].fd, (st.st_mode & ~S_IFMT) | permissions) < 0)) {
490 fr_perm_mode_to_oct(oct_need, (st.st_mode & ~S_IFMT) | permissions);
491 fr_perm_mode_to_str(str_need, (st.st_mode & ~S_IFMT) | permissions);
492
493 WARN("Failed resetting file %s permissions to %s (%s): %s",
494 filename, oct_need, str_need, fr_syserror(errno));
495 }
496 }
497
498 /*
499 * Seek to the end of the file before returning the FD to
500 * the caller.
501 */
502 real_offset = lseek(ef->entries[i].fd, 0, SEEK_END);
503 if (offset) *offset = real_offset;
504
505 /*
506 * Return holding the mutex for the entry.
507 */
508 ef->entries[i].last_used = now;
509
511
512 /*
513 * Every path here called lseek() on the fd at try_lock, which
514 * fails for an invalid fd and goes to error, so the fd is valid,
515 * and the caller only ever holds the mutex with an fd >= 0.
516 */
517 fr_assert(ef->entries[i].fd >= 0);
518
519#ifdef __COVERITY__
520 /*
521 * The caller holds ef->mutex until exfile_close(). The
522 * macros in exfile.h tell Coverity about the lock at the call
523 * site. Here Coverity must see ef->mutex released.
524 */
525 __coverity_exclusive_lock_release__(&ef->mutex);
526#endif
527 return ef->entries[i].fd;
528}
529
530/** Open a new log file, or maybe an existing one.
531 *
532 * When multithreaded, the FD is locked via a mutex. This way we're
533 * sure that no other thread is writing to the file.
534 *
535 * On success the mutex is held until exfile_close() is called. On
536 * failure the mutex is not held.
537 *
538 * @param ef The logfile context returned from exfile_init().
539 * @param filename the file to open.
540 * @param permissions to use.
541 * @param flags flags to pass to open.
542 * @param offset Optional pointer to store offset in when seeking the end of file.
543 * @return
544 * - FD used to write to the file.
545 * - -1 on failure.
546 */
547int exfile_open(exfile_t *ef, char const *filename, mode_t permissions, int flags, off_t *offset)
548{
549 if (!ef || !filename) return -1;
550
551 if (!ef->locking) {
552 int found = exfile_open_mkdir(filename, permissions, flags);
553 off_t real_offset;
554
555 if (found < 0) return -1;
556 real_offset = lseek(found, 0, SEEK_END);
557 if (offset) *offset = real_offset;
558 return found;
559 }
560
561 return exfile_open_lock(ef, filename, permissions, flags, offset);
562}
563
564/*
565 * exfile_close() calls exfile_close_lock() when ef->locking is true.
566 * exfile_close_lock() releases ef->mutex on every return path.
567 */
568static int exfile_close_lock(exfile_t *ef, int fd)
569{
570 uint32_t i;
571
572#ifdef __COVERITY__
573 /*
574 * The caller has held ef->mutex since exfile_open(). The
575 * macros in exfile.h tell Coverity about the lock at the call
576 * site. Here Coverity must see ef->mutex taken.
577 */
578 __coverity_exclusive_lock_acquire__(&ef->mutex);
579#endif
580
581 /*
582 * Unlock the bytes that we had previously locked.
583 */
584 for (i = 0; i < ef->max_entries; i++) {
585 if (ef->entries[i].fd != fd) continue;
586
587 (void) lseek(ef->entries[i].fd, 0, SEEK_SET);
588 (void) rad_unlockfd(ef->entries[i].fd, 0);
589
590 /*
591 * If max idle is 0, then clean up the file immediately
592 * this is mostly used for testing.
593 */
595 exfile_cleanup_entry(ef, &ef->entries[i]);
596 pthread_mutex_unlock(&(ef->mutex));
597 return 0;
598 }
599
600 pthread_mutex_unlock(&(ef->mutex));
601
603 return 0;
604 }
605
606 pthread_mutex_unlock(&(ef->mutex));
607
608 fr_strerror_const("Attempt to unlock file which is not tracked");
609 return -1;
610}
611
612/** Close the log file. Really just return it to the pool.
613 *
614 * When multithreaded, the FD is locked via a mutex. This way we're sure that no other thread is
615 * writing to the file. This function will unlock the mutex, so that other threads can write to
616 * the file.
617 *
618 * @param ef The logfile context returned from #exfile_init.
619 * @param fd the FD to close (i.e. return to the pool).
620 * @return
621 * - 0 on success.
622 * - -1 on failure.
623 */
624int exfile_close(exfile_t *ef, int fd)
625{
626 if (!ef->locking) {
627 /*
628 * No locking: just close the file.
629 */
630 close(fd);
631 return 0;
632 }
633 return exfile_close_lock(ef, fd);
634}
va_list args
Definition acutest.h:923
Configuration AVP similar to a fr_pair_t.
Definition cf_priv.h:77
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
#define MEM(x)
Definition debug.h:38
#define ERROR(fmt,...)
Definition dhcpclient.c:40
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2717
fr_dict_t const * fr_dict_internal(void)
Definition dict_util.c:5065
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
Definition dict_util.c:3667
ino_t st_ino
inode number
Definition exfile.c:59
exfile_t * exfile_init(TALLOC_CTX *ctx, uint32_t max_entries, fr_time_delta_t max_idle, bool locking)
Initialize a way for multiple threads to log to one or more files.
Definition exfile.c:171
static void exfile_cleanup_entry(exfile_t *ef, exfile_entry_t *entry)
Definition exfile.c:124
pthread_mutex_t mutex
Definition exfile.c:70
#define MAX_TRY_LOCK
How many times we attempt to acquire a lock before giving up.
Definition exfile.c:80
exfile_trigger_t
Definition exfile.c:39
@ EXFILE_TRIGGER_RESERVE
Definition exfile.c:42
@ EXFILE_TRIGGER_RELEASE
Definition exfile.c:43
@ EXFILE_TRIGGER_OPEN
Definition exfile.c:40
@ EXFILE_TRIGGER_CLOSE
Definition exfile.c:41
@ EXFILE_TRIGGER_MAX
Definition exfile.c:44
uint32_t max_entries
How many file descriptors we keep track of.
Definition exfile.c:65
static const char * exfile_trigger_names[EXFILE_TRIGGER_MAX]
Definition exfile.c:47
bool locking
Definition exfile.c:72
static void exfile_trigger(exfile_t *ef, exfile_entry_t *entry, exfile_trigger_t ex_trigger)
Send an exfile trigger.
Definition exfile.c:89
char const * trigger_prefix
Trigger path in the global trigger section.
Definition exfile.c:74
dev_t st_dev
device inode
Definition exfile.c:58
fr_time_t last_cleaned
Definition exfile.c:69
static int exfile_open_lock(exfile_t *ef, char const *filename, mode_t permissions, int flags, off_t *offset)
Definition exfile.c:296
uint32_t hash
Hash for cheap comparison.
Definition exfile.c:56
char * filename
Filename.
Definition exfile.c:60
void exfile_enable_triggers(exfile_t *ef, CONF_SECTION *conf, char const *trigger_prefix, fr_pair_list_t *trigger_args)
Enable triggers for an exfiles handle.
Definition exfile.c:219
exfile_entry_t * entries
Definition exfile.c:71
bool trigger_undef[EXFILE_TRIGGER_MAX]
Is the trigger undefined.
Definition exfile.c:76
int exfile_open(exfile_t *ef, char const *filename, mode_t permissions, int flags, off_t *offset)
Open a new log file, or maybe an existing one.
Definition exfile.c:547
static int _exfile_free(exfile_t *ef)
Definition exfile.c:143
static int exfile_open_mkdir(char const *filename, mode_t permissions, int flags)
Definition exfile.c:238
fr_time_t last_used
Last time the entry was used.
Definition exfile.c:57
fr_pair_list_t trigger_args
Arguments to pass to trigger.
Definition exfile.c:75
CONF_SECTION * conf
Conf section to search for triggers.
Definition exfile.c:73
fr_time_delta_t max_idle
Maximum idle time for a descriptor.
Definition exfile.c:66
CONF_PAIR * trigger_cp[EXFILE_TRIGGER_MAX]
Cache of trigger CONF_PAIRs.
Definition exfile.c:77
int fd
File descriptor associated with an entry.
Definition exfile.c:55
static int exfile_close_lock(exfile_t *ef, int fd)
Definition exfile.c:568
int exfile_close(exfile_t *ef, int fd)
Close the log file.
Definition exfile.c:624
Definition exfile.c:54
uint32_t fr_hash_string(char const *p)
Definition hash.c:919
talloc_free(hp)
unlang_interpret_t * unlang_interpret_get_thread_default(void)
Get the default interpreter for this thread.
Definition interpret.c:2561
#define fr_time()
Definition event.c:58
ssize_t fr_mkdir(int *fd_out, char const *path, ssize_t len, mode_t mode, fr_mkdir_func_t func, void *uctx)
Create directories that are missing in the specified path.
Definition file.c:218
unsigned int uint32_t
unsigned char uint8_t
int rad_unlockfd(int fd, int lock_len)
Definition misc.c:141
int rad_lockfd_nonblock(int fd, int lock_len)
Definition misc.c:129
int fr_pair_list_copy(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from)
Duplicate a list of pairs.
Definition pair.c:2303
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:47
char const * fr_perm_mode_to_str(char out[static 10], mode_t mode)
Convert mode_t into humanly readable permissions flags.
Definition perm.c:36
char const * fr_perm_mode_to_oct(char out[static 5], mode_t mode)
Definition perm.c:51
#define fr_assert(_expr)
Definition rad_assert.h:37
#define WARN(fmt,...)
static rs_t * conf
Definition radsniff.c:52
static unsigned int hash(char const *username, unsigned int tablesize)
Definition rlm_passwd.c:132
static char const * name
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
int talloc_link_ctx(TALLOC_CTX *parent, TALLOC_CTX *child)
Link two different parent and child contexts, so the child is freed before the parent.
Definition talloc.c:168
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:289
#define talloc_strdup(_ctx, _str)
Definition talloc.h:149
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
Definition talloc.h:143
#define fr_time_gteq(_a, _b)
Definition time.h:238
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition time.h:590
#define fr_time_delta_eq(_a, _b)
Definition time.h:287
#define fr_time_add(_a, _b)
Add a time/time delta together.
Definition time.h:196
#define fr_time_gt(_a, _b)
Definition time.h:237
#define fr_time_lt(_a, _b)
Definition time.h:239
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
"server local" time.
Definition time.h:69
int trigger(unlang_interpret_t *intp, CONF_SECTION const *cs, CONF_PAIR **trigger_cp, char const *name, bool rate_limit, fr_pair_list_t *args, void const *uctx)
Execute a trigger - call an executable to process an event.
Definition trigger.c:160
#define fr_pair_list_prepend_by_da_len(_ctx, _vp, _list, _attr, _val, _len, _tainted)
Prepend a pair to a list, assigning its value.
Definition pair.h:400
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223