The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: ca012f3b335ff7e5bd9171d00e5d71b89ad10bf5 $
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#include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
27#include <freeradius-devel/server/exfile.h>
28#include <freeradius-devel/server/trigger.h>
29
30#include <freeradius-devel/util/debug.h>
31#include <freeradius-devel/util/file.h>
32#include <freeradius-devel/util/misc.h>
33#include <freeradius-devel/util/perm.h>
34#include <freeradius-devel/util/syserror.h>
35
36#include <fcntl.h>
37
45
47 "open",
48 "close",
49 "reserve",
50 "release"
51};
52
53typedef struct {
54 int fd; //!< File descriptor associated with an entry.
55 uint32_t hash; //!< Hash for cheap comparison.
56 fr_time_t last_used; //!< Last time the entry was used.
57 dev_t st_dev; //!< device inode
58 ino_t st_ino; //!< inode number
59 char *filename; //!< Filename.
61
62
63struct exfile_s {
64 uint32_t max_entries; //!< How many file descriptors we keep track of.
65 fr_time_delta_t max_idle; //!< Maximum idle time for a descriptor.
69 bool locking;
70 CONF_SECTION *conf; //!< Conf section to search for triggers.
71 char const *trigger_prefix; //!< Trigger path in the global trigger section.
72 fr_pair_list_t trigger_args; //!< Arguments to pass to trigger.
73 bool trigger_undef[EXFILE_TRIGGER_MAX]; //!< Is the trigger undefined
74 CONF_PAIR *trigger_cp[EXFILE_TRIGGER_MAX]; //!< Cache of trigger CONF_PAIRs
75};
76
77#define MAX_TRY_LOCK 4 //!< How many times we attempt to acquire a lock
78 //!< before giving up.
79
80/** Send an exfile trigger.
81 *
82 * @param[in] ef to send trigger for.
83 * @param[in] entry for the file that the event occurred on.
84 * @param[in] ex_trigger to fire.
85 */
86static inline void exfile_trigger(exfile_t *ef, exfile_entry_t *entry, exfile_trigger_t ex_trigger)
87{
88 char name[128];
91 fr_dict_attr_t const *da;
92
93 if (ef->trigger_undef[ex_trigger]) return;
94
96 fr_assert(ef != NULL);
97 fr_assert(ex_trigger < EXFILE_TRIGGER_MAX);
98
99 if (!ef->trigger_prefix) return;
100
102 if (!da) {
103 ERROR("Incomplete internal dictionary: Missing definition for \"Exfile-Name\"");
104 return;
105 }
106
107 (void) fr_pair_list_copy(NULL, &args, &ef->trigger_args);
108
110 talloc_array_length(entry->filename) - 1, false);
111
112 snprintf(name, sizeof(name), "%s.%s", ef->trigger_prefix, exfile_trigger_names[ex_trigger]);
113 if (trigger(unlang_interpret_get_thread_default(), ef->conf, &ef->trigger_cp[ex_trigger], name, false, &args) == -1) {
114 ef->trigger_undef[ex_trigger] = true;
115 }
116
118}
119
120
122{
123 if (entry->fd >= 0) close(entry->fd);
124
125 entry->hash = 0;
126 entry->fd = -1;
127
128 /*
129 * Issue close trigger *after* we've closed the fd
130 */
132
133 /*
134 * Trigger still needs access to filename to populate Exfile-Name
135 */
136 TALLOC_FREE(entry->filename);
137}
138
139
140static int _exfile_free(exfile_t *ef)
141{
142 uint32_t i;
143
144 pthread_mutex_lock(&ef->mutex);
145
146 for (i = 0; i < ef->max_entries; i++) {
147 if (!ef->entries[i].filename) continue;
148
149 exfile_cleanup_entry(ef, &ef->entries[i]);
150 }
151
152 pthread_mutex_unlock(&ef->mutex);
153 pthread_mutex_destroy(&ef->mutex);
154
155 return 0;
156}
157
158/** Initialize a way for multiple threads to log to one or more files.
159 *
160 * @param ctx The talloc context
161 * @param max_entries Max file descriptors to cache, and manage locks for.
162 * @param max_idle Maximum time a file descriptor can be idle before it's closed.
163 * @param locking whether or not to lock the files.
164 * @return
165 * - new context.
166 * - NULL on error.
167 */
168exfile_t *exfile_init(TALLOC_CTX *ctx, uint32_t max_entries, fr_time_delta_t max_idle, bool locking)
169{
170 exfile_t *ef;
171
172 ef = talloc_zero(NULL, exfile_t);
173 if (!ef) return NULL;
175
176 talloc_link_ctx(ctx, ef);
177
178 ef->max_entries = max_entries;
179 ef->max_idle = max_idle;
180 ef->locking = locking;
181
182 /*
183 * If we're not locking the files, just return the
184 * handle. Each call to exfile_open() will just open a
185 * new file descriptor.
186 */
187 if (!ef->locking) return ef;
188
189 ef->entries = talloc_zero_array(ef, exfile_entry_t, max_entries);
190 if (!ef->entries) {
191 talloc_free(ef);
192 return NULL;
193 }
194
195 if (pthread_mutex_init(&ef->mutex, NULL) != 0) {
196 talloc_free(ef);
197 return NULL;
198 }
199
200 talloc_set_destructor(ef, _exfile_free);
201
202 return ef;
203}
204
205/** Enable triggers for an exfiles handle
206 *
207 * @param[in] ef to enable triggers for.
208 * @param[in] conf section to search for triggers in.
209 * @param[in] trigger_prefix prefix to prepend to all trigger names. Usually a path
210 * to the module's trigger configuration .e.g.
211 * @verbatim modules.<name>.file @endverbatim
212 * @verbatim <trigger name> @endverbatim is appended to form the complete path.
213 * @param[in] trigger_args to make available in any triggers executed by the exfile api.
214 * Exfile-File is automatically added to this list.
215 */
216void exfile_enable_triggers(exfile_t *ef, CONF_SECTION *conf, char const *trigger_prefix, fr_pair_list_t *trigger_args)
217{
219 MEM(ef->trigger_prefix = trigger_prefix ? talloc_typed_strdup(ef, trigger_prefix) : "");
220
222
223 ef->conf = conf;
224
225 if (!trigger_args) return;
226
227 (void) fr_pair_list_copy(ef, &ef->trigger_args, trigger_args);
228}
229
230
231/*
232 * Try to open the file. It it doesn't exist, try to
233 * create it's parent directories.
234 */
235static int exfile_open_mkdir(exfile_t *ef, char const *filename, mode_t permissions)
236{
237 int fd;
238
239 fd = open(filename, O_RDWR | O_CREAT, permissions);
240 if (fd < 0) {
241 mode_t dirperm;
242 char *p, *dir;
243
244 /*
245 * Maybe the directory doesn't exist. Try to
246 * create it.
247 */
248 dir = talloc_typed_strdup(ef, filename);
249 if (!dir) return -1;
250 p = strrchr(dir, FR_DIR_SEP);
251 if (!p) {
252 fr_strerror_printf("No '/' in '%s'", filename);
253 talloc_free(dir);
254 return -1;
255 }
256 *p = '\0';
257
258 /*
259 * Ensure that the 'x' bit is set, so that we can
260 * read the directory.
261 */
262 dirperm = permissions;
263 if ((dirperm & 0600) != 0) dirperm |= 0100;
264 if ((dirperm & 0060) != 0) dirperm |= 0010;
265 if ((dirperm & 0006) != 0) dirperm |= 0001;
266
267 if (fr_mkdir(NULL, dir, -1, dirperm, NULL, NULL) < 0) {
268 fr_strerror_printf("Failed to create directory %s: %s", dir, fr_syserror(errno));
269 talloc_free(dir);
270 return -1;
271 }
272 talloc_free(dir);
273
274 fd = open(filename, O_RDWR | O_CREAT, permissions);
275 if (fd < 0) {
276 fr_strerror_printf("Failed to open file %s: %s", filename, fr_syserror(errno));
277 return -1;
278 }
279 }
280
281 return fd;
282}
283
284/*
285 * Experience appears to show that coverity models of functions can't use incoming parameters
286 * to influence whether and which __coverity*__() functions are called. We therefore create a
287 * separate function for the locking case which we *can* model.
288 */
289static int exfile_open_lock(exfile_t *ef, char const *filename, mode_t permissions, off_t *offset)
290{
291 int i, tries, unused = -1, found = -1, oldest = -1;
292 bool do_cleanup = false;
294 fr_time_t now;
295 struct stat st;
296 off_t real_offset;
297
298 /*
299 * It's faster to do hash comparisons of a string than
300 * full string comparisons.
301 */
302 hash = fr_hash_string(filename);
303 now = fr_time();
304 unused = -1;
305
306 pthread_mutex_lock(&ef->mutex);
307
308 if (fr_time_gt(now, fr_time_add(ef->last_cleaned, fr_time_delta_from_sec(1)))) do_cleanup = true;
309
310 /*
311 * Find the matching entry, or an unused one.
312 *
313 * Also track which entry is the oldest, in case there
314 * are no unused entries.
315 */
316 for (i = 0; i < (int) ef->max_entries; i++) {
317 if (!ef->entries[i].filename) {
318 if (unused < 0) unused = i;
319 continue;
320 }
321
322 if ((oldest < 0) ||
323 (fr_time_lt(ef->entries[i].last_used, ef->entries[oldest].last_used))) {
324 oldest = i;
325 }
326
327 /*
328 * Hash comparisons are fast. String comparisons are slow.
329 *
330 * But we still need to do string comparisons if
331 * the hash matches, because 1/2^16 filenames
332 * will result in a hash collision. And that's
333 * enough filenames in a long-running server to
334 * ensure that it happens.
335 */
336 if ((found < 0) &&
337 (ef->entries[i].hash == hash) &&
338 (strcmp(ef->entries[i].filename, filename) == 0)) {
339 found = i;
340
341 /*
342 * If we're not cleaning up, stop now.
343 */
344 if (!do_cleanup) break;
345
346 /*
347 * If we are cleaning up, then clean up
348 * entries OTHER than the one we found,
349 * do so now.
350 */
351 } else if (do_cleanup) {
352 if (fr_time_gteq(fr_time_add(ef->entries[i].last_used, ef->max_idle), now)) continue;
353
354 exfile_cleanup_entry(ef, &ef->entries[i]);
355 }
356 }
357
358 if (do_cleanup) ef->last_cleaned = now;
359
360 /*
361 * We found an existing entry, return that.
362 */
363 if (found >= 0) {
364 i = found;
365
366 /*
367 * Stat the *filename*, not the file we opened.
368 * If that's not the file we opened, then go back
369 * and re-open the file.
370 */
371 if (stat(ef->entries[i].filename, &st) < 0) {
372 goto reopen;
373 }
374
375 if ((st.st_dev != ef->entries[i].st_dev) ||
376 (st.st_ino != ef->entries[i].st_ino)) {
377 close(ef->entries[i].fd);
378 goto reopen;
379 }
380
381 goto try_lock;
382 }
383
384 /*
385 * There are no unused entries, free the oldest one.
386 */
387 if (unused < 0) {
388 exfile_cleanup_entry(ef, &ef->entries[oldest]);
389 unused = oldest;
390 }
391
392 /*
393 * Create a new entry.
394 */
395 i = unused;
396
397 ef->entries[i].hash = hash;
398 ef->entries[i].filename = talloc_typed_strdup(ef->entries, filename);
399 ef->entries[i].fd = -1;
400
401reopen:
402 ef->entries[i].fd = exfile_open_mkdir(ef, filename, permissions);
403 if (ef->entries[i].fd < 0) goto error;
404
406
407try_lock:
408 /*
409 * Lock from the start of the file.
410 */
411 if (lseek(ef->entries[i].fd, 0, SEEK_SET) < 0) {
412 fr_strerror_printf("Failed to seek in file %s: %s", filename, fr_syserror(errno));
413
414 error:
415 exfile_cleanup_entry(ef, &ef->entries[i]);
416 pthread_mutex_unlock(&(ef->mutex));
417 return -1;
418 }
419
420 /*
421 * Try to lock it. If we can't lock it, it's because
422 * some reader has re-named the file to "foo.work" and
423 * locked it. So, we close the current file, re-open it,
424 * and try again/
425 */
426 for (tries = 0; tries < MAX_TRY_LOCK; tries++) {
427 if (rad_lockfd_nonblock(ef->entries[i].fd, 0) >= 0) break;
428
429 if (errno != EAGAIN) {
430 fr_strerror_printf("Failed to lock file %s: %s", filename, fr_syserror(errno));
431 goto error;
432 }
433
434 close(ef->entries[i].fd);
435 ef->entries[i].fd = open(filename, O_RDWR | O_CREAT, permissions);
436 if (ef->entries[i].fd < 0) {
437 fr_strerror_printf("Failed to open file %s: %s", filename, fr_syserror(errno));
438 goto error;
439 }
440 }
441
442 if (tries >= MAX_TRY_LOCK) {
443 fr_strerror_printf("Failed to lock file %s: too many tries", filename);
444 goto error;
445 }
446
447 /*
448 * Maybe someone deleted the file while we were waiting
449 * for the lock. If so, re-open it.
450 */
451 if (fstat(ef->entries[i].fd, &st) < 0) {
452 fr_strerror_printf("Failed to stat file %s: %s", filename, fr_syserror(errno));
453 goto reopen;
454 }
455
456 if (st.st_nlink == 0) {
457 close(ef->entries[i].fd);
458 goto reopen;
459 }
460
461 /*
462 * Remember which device and inode this file is
463 * for.
464 */
465 ef->entries[i].st_dev = st.st_dev;
466 ef->entries[i].st_ino = st.st_ino;
467
468 /*
469 * Sometimes the file permissions are changed externally.
470 * just be sure to update the permission if necessary.
471 */
472 if ((st.st_mode & ~S_IFMT) != permissions) {
473 char str_need[10], oct_need[5];
474 char str_have[10], oct_have[5];
475
476 fr_perm_mode_to_oct(oct_need, permissions);
477 fr_perm_mode_to_str(str_need, permissions);
478
479 fr_perm_mode_to_oct(oct_have, st.st_mode & ~S_IFMT);
480 fr_perm_mode_to_str(str_have, st.st_mode & ~S_IFMT);
481
482 WARN("File %s permissions are %s (%s) not %s (%s))", filename,
483 oct_have, str_have, oct_need, str_need);
484
485 if (((st.st_mode | permissions) != st.st_mode) &&
486 (fchmod(ef->entries[i].fd, (st.st_mode & ~S_IFMT) | permissions) < 0)) {
487 fr_perm_mode_to_oct(oct_need, (st.st_mode & ~S_IFMT) | permissions);
488 fr_perm_mode_to_str(str_need, (st.st_mode & ~S_IFMT) | permissions);
489
490 WARN("Failed resetting file %s permissions to %s (%s): %s",
491 filename, oct_need, str_need, fr_syserror(errno));
492 }
493 }
494
495 /*
496 * Seek to the end of the file before returning the FD to
497 * the caller.
498 */
499 real_offset = lseek(ef->entries[i].fd, 0, SEEK_END);
500 if (offset) *offset = real_offset;
501
502 /*
503 * Return holding the mutex for the entry.
504 */
505 ef->entries[i].last_used = now;
506
508
509 /* coverity[missing_unlock] */
510 return ef->entries[i].fd;
511}
512
513/** Open a new log file, or maybe an existing one.
514 *
515 * When multithreaded, the FD is locked via a mutex. This way we're
516 * sure that no other thread is writing to the file.
517 *
518 * @param ef The logfile context returned from exfile_init().
519 * @param filename the file to open.
520 * @param permissions to use.
521 * @param offset Optional pointer to store offset in when seeking the end of file.
522 * @return
523 * - FD used to write to the file.
524 * - -1 on failure.
525 */
526int exfile_open(exfile_t *ef, char const *filename, mode_t permissions, off_t *offset)
527{
528 if (!ef || !filename) return -1;
529
530 if (!ef->locking) {
531 int found = exfile_open_mkdir(ef, filename, permissions);
532 off_t real_offset;
533
534 if (found < 0) return -1;
535 real_offset = lseek(found, 0, SEEK_END);
536 if (offset) *offset = real_offset;
537 return found;
538 }
539
540 return exfile_open_lock(ef, filename, permissions, offset);
541}
542
543/*
544 * Same split for exfile_close().
545 */
546static int exfile_close_lock(exfile_t *ef, int fd)
547{
548 uint32_t i;
549
550 /*
551 * Unlock the bytes that we had previously locked.
552 */
553 for (i = 0; i < ef->max_entries; i++) {
554 if (ef->entries[i].fd != fd) continue;
555
556 (void) lseek(ef->entries[i].fd, 0, SEEK_SET);
557 (void) rad_unlockfd(ef->entries[i].fd, 0);
558 pthread_mutex_unlock(&(ef->mutex));
559
561 return 0;
562 }
563
564 pthread_mutex_unlock(&(ef->mutex));
565
566 fr_strerror_const("Attempt to unlock file which is not tracked");
567 return -1;
568}
569
570/** Close the log file. Really just return it to the pool.
571 *
572 * When multithreaded, the FD is locked via a mutex. This way we're sure that no other thread is
573 * writing to the file. This function will unlock the mutex, so that other threads can write to
574 * the file.
575 *
576 * @param ef The logfile context returned from #exfile_init.
577 * @param fd the FD to close (i.e. return to the pool).
578 * @return
579 * - 0 on success.
580 * - -1 on failure.
581 */
582int exfile_close(exfile_t *ef, int fd)
583{
584 if (!ef->locking) {
585 /*
586 * No locking: just close the file.
587 */
588 close(fd);
589 return 0;
590 }
591 return exfile_close_lock(ef, fd);
592}
va_list args
Definition acutest.h:770
Configuration AVP similar to a fr_pair_t.
Definition cf_priv.h:70
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
#define MEM(x)
Definition debug.h:36
#define ERROR(fmt,...)
Definition dhcpclient.c:41
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2496
fr_dict_t const * fr_dict_internal(void)
Definition dict_util.c:4749
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:3424
ino_t st_ino
inode number
Definition exfile.c:58
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:168
static void exfile_cleanup_entry(exfile_t *ef, exfile_entry_t *entry)
Definition exfile.c:121
pthread_mutex_t mutex
Definition exfile.c:67
#define MAX_TRY_LOCK
How many times we attempt to acquire a lock before giving up.
Definition exfile.c:77
uint32_t max_entries
How many file descriptors we keep track of.
Definition exfile.c:64
static int exfile_open_lock(exfile_t *ef, char const *filename, mode_t permissions, off_t *offset)
Definition exfile.c:289
static const char * exfile_trigger_names[EXFILE_TRIGGER_MAX]
Definition exfile.c:46
bool locking
Definition exfile.c:69
exfile_trigger_t
Definition exfile.c:38
@ EXFILE_TRIGGER_RESERVE
Definition exfile.c:41
@ EXFILE_TRIGGER_RELEASE
Definition exfile.c:42
@ EXFILE_TRIGGER_OPEN
Definition exfile.c:39
@ EXFILE_TRIGGER_CLOSE
Definition exfile.c:40
@ EXFILE_TRIGGER_MAX
Definition exfile.c:43
static int exfile_open_mkdir(exfile_t *ef, char const *filename, mode_t permissions)
Definition exfile.c:235
static void exfile_trigger(exfile_t *ef, exfile_entry_t *entry, exfile_trigger_t ex_trigger)
Send an exfile trigger.
Definition exfile.c:86
char const * trigger_prefix
Trigger path in the global trigger section.
Definition exfile.c:71
dev_t st_dev
device inode
Definition exfile.c:57
fr_time_t last_cleaned
Definition exfile.c:66
uint32_t hash
Hash for cheap comparison.
Definition exfile.c:55
char * filename
Filename.
Definition exfile.c:59
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:216
exfile_entry_t * entries
Definition exfile.c:68
bool trigger_undef[EXFILE_TRIGGER_MAX]
Is the trigger undefined.
Definition exfile.c:73
static int _exfile_free(exfile_t *ef)
Definition exfile.c:140
fr_time_t last_used
Last time the entry was used.
Definition exfile.c:56
fr_pair_list_t trigger_args
Arguments to pass to trigger.
Definition exfile.c:72
CONF_SECTION * conf
Conf section to search for triggers.
Definition exfile.c:70
fr_time_delta_t max_idle
Maximum idle time for a descriptor.
Definition exfile.c:65
int exfile_open(exfile_t *ef, char const *filename, mode_t permissions, off_t *offset)
Open a new log file, or maybe an existing one.
Definition exfile.c:526
CONF_PAIR * trigger_cp[EXFILE_TRIGGER_MAX]
Cache of trigger CONF_PAIRs.
Definition exfile.c:74
int fd
File descriptor associated with an entry.
Definition exfile.c:54
static int exfile_close_lock(exfile_t *ef, int fd)
Definition exfile.c:546
int exfile_close(exfile_t *ef, int fd)
Close the log file.
Definition exfile.c:582
Definition exfile.c:53
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:219
uint32_t fr_hash_string(char const *p)
Definition hash.c:865
unlang_interpret_t * unlang_interpret_get_thread_default(void)
Get the default interpreter for this thread.
Definition interpret.c:2040
talloc_free(reap)
unsigned int uint32_t
unsigned int mode_t
long long int off_t
int rad_unlockfd(int fd, int lock_len)
Definition misc.c:142
int rad_lockfd_nonblock(int fd, int lock_len)
Definition misc.c:130
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:2321
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:46
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:38
#define WARN(fmt,...)
Definition radclient.h:47
static rs_t * conf
Definition radsniff.c:53
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
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
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:167
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
Definition talloc.c:467
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:229
#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_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)
Execute a trigger - call an executable to process an event.
Definition trigger.c:149
close(uq->fd)
#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:378
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