~ubuntu-branches/ubuntu/trusty/syslog-ng/trusty-proposed

« back to all changes in this revision

Viewing changes to .pc/affile-release-per-writer-LogQueue-instances-during-runtime.patch/modules/affile/affile.c

  • Committer: Package Import Robot
  • Author(s): Laszlo Boszormenyi (GCS), Gergely Nagy
  • Date: 2011-10-11 14:30:48 UTC
  • mfrom: (1.3.7)
  • Revision ID: package-import@ubuntu.com-20111011143048-r1iljux9xbvj3lwh
Tags: 3.3.1.dfsg-1
* New upstream release with important fixes from upstream git tree with
  non-free manpages removed.
* Drop syslog-ng.conf(5) (closes: #496521).
* syslog-ng(8) is generated, and does not mention -Q anymore
  (closes: #616069).
* Supports CAP_SYSLOG on recent kernels (closes: #630172).
* Does not use g_timeout_add_seconds anymore (closes: #609154).

[ Gergely Nagy <algernon@madhouse-project.org> ]
* Update debian/copyright to DEP-5 format.
* Simplified the logrotate file by merging identical entries.
* Include local configuration files from /etc/syslog-ng/conf.d/ (Closes:
  #609050).
* Update syslog-ng.conf to be fully 3.3 compliant.
* Compress both source and binaries (except the syslog-ng meta
  package) with xz, instead of gzip.
* Use dpkg triggers to restart syslog-ng when appropriate.
* Include DFSG-free manual pages for all binaries.
* Build with Hardening enabled.
* Mention syslog(3) in /etc/default/syslog-ng, instead of
  <linux/kernel.h> (Closes: #608605)
* Support 'status' in the init script.
  Patch from Peter Eisentraut <petere@debian.org> (Closes: #644458)
* Build-Depend on libevtlog-dev (>= 0.2.12-5~) for correct shlibs.
* Use [linux-any] in Build-Depends instead of hardcoded links.
  (Closes: #634715)
* Use $SYSLOGNG_OPTS in the init script when reloading syslog-ng.
  (Closes: #589081)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2002-2010 BalaBit IT Ltd, Budapest, Hungary
 
3
 * Copyright (c) 1998-2010 Balázs Scheidler
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify it
 
6
 * under the terms of the GNU General Public License version 2 as published
 
7
 * by the Free Software Foundation, or (at your option) any later version.
 
8
 *
 
9
 * This library is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
 * Lesser General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU Lesser General Public
 
15
 * License along with this library; if not, write to the Free Software
 
16
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
17
 *
 
18
 * As an additional exemption you are allowed to compile & link against the
 
19
 * OpenSSL libraries as published by the OpenSSL project. See the file
 
20
 * COPYING for details.
 
21
 *
 
22
 */
 
23
#include "affile.h"
 
24
#include "driver.h"
 
25
#include "messages.h"
 
26
#include "misc.h"
 
27
#include "serialize.h"
 
28
#include "gprocess.h"
 
29
#include "stats.h"
 
30
#include "mainloop.h"
 
31
 
 
32
#include <sys/types.h>
 
33
#include <sys/stat.h>
 
34
#include <fcntl.h>
 
35
#include <string.h>
 
36
#include <unistd.h>
 
37
#include <errno.h>
 
38
#include <time.h>
 
39
#include <stdlib.h>
 
40
 
 
41
static gboolean
 
42
affile_open_file(gchar *name, gint flags,
 
43
                 gint uid, gint gid, gint mode,
 
44
                 gint dir_uid, gint dir_gid, gint dir_mode,
 
45
                 gboolean create_dirs, gboolean privileged, gboolean is_pipe, gint *fd)
 
46
{
 
47
  cap_t saved_caps;
 
48
  struct stat st;
 
49
 
 
50
  if (strstr(name, "../") || strstr(name, "/..")) 
 
51
    {
 
52
      msg_error("Spurious path, logfile not created",
 
53
                evt_tag_str("path", name),
 
54
                NULL);
 
55
      return FALSE;
 
56
    }
 
57
 
 
58
  saved_caps = g_process_cap_save();
 
59
  if (privileged)
 
60
    {
 
61
      g_process_cap_modify(CAP_DAC_READ_SEARCH, TRUE);
 
62
      g_process_cap_modify(CAP_SYSLOG, TRUE);
 
63
    }
 
64
  else
 
65
    {
 
66
      g_process_cap_modify(CAP_DAC_OVERRIDE, TRUE);
 
67
    }
 
68
 
 
69
  if (create_dirs && !create_containing_directory(name, dir_uid, dir_gid, dir_mode))
 
70
    {
 
71
      g_process_cap_restore(saved_caps);
 
72
      return FALSE;
 
73
    }
 
74
 
 
75
  *fd = -1;
 
76
  if (stat(name, &st) >= 0)
 
77
    {
 
78
      if (is_pipe && !S_ISFIFO(st.st_mode))
 
79
        {
 
80
          msg_warning("WARNING: you are using the pipe driver, underlying file is not a FIFO, it should be used by file()",
 
81
                    evt_tag_str("filename", name),
 
82
                    NULL);
 
83
        }
 
84
      else if (!is_pipe && S_ISFIFO(st.st_mode))
 
85
        {
 
86
          msg_warning("WARNING: you are using the file driver, underlying file is a FIFO, it should be used by pipe()",
 
87
                      evt_tag_str("filename", name),
 
88
                      NULL);
 
89
        }
 
90
    }
 
91
  *fd = open(name, flags, mode < 0 ? 0600 : mode);
 
92
  if (is_pipe && *fd < 0 && errno == ENOENT)
 
93
    {
 
94
      if (mkfifo(name, 0666) >= 0)
 
95
        *fd = open(name, flags, 0666);
 
96
    }
 
97
 
 
98
  if (*fd != -1)
 
99
    {
 
100
      g_fd_set_cloexec(*fd, TRUE);
 
101
      
 
102
      g_process_cap_modify(CAP_CHOWN, TRUE);
 
103
      g_process_cap_modify(CAP_FOWNER, TRUE);
 
104
      set_permissions_fd(*fd, uid, gid, mode);
 
105
    }
 
106
  g_process_cap_restore(saved_caps);
 
107
  msg_trace("affile_open_file",
 
108
            evt_tag_str("path", name),
 
109
            evt_tag_int("fd",*fd),
 
110
            NULL);
 
111
 
 
112
  return *fd != -1;
 
113
}
 
114
 
 
115
static gboolean
 
116
affile_sd_open_file(AFFileSourceDriver *self, gchar *name, gint *fd)
 
117
{
 
118
  gint flags;
 
119
  
 
120
  if (self->flags & AFFILE_PIPE)
 
121
    flags = O_RDWR | O_NOCTTY | O_NONBLOCK | O_LARGEFILE;
 
122
  else
 
123
    flags = O_RDONLY | O_NOCTTY | O_NONBLOCK | O_LARGEFILE;
 
124
 
 
125
  if (affile_open_file(name, flags, -1, -1, -1, 0, 0, 0, 0, !!(self->flags & AFFILE_PRIVILEGED), !!(self->flags & AFFILE_PIPE), fd))
 
126
    return TRUE;
 
127
  return FALSE;
 
128
}
 
129
 
 
130
static inline gchar *
 
131
affile_sd_format_persist_name(AFFileSourceDriver *self)
 
132
{
 
133
  static gchar persist_name[1024];
 
134
  
 
135
  g_snprintf(persist_name, sizeof(persist_name), "affile_sd_curpos(%s)", self->filename->str);
 
136
  return persist_name;
 
137
}
 
138
 
 
139
static void
 
140
affile_sd_recover_state(LogPipe *s, GlobalConfig *cfg, LogProto *proto)
 
141
{
 
142
  AFFileSourceDriver *self = (AFFileSourceDriver *) s;
 
143
 
 
144
  if ((self->flags & AFFILE_PIPE) || self->reader_options.follow_freq <= 0)
 
145
    return;
 
146
 
 
147
  if (!log_proto_restart_with_state(proto, cfg->state, affile_sd_format_persist_name(self)))
 
148
    {
 
149
      msg_error("Error converting persistent state from on-disk format, losing file position information",
 
150
                evt_tag_str("filename", self->filename->str),
 
151
                NULL);
 
152
      return;
 
153
    }
 
154
}
 
155
 
 
156
static LogProto *
 
157
affile_sd_construct_proto(AFFileSourceDriver *self, LogTransport *transport)
 
158
{
 
159
  guint flags;
 
160
  LogProto *proto;
 
161
  MsgFormatHandler *handler;
 
162
 
 
163
  flags =
 
164
    ((self->reader_options.follow_freq > 0)
 
165
     ? LPBS_IGNORE_EOF | LPBS_POS_TRACKING
 
166
     : LPBS_NOMREAD);
 
167
 
 
168
  handler = self->reader_options.parse_options.format_handler;
 
169
  if ((handler && handler->construct_proto))
 
170
    proto = self->reader_options.parse_options.format_handler->construct_proto(&self->reader_options.parse_options, transport, flags);
 
171
  else if (self->reader_options.padding)
 
172
    proto = log_proto_record_server_new(transport, self->reader_options.padding, flags);
 
173
  else
 
174
    proto = log_proto_text_server_new(transport, self->reader_options.msg_size, flags);
 
175
 
 
176
  return proto;
 
177
}
 
178
 
 
179
/* NOTE: runs in the main thread */
 
180
static void
 
181
affile_sd_notify(LogPipe *s, LogPipe *sender, gint notify_code, gpointer user_data)
 
182
{
 
183
  AFFileSourceDriver *self = (AFFileSourceDriver *) s;
 
184
  GlobalConfig *cfg = log_pipe_get_config(s);
 
185
  gint fd;
 
186
  
 
187
  switch (notify_code)
 
188
    {
 
189
    case NC_FILE_MOVED:
 
190
      { 
 
191
        msg_verbose("Follow-mode file source moved, tracking of the new file is started",
 
192
                    evt_tag_str("filename", self->filename->str),
 
193
                    NULL);
 
194
        
 
195
        log_pipe_deinit(self->reader);
 
196
        log_pipe_unref(self->reader);
 
197
        
 
198
        if (affile_sd_open_file(self, self->filename->str, &fd))
 
199
          {
 
200
            LogTransport *transport;
 
201
            LogProto *proto;
 
202
            
 
203
            transport = log_transport_plain_new(fd, 0);
 
204
            transport->timeout = 10;
 
205
 
 
206
            proto = affile_sd_construct_proto(self, transport);
 
207
 
 
208
            self->reader = log_reader_new(proto);
 
209
 
 
210
            log_reader_set_options(self->reader, s, &self->reader_options, 1, SCS_FILE, self->super.super.id, self->filename->str);
 
211
            log_reader_set_follow_filename(self->reader, self->filename->str);
 
212
            log_reader_set_immediate_check(self->reader);
 
213
 
 
214
            log_pipe_append(self->reader, s);
 
215
            if (!log_pipe_init(self->reader, cfg))
 
216
              {
 
217
                msg_error("Error initializing log_reader, closing fd",
 
218
                          evt_tag_int("fd", fd),
 
219
                          NULL);
 
220
                log_pipe_unref(self->reader);
 
221
                self->reader = NULL;
 
222
                close(fd);
 
223
              }
 
224
            affile_sd_recover_state(s, cfg, proto);
 
225
          }
 
226
        else
 
227
          {
 
228
            self->reader = NULL;
 
229
          }
 
230
        break;
 
231
      }
 
232
    default:
 
233
      break;
 
234
    }
 
235
}
 
236
 
 
237
static void
 
238
affile_sd_queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options, gpointer user_data)
 
239
{
 
240
  AFFileSourceDriver *self = (AFFileSourceDriver *) s;
 
241
  static NVHandle filename_handle = 0;
 
242
 
 
243
  if (!filename_handle)
 
244
    filename_handle = log_msg_get_value_handle("FILE_NAME");
 
245
  
 
246
  log_msg_set_value(msg, filename_handle, self->filename->str, self->filename->len);
 
247
 
 
248
  log_pipe_forward_msg(s, msg, path_options);
 
249
}
 
250
 
 
251
static gboolean
 
252
affile_sd_init(LogPipe *s)
 
253
{
 
254
  AFFileSourceDriver *self = (AFFileSourceDriver *) s;
 
255
  GlobalConfig *cfg = log_pipe_get_config(s);
 
256
  gint fd;
 
257
  gboolean file_opened, open_deferred = FALSE;
 
258
 
 
259
  if (!log_src_driver_init_method(s))
 
260
    return FALSE;
 
261
 
 
262
  log_reader_options_init(&self->reader_options, cfg, self->super.super.group);
 
263
 
 
264
  file_opened = affile_sd_open_file(self, self->filename->str, &fd);
 
265
  if (!file_opened && self->reader_options.follow_freq > 0)
 
266
    {
 
267
      msg_info("Follow-mode file source not found, deferring open",
 
268
               evt_tag_str("filename", self->filename->str),
 
269
               NULL);
 
270
      open_deferred = TRUE;
 
271
      fd = -1;
 
272
    }
 
273
 
 
274
  if (file_opened || open_deferred)
 
275
    {
 
276
      LogTransport *transport;
 
277
      LogProto *proto;
 
278
 
 
279
      transport = log_transport_plain_new(fd, 0);
 
280
      transport->timeout = 10;
 
281
 
 
282
      proto = affile_sd_construct_proto(self, transport);
 
283
      /* FIXME: we shouldn't use reader_options to store log protocol parameters */
 
284
      self->reader = log_reader_new(proto);
 
285
 
 
286
      log_reader_set_options(self->reader, s, &self->reader_options, 1, SCS_FILE, self->super.super.id, self->filename->str);
 
287
      log_reader_set_follow_filename(self->reader, self->filename->str);
 
288
 
 
289
      /* NOTE: if the file could not be opened, we ignore the last
 
290
       * remembered file position, if the file is created in the future
 
291
       * we're going to read from the start. */
 
292
      
 
293
      log_pipe_append(self->reader, s);
 
294
 
 
295
      if (!log_pipe_init(self->reader, NULL))
 
296
        {
 
297
          msg_error("Error initializing log_reader, closing fd",
 
298
                    evt_tag_int("fd", fd),
 
299
                    NULL);
 
300
          log_pipe_unref(self->reader);
 
301
          self->reader = NULL;
 
302
          close(fd);
 
303
          return FALSE;
 
304
        }
 
305
      affile_sd_recover_state(s, cfg, proto);
 
306
    }
 
307
  else
 
308
    {
 
309
      msg_error("Error opening file for reading",
 
310
                evt_tag_str("filename", self->filename->str),
 
311
                evt_tag_errno(EVT_TAG_OSERROR, errno),
 
312
                NULL);
 
313
      return self->super.super.optional;
 
314
    }
 
315
  return TRUE;
 
316
 
 
317
}
 
318
 
 
319
static gboolean
 
320
affile_sd_deinit(LogPipe *s)
 
321
{
 
322
  AFFileSourceDriver *self = (AFFileSourceDriver *) s;
 
323
 
 
324
  if (self->reader)
 
325
    {
 
326
      log_pipe_deinit(self->reader);
 
327
      log_pipe_unref(self->reader);
 
328
      self->reader = NULL;
 
329
    }
 
330
 
 
331
  if (!log_src_driver_deinit_method(s))
 
332
    return FALSE;
 
333
 
 
334
  return TRUE;
 
335
}
 
336
 
 
337
static void
 
338
affile_sd_free(LogPipe *s)
 
339
{
 
340
  AFFileSourceDriver *self = (AFFileSourceDriver *) s;
 
341
 
 
342
  g_string_free(self->filename, TRUE);
 
343
  g_assert(!self->reader);
 
344
 
 
345
  log_reader_options_destroy(&self->reader_options);
 
346
 
 
347
  log_src_driver_free(s);
 
348
}
 
349
 
 
350
LogDriver *
 
351
affile_sd_new(gchar *filename, guint32 flags)
 
352
{
 
353
  AFFileSourceDriver *self = g_new0(AFFileSourceDriver, 1);
 
354
  
 
355
  log_src_driver_init_instance(&self->super);
 
356
  self->filename = g_string_new(filename);
 
357
  self->flags = flags;
 
358
  self->super.super.super.init = affile_sd_init;
 
359
  self->super.super.super.queue = affile_sd_queue;
 
360
  self->super.super.super.deinit = affile_sd_deinit;
 
361
  self->super.super.super.notify = affile_sd_notify;
 
362
  self->super.super.super.free_fn = affile_sd_free;
 
363
  log_reader_options_defaults(&self->reader_options);
 
364
  self->reader_options.parse_options.flags |= LP_LOCAL;
 
365
 
 
366
  if ((self->flags & AFFILE_PIPE))
 
367
    {
 
368
      static gboolean warned = FALSE;
 
369
 
 
370
      if (configuration && configuration->version < 0x0302)
 
371
        {
 
372
          if (!warned)
 
373
            {
 
374
              msg_warning("WARNING: the expected message format is being changed for pipe() to improve "
 
375
                          "syslogd compatibity with syslog-ng 3.2. If you are using custom "
 
376
                          "applications which bypass the syslog() API, you might "
 
377
                          "need the 'expect-hostname' flag to get the old behaviour back", NULL);
 
378
              warned = TRUE;
 
379
            }
 
380
        }
 
381
      else
 
382
        {
 
383
          self->reader_options.parse_options.flags &= ~LP_EXPECT_HOSTNAME;
 
384
        }
 
385
    }
 
386
  
 
387
  if (configuration && configuration->version < 0x0300)
 
388
    {
 
389
      static gboolean warned = FALSE;
 
390
      
 
391
      if (!warned)
 
392
        {
 
393
          msg_warning("WARNING: file source: default value of follow_freq in file sources is changing in 3.0 to '1' for all files except /proc/kmsg",
 
394
                      NULL);
 
395
          warned = TRUE;
 
396
        }
 
397
    }
 
398
  else
 
399
    {
 
400
      if ((self->flags & AFFILE_PIPE) == 0)
 
401
        {
 
402
          if (0 ||
 
403
#if __linux__
 
404
              (strcmp(filename, "/proc/kmsg") == 0) ||
 
405
#elif __FreeBSD__
 
406
              (strcmp(filename, "/dev/klog") == 0) ||
 
407
#endif
 
408
               0)
 
409
            {
 
410
              self->reader_options.follow_freq = 0;
 
411
            }
 
412
          else
 
413
            {
 
414
              self->reader_options.follow_freq = 1000;
 
415
            }
 
416
        }
 
417
    }
 
418
#if __linux__
 
419
  if (strcmp(filename, "/proc/kmsg") == 0)
 
420
    {
 
421
      self->flags |= AFFILE_PRIVILEGED;
 
422
    }
 
423
#endif
 
424
  return &self->super.super;
 
425
}
 
426
 
 
427
/*
 
428
 * Threading notes:
 
429
 *
 
430
 * Apart from standard initialization/deinitialization (normally performed
 
431
 * by the main thread when syslog-ng starts up) the following processes are
 
432
 * performed in various threads.
 
433
 *
 
434
 *   - queue runs in the thread of the source thread that generated the message
 
435
 *   - if the message is to be written to a not-yet-opened file, a new gets
 
436
 *     opened and stored in the writer_hash hashtable (initiated from queue,
 
437
 *     but performed in the main thread, but more on that later)
 
438
 *   - currently opened destination files are checked regularly and closed
 
439
 *     if they are idle for a given amount of time (time_reap) (this is done
 
440
 *     in the main thread)
 
441
 *
 
442
 * Some of these operations have to be performed in the main thread, others
 
443
 * are done in the queue call.
 
444
 *
 
445
 * References
 
446
 * ==========
 
447
 *
 
448
 * The AFFileDestDriver instance is registered into the current
 
449
 * configuration, thus its presence is always given, it cannot go away while
 
450
 * syslog-ng is running.
 
451
 *
 
452
 * AFFileDestWriter instances are created dynamically when a new file is
 
453
 * opened. A reference is stored in the writer_hash hashtable. This is then:
 
454
 *    - looked up in _queue() (in the source thread)
 
455
 *    - cleaned up in reap callback (in the main thread)
 
456
 *
 
457
 * writer_hash is locked (currently a simple mutex) using
 
458
 * AFFileDestDriver->lock.  The "queue" method cannot hold the lock while
 
459
 * forwarding it to the next pipe, thus a reference is taken under the
 
460
 * protection of the lock, keeping a the next pipe alive, even if that would
 
461
 * go away in a parallel reaper process.
 
462
 */
 
463
 
 
464
struct _AFFileDestWriter
 
465
{
 
466
  LogPipe super;
 
467
  GStaticMutex lock;
 
468
  AFFileDestDriver *owner;
 
469
  gchar *filename;
 
470
  LogPipe *writer;
 
471
  time_t last_msg_stamp;
 
472
  time_t last_open_stamp;
 
473
  time_t time_reopen;
 
474
  struct iv_timer reap_timer;
 
475
  gboolean reopen_pending, queue_pending;
 
476
};
 
477
 
 
478
static void affile_dd_reap_writer(AFFileDestDriver *self, AFFileDestWriter *dw);
 
479
 
 
480
static void
 
481
affile_dw_arm_reaper(AFFileDestWriter *self)
 
482
{
 
483
  /* not yet reaped, set up the next callback */
 
484
  iv_validate_now();
 
485
  self->reap_timer.expires = iv_now;
 
486
  timespec_add_msec(&self->reap_timer.expires, self->owner->time_reap * 1000 / 2);
 
487
  iv_timer_register(&self->reap_timer);
 
488
}
 
489
 
 
490
static void
 
491
affile_dw_reap(gpointer s)
 
492
{
 
493
  AFFileDestWriter *self = (AFFileDestWriter *) s;
 
494
 
 
495
  main_loop_assert_main_thread();
 
496
 
 
497
  g_static_mutex_lock(&self->lock);
 
498
  if (!log_writer_has_pending_writes((LogWriter *) self->writer) &&
 
499
      !self->queue_pending &&
 
500
      (cached_g_current_time_sec() - self->last_msg_stamp) >= self->owner->time_reap)
 
501
    {
 
502
      g_static_mutex_unlock(&self->lock);
 
503
      msg_verbose("Destination timed out, reaping",
 
504
                  evt_tag_str("template", self->owner->filename_template->template),
 
505
                  evt_tag_str("filename", self->filename),
 
506
                  NULL);
 
507
      affile_dd_reap_writer(self->owner, self);
 
508
    }
 
509
  else
 
510
    {
 
511
      g_static_mutex_unlock(&self->lock);
 
512
      affile_dw_arm_reaper(self);
 
513
    }
 
514
}
 
515
 
 
516
static gboolean
 
517
affile_dw_reopen(AFFileDestWriter *self)
 
518
{
 
519
  int fd, flags;
 
520
  struct stat st;
 
521
 
 
522
  self->last_open_stamp = self->last_msg_stamp;
 
523
  if (self->owner->overwrite_if_older > 0 && 
 
524
      stat(self->filename, &st) == 0 &&
 
525
      st.st_mtime < time(NULL) - self->owner->overwrite_if_older)
 
526
    {
 
527
      msg_info("Destination file is older than overwrite_if_older(), overwriting",
 
528
                 evt_tag_str("filename", self->filename),
 
529
                 evt_tag_int("overwrite_if_older", self->owner->overwrite_if_older),
 
530
                 NULL);
 
531
      unlink(self->filename);
 
532
    }
 
533
 
 
534
  if (self->owner->flags & AFFILE_PIPE)
 
535
    flags = O_RDWR | O_NOCTTY | O_NONBLOCK | O_LARGEFILE;
 
536
  else
 
537
    flags = O_WRONLY | O_CREAT | O_NOCTTY | O_NONBLOCK | O_LARGEFILE;
 
538
 
 
539
 
 
540
  if (affile_open_file(self->filename, flags,
 
541
                       self->owner->file_uid, self->owner->file_gid, self->owner->file_perm, 
 
542
                       self->owner->dir_uid, self->owner->dir_gid, self->owner->dir_perm, 
 
543
                       !!(self->owner->flags & AFFILE_CREATE_DIRS), FALSE, !!(self->owner->flags & AFFILE_PIPE), &fd))
 
544
    {
 
545
      guint write_flags;
 
546
      
 
547
      write_flags =
 
548
        ((self->owner->flags & AFFILE_PIPE) ? LTF_PIPE : LTF_APPEND) |
 
549
        ((self->owner->flags & AFFILE_FSYNC) ? LTF_FSYNC : 0);
 
550
      log_writer_reopen(self->writer,
 
551
                        self->owner->flags & AFFILE_PIPE
 
552
                        ? log_proto_text_client_new(log_transport_plain_new(fd, write_flags))
 
553
                        : log_proto_file_writer_new(log_transport_plain_new(fd, write_flags), self->owner->writer_options.flush_lines));
 
554
 
 
555
      main_loop_call((void * (*)(void *)) affile_dw_arm_reaper, self, TRUE);
 
556
    }
 
557
  else
 
558
    {
 
559
      msg_error("Error opening file for writing",
 
560
                evt_tag_str("filename", self->filename),
 
561
                evt_tag_errno(EVT_TAG_OSERROR, errno),
 
562
                NULL);
 
563
      return self->owner->super.super.optional;
 
564
    }
 
565
  return TRUE;
 
566
}
 
567
 
 
568
static gboolean
 
569
affile_dw_init(LogPipe *s)
 
570
{
 
571
  AFFileDestWriter *self = (AFFileDestWriter *) s;
 
572
  GlobalConfig *cfg = log_pipe_get_config(s);
 
573
 
 
574
  if (cfg)
 
575
    self->time_reopen = cfg->time_reopen;
 
576
 
 
577
  msg_verbose("Initializing destination file writer",
 
578
              evt_tag_str("template", self->owner->filename_template->template),
 
579
              evt_tag_str("filename", self->filename),
 
580
              NULL);
 
581
 
 
582
  if (!self->writer)
 
583
    {
 
584
      guint32 flags;
 
585
 
 
586
      flags = LW_FORMAT_FILE |
 
587
        ((self->owner->flags & AFFILE_PIPE) ? 0 : LW_SOFT_FLOW_CONTROL);
 
588
 
 
589
      self->writer = log_writer_new(flags);
 
590
    }
 
591
  log_writer_set_options((LogWriter *) self->writer, s, &self->owner->writer_options, 1,
 
592
                         self->owner->flags & AFFILE_PIPE ? SCS_PIPE : SCS_FILE,
 
593
                         self->owner->super.super.id, self->filename);
 
594
  log_writer_set_queue(self->writer, log_dest_driver_acquire_queue(&self->owner->super, NULL));
 
595
 
 
596
  if (!log_pipe_init(self->writer, NULL))
 
597
    {
 
598
      msg_error("Error initializing log writer", NULL);
 
599
      log_pipe_unref(self->writer);
 
600
      self->writer = NULL;
 
601
      return FALSE;
 
602
    }
 
603
  log_pipe_append(&self->super, self->writer);
 
604
 
 
605
  return affile_dw_reopen(self);
 
606
}
 
607
 
 
608
static gboolean
 
609
affile_dw_deinit(LogPipe *s)
 
610
{
 
611
  AFFileDestWriter *self = (AFFileDestWriter *) s;
 
612
 
 
613
  main_loop_assert_main_thread();
 
614
  if (self->writer)
 
615
    {
 
616
      log_pipe_deinit(self->writer);
 
617
    }
 
618
  if (iv_timer_registered(&self->reap_timer))
 
619
    iv_timer_unregister(&self->reap_timer);
 
620
  return TRUE;
 
621
}
 
622
 
 
623
/*
 
624
 * NOTE: the caller (e.g. AFFileDestDriver) holds a reference to @self, thus
 
625
 * @self may _never_ be freed, even if the reaper timer is elapsed in the
 
626
 * main thread.
 
627
 */
 
628
static void
 
629
affile_dw_queue(LogPipe *s, LogMessage *lm, const LogPathOptions *path_options, gpointer user_data)
 
630
{
 
631
  AFFileDestWriter *self = (AFFileDestWriter *) s;
 
632
 
 
633
  g_static_mutex_lock(&self->lock);
 
634
  self->last_msg_stamp = cached_g_current_time_sec();
 
635
  if (self->last_open_stamp == 0)
 
636
    self->last_open_stamp = self->last_msg_stamp;
 
637
 
 
638
  if (!log_writer_opened((LogWriter *) self->writer) &&
 
639
      !self->reopen_pending &&
 
640
      (self->last_open_stamp < self->last_msg_stamp - self->time_reopen))
 
641
    {
 
642
      self->reopen_pending = TRUE;
 
643
      /* if the file couldn't be opened, try it again every time_reopen seconds */
 
644
      g_static_mutex_unlock(&self->lock);
 
645
      affile_dw_reopen(self);
 
646
      g_static_mutex_lock(&self->lock);
 
647
      self->reopen_pending = FALSE;
 
648
    }
 
649
  g_static_mutex_unlock(&self->lock);
 
650
 
 
651
  log_pipe_forward_msg(&self->super, lm, path_options);
 
652
}
 
653
 
 
654
static void
 
655
affile_dw_set_owner(AFFileDestWriter *self, AFFileDestDriver *owner)
 
656
{
 
657
  if (self->owner)
 
658
    log_pipe_unref(&self->owner->super.super.super);
 
659
  log_pipe_ref(&owner->super.super.super);
 
660
  self->owner = owner;
 
661
  if (self->writer)
 
662
    log_writer_set_options((LogWriter *) self->writer, &self->super, &owner->writer_options, 1, SCS_FILE, self->owner->super.super.id, self->filename);
 
663
  
 
664
}
 
665
 
 
666
static void
 
667
affile_dw_free(LogPipe *s)
 
668
{
 
669
  AFFileDestWriter *self = (AFFileDestWriter *) s;
 
670
  
 
671
  log_pipe_unref(self->writer);
 
672
  self->writer = NULL;
 
673
  g_free(self->filename);
 
674
  log_pipe_unref(&self->owner->super.super.super);
 
675
  log_pipe_free_method(s);
 
676
}
 
677
 
 
678
static AFFileDestWriter *
 
679
affile_dw_new(AFFileDestDriver *owner, const gchar *filename)
 
680
{
 
681
  AFFileDestWriter *self = g_new0(AFFileDestWriter, 1);
 
682
  
 
683
  log_pipe_init_instance(&self->super);
 
684
 
 
685
  self->super.init = affile_dw_init;
 
686
  self->super.deinit = affile_dw_deinit;
 
687
  self->super.free_fn = affile_dw_free;  
 
688
  self->super.queue = affile_dw_queue;
 
689
  log_pipe_ref(&owner->super.super.super);
 
690
  self->owner = owner;
 
691
  self->time_reopen = 60;
 
692
 
 
693
  IV_TIMER_INIT(&self->reap_timer);
 
694
  self->reap_timer.cookie = self;
 
695
  self->reap_timer.handler = affile_dw_reap;
 
696
 
 
697
  /* we have to take care about freeing filename later. 
 
698
     This avoids a move of the filename. */
 
699
  self->filename = g_strdup(filename);
 
700
  g_static_mutex_init(&self->lock);
 
701
  return self;
 
702
}
 
703
 
 
704
void 
 
705
affile_dd_set_file_uid(LogDriver *s, const gchar *file_uid)
 
706
{
 
707
  AFFileDestDriver *self = (AFFileDestDriver *) s;
 
708
  
 
709
  self->file_uid = 0;
 
710
  if (!resolve_user(file_uid, &self->file_uid))
 
711
    {
 
712
      msg_error("Error resolving user",
 
713
                 evt_tag_str("user", file_uid),
 
714
                 NULL);
 
715
    }
 
716
}
 
717
 
 
718
void 
 
719
affile_dd_set_file_gid(LogDriver *s, const gchar *file_gid)
 
720
{
 
721
  AFFileDestDriver *self = (AFFileDestDriver *) s;
 
722
  
 
723
  self->file_gid = 0;
 
724
  if (!resolve_group(file_gid, &self->file_gid))
 
725
    {
 
726
      msg_error("Error resolving group",
 
727
                 evt_tag_str("group", file_gid),
 
728
                 NULL);
 
729
    }
 
730
}
 
731
 
 
732
void 
 
733
affile_dd_set_file_perm(LogDriver *s, gint file_perm)
 
734
{
 
735
  AFFileDestDriver *self = (AFFileDestDriver *) s;
 
736
  
 
737
  self->file_perm = file_perm;
 
738
}
 
739
 
 
740
void 
 
741
affile_dd_set_dir_uid(LogDriver *s, const gchar *dir_uid)
 
742
{
 
743
  AFFileDestDriver *self = (AFFileDestDriver *) s;
 
744
  
 
745
  self->dir_uid = 0;
 
746
  if (!resolve_user(dir_uid, &self->dir_uid))
 
747
    {
 
748
      msg_error("Error resolving user",
 
749
                 evt_tag_str("user", dir_uid),
 
750
                 NULL);
 
751
    }
 
752
}
 
753
 
 
754
void 
 
755
affile_dd_set_dir_gid(LogDriver *s, const gchar *dir_gid)
 
756
{
 
757
  AFFileDestDriver *self = (AFFileDestDriver *) s;
 
758
  
 
759
  self->dir_gid = 0;
 
760
  if (!resolve_group(dir_gid, &self->dir_gid))
 
761
    {
 
762
      msg_error("Error resolving group",
 
763
                 evt_tag_str("group", dir_gid),
 
764
                 NULL);
 
765
    }
 
766
}
 
767
 
 
768
void 
 
769
affile_dd_set_dir_perm(LogDriver *s, gint dir_perm)
 
770
{
 
771
  AFFileDestDriver *self = (AFFileDestDriver *) s;
 
772
  
 
773
  self->dir_perm = dir_perm;
 
774
}
 
775
 
 
776
void 
 
777
affile_dd_set_create_dirs(LogDriver *s, gboolean create_dirs)
 
778
{
 
779
  AFFileDestDriver *self = (AFFileDestDriver *) s;
 
780
  
 
781
  if (create_dirs)
 
782
    self->flags |= AFFILE_CREATE_DIRS;
 
783
  else 
 
784
    self->flags &= ~AFFILE_CREATE_DIRS;
 
785
}
 
786
 
 
787
void 
 
788
affile_dd_set_overwrite_if_older(LogDriver *s, gint overwrite_if_older)
 
789
{
 
790
  AFFileDestDriver *self = (AFFileDestDriver *) s;
 
791
  
 
792
  self->overwrite_if_older = overwrite_if_older;
 
793
}
 
794
 
 
795
void 
 
796
affile_dd_set_fsync(LogDriver *s, gboolean fsync)
 
797
{
 
798
  AFFileDestDriver *self = (AFFileDestDriver *) s;
 
799
  if (fsync)
 
800
    self->flags |= AFFILE_FSYNC;
 
801
  else
 
802
    self->flags &= ~AFFILE_FSYNC;
 
803
}
 
804
 
 
805
void
 
806
affile_dd_set_local_time_zone(LogDriver *s, const gchar *local_time_zone)
 
807
{
 
808
  AFFileDestDriver *self = (AFFileDestDriver *) s;
 
809
 
 
810
  self->local_time_zone = g_strdup(local_time_zone);
 
811
}
 
812
 
 
813
static inline gchar *
 
814
affile_dd_format_persist_name(AFFileDestDriver *self)
 
815
{
 
816
  static gchar persist_name[1024];
 
817
 
 
818
  g_snprintf(persist_name, sizeof(persist_name), "affile_dd_writers(%s)", self->filename_template->template);
 
819
  return persist_name;
 
820
}
 
821
 
 
822
static void
 
823
affile_dd_reap_writer(AFFileDestDriver *self, AFFileDestWriter *dw)
 
824
{
 
825
  main_loop_assert_main_thread();
 
826
  
 
827
  if ((self->flags & AFFILE_NO_EXPAND) == 0)
 
828
    {
 
829
      g_static_mutex_lock(&self->lock);
 
830
      /* remove from hash table */
 
831
      g_hash_table_remove(self->writer_hash, dw->filename);
 
832
      g_static_mutex_unlock(&self->lock);
 
833
    }
 
834
  else
 
835
    {
 
836
      g_static_mutex_lock(&self->lock);
 
837
      g_assert(dw == self->single_writer);
 
838
      self->single_writer = NULL;
 
839
      g_static_mutex_unlock(&self->lock);
 
840
    }
 
841
 
 
842
  log_pipe_deinit(&dw->super);
 
843
  log_pipe_unref(&dw->super);
 
844
}
 
845
 
 
846
 
 
847
/**
 
848
 * affile_dd_reuse_writer:
 
849
 *
 
850
 * This function is called as a g_hash_table_foreach() callback to set the
 
851
 * owner of each writer, previously connected to an AFileDestDriver instance
 
852
 * in an earlier configuration. This way AFFileDestWriter instances are
 
853
 * remembered accross reloads.
 
854
 * 
 
855
 **/
 
856
static void
 
857
affile_dd_reuse_writer(gpointer key, gpointer value, gpointer user_data)
 
858
{
 
859
  AFFileDestDriver *self = (AFFileDestDriver *) user_data;
 
860
  AFFileDestWriter *writer = (AFFileDestWriter *) value;
 
861
  
 
862
  affile_dw_set_owner(writer, self);
 
863
  log_pipe_init(&writer->super, NULL);
 
864
}
 
865
 
 
866
 
 
867
static gboolean
 
868
affile_dd_init(LogPipe *s)
 
869
{
 
870
  AFFileDestDriver *self = (AFFileDestDriver *) s;
 
871
  GlobalConfig *cfg = log_pipe_get_config(s);
 
872
 
 
873
  if (!log_dest_driver_init_method(s))
 
874
    return FALSE;
 
875
 
 
876
  if (cfg->create_dirs)
 
877
    self->flags |= AFFILE_CREATE_DIRS;
 
878
  if (self->file_uid == -1)
 
879
    self->file_uid = cfg->file_uid;
 
880
  if (self->file_gid == -1)
 
881
    self->file_gid = cfg->file_gid;
 
882
  if (self->file_perm == -1)
 
883
    self->file_perm = cfg->file_perm;
 
884
  if (self->dir_uid == -1)
 
885
    self->dir_uid = cfg->dir_uid;
 
886
  if (self->dir_gid == -1)
 
887
    self->dir_gid = cfg->dir_gid;
 
888
  if (self->dir_perm == -1)
 
889
    self->dir_perm = cfg->dir_perm;
 
890
  if (self->time_reap == -1)
 
891
    self->time_reap = cfg->time_reap;
 
892
  
 
893
  log_writer_options_init(&self->writer_options, cfg, 0);
 
894
  log_template_options_init(&self->template_fname_options, cfg);
 
895
              
 
896
  if ((self->flags & AFFILE_NO_EXPAND) == 0)
 
897
    {
 
898
      self->writer_hash = cfg_persist_config_fetch(cfg, affile_dd_format_persist_name(self));
 
899
      if (self->writer_hash)
 
900
        g_hash_table_foreach(self->writer_hash, affile_dd_reuse_writer, self);
 
901
    }
 
902
  else
 
903
    {
 
904
      self->single_writer = cfg_persist_config_fetch(cfg, affile_dd_format_persist_name(self));
 
905
      if (self->single_writer)
 
906
        {
 
907
          affile_dw_set_owner(self->single_writer, self);
 
908
          log_pipe_init(&self->single_writer->super, cfg);
 
909
        }
 
910
    }
 
911
  
 
912
  
 
913
  return TRUE;
 
914
}
 
915
 
 
916
 
 
917
/**
 
918
 * This is registered as a destroy-notify callback for an AFFileDestWriter
 
919
 * instance. It destructs and frees the writer instance.
 
920
 **/
 
921
static void
 
922
affile_dd_destroy_writer(gpointer value)
 
923
{
 
924
  AFFileDestWriter *writer = (AFFileDestWriter *) value;
 
925
 
 
926
  main_loop_assert_main_thread();
 
927
  log_pipe_deinit(&writer->super);
 
928
  log_pipe_unref(&writer->super);
 
929
}
 
930
 
 
931
/*
 
932
 * This function is called as a g_hash_table_foreach_remove() callback to
 
933
 * free the specific AFFileDestWriter instance in the hashtable.
 
934
 */
 
935
static gboolean
 
936
affile_dd_destroy_writer_hr(gpointer key, gpointer value, gpointer user_data)
 
937
{
 
938
  affile_dd_destroy_writer(value);
 
939
  return TRUE;
 
940
}
 
941
 
 
942
/**
 
943
 * affile_dd_destroy_writer_hash:
 
944
 * @value: GHashTable instance passed as a generic pointer
 
945
 *
 
946
 * Destroy notify callback for the GHashTable storing AFFileDestWriter instances.
 
947
 **/
 
948
static void
 
949
affile_dd_destroy_writer_hash(gpointer value)
 
950
{
 
951
  GHashTable *writer_hash = (GHashTable *) value;
 
952
  
 
953
  g_hash_table_foreach_remove(writer_hash, affile_dd_destroy_writer_hr, NULL);
 
954
  g_hash_table_destroy(writer_hash);
 
955
}
 
956
 
 
957
static void
 
958
affile_dd_deinit_writer(gpointer key, gpointer value, gpointer user_data)
 
959
{
 
960
  log_pipe_deinit((LogPipe *) value);
 
961
}
 
962
 
 
963
static gboolean
 
964
affile_dd_deinit(LogPipe *s)
 
965
{
 
966
  AFFileDestDriver *self = (AFFileDestDriver *) s;
 
967
  GlobalConfig *cfg = log_pipe_get_config(s);
 
968
  /* NOTE: we free all AFFileDestWriter instances here as otherwise we'd
 
969
   * have circular references between AFFileDestDriver and file writers */
 
970
  if (self->single_writer)
 
971
    {
 
972
      g_assert(self->writer_hash == NULL);
 
973
 
 
974
      log_pipe_deinit(&self->single_writer->super);
 
975
      cfg_persist_config_add(cfg, affile_dd_format_persist_name(self), self->single_writer, affile_dd_destroy_writer, FALSE);
 
976
      self->single_writer = NULL;
 
977
    }
 
978
  else if (self->writer_hash)
 
979
    {
 
980
      g_assert(self->single_writer == NULL);
 
981
      
 
982
      g_hash_table_foreach(self->writer_hash, affile_dd_deinit_writer, NULL);
 
983
      cfg_persist_config_add(cfg, affile_dd_format_persist_name(self), self->writer_hash, affile_dd_destroy_writer_hash, FALSE);
 
984
      self->writer_hash = NULL;
 
985
    }
 
986
 
 
987
  if (!log_dest_driver_deinit_method(s))
 
988
    return FALSE;
 
989
 
 
990
  return TRUE;
 
991
}
 
992
 
 
993
/*
 
994
 * This function is ran in the main thread whenever a writer is not yet
 
995
 * instantiated.  Returns a reference to the newly constructed LogPipe
 
996
 * instance where the caller needs to forward its message.
 
997
 */
 
998
static LogPipe *
 
999
affile_dd_open_writer(gpointer args[])
 
1000
{
 
1001
  AFFileDestDriver *self = args[0];
 
1002
  GlobalConfig *cfg = log_pipe_get_config(&self->super.super.super);
 
1003
  AFFileDestWriter *next;
 
1004
 
 
1005
  main_loop_assert_main_thread();
 
1006
  if (self->flags & AFFILE_NO_EXPAND)
 
1007
    {
 
1008
      if (!self->single_writer)
 
1009
        {
 
1010
          next = affile_dw_new(self, self->filename_template->template);
 
1011
          if (next && log_pipe_init(&next->super, cfg))
 
1012
            {
 
1013
              log_pipe_ref(&next->super);
 
1014
              g_static_mutex_lock(&self->lock);
 
1015
              self->single_writer = next;
 
1016
              g_static_mutex_unlock(&self->lock);
 
1017
            }
 
1018
          else
 
1019
            {
 
1020
              log_pipe_unref(&next->super);
 
1021
              next = NULL;
 
1022
            }
 
1023
        }
 
1024
      else
 
1025
        {
 
1026
          next = self->single_writer;
 
1027
          log_pipe_ref(&next->super);
 
1028
        }
 
1029
    }
 
1030
  else
 
1031
    {
 
1032
      GString *filename = args[1];
 
1033
 
 
1034
      /* hash table construction is serialized, as we only do that in the main thread. */
 
1035
      if (!self->writer_hash)
 
1036
        self->writer_hash = g_hash_table_new(g_str_hash, g_str_equal);
 
1037
 
 
1038
      /* we don't need to lock the hashtable as it is only written in
 
1039
       * the main thread, which we're running right now.  lookups in
 
1040
       * other threads must be locked. writers must be locked even in
 
1041
       * this thread to exclude lookups in other threads.  */
 
1042
 
 
1043
      next = g_hash_table_lookup(self->writer_hash, filename->str);
 
1044
      if (!next)
 
1045
        {
 
1046
          next = affile_dw_new(self, filename->str);
 
1047
          if (!log_pipe_init(&next->super, cfg))
 
1048
            {
 
1049
              log_pipe_unref(&next->super);
 
1050
              next = NULL;
 
1051
            }
 
1052
          else
 
1053
            {
 
1054
              log_pipe_ref(&next->super);
 
1055
              g_static_mutex_lock(&self->lock);
 
1056
              g_hash_table_insert(self->writer_hash, next->filename, next);
 
1057
              g_static_mutex_unlock(&self->lock);
 
1058
            }
 
1059
        }
 
1060
      else
 
1061
        {
 
1062
          log_pipe_ref(&next->super);
 
1063
        }
 
1064
    }
 
1065
 
 
1066
  if (next)
 
1067
    {
 
1068
      next->queue_pending = TRUE;
 
1069
      /* we're returning a reference */
 
1070
      return &next->super;
 
1071
    }
 
1072
  return NULL;
 
1073
}
 
1074
 
 
1075
static void
 
1076
affile_dd_queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options, gpointer user_data)
 
1077
{
 
1078
  AFFileDestDriver *self = (AFFileDestDriver *) s;
 
1079
  AFFileDestWriter *next;
 
1080
  gpointer args[2] = { self, NULL };
 
1081
 
 
1082
  if (self->flags & AFFILE_NO_EXPAND)
 
1083
    {
 
1084
      /* no need to lock the check below, the worst case that happens is
 
1085
       * that we go to the mainloop to return the same information, but this
 
1086
       * is not fast path anyway */
 
1087
 
 
1088
      g_static_mutex_lock(&self->lock);
 
1089
      if (!self->single_writer)
 
1090
        {
 
1091
          g_static_mutex_unlock(&self->lock);
 
1092
          next = main_loop_call((void *(*)(void *)) affile_dd_open_writer, args, TRUE);
 
1093
        }
 
1094
      else
 
1095
        {
 
1096
          /* we need to lock single_writer in order to get a reference and
 
1097
           * make sure it is not a stale pointer by the time we ref it */
 
1098
          next = self->single_writer;
 
1099
          next->queue_pending = TRUE;
 
1100
          log_pipe_ref(&next->super);
 
1101
          g_static_mutex_unlock(&self->lock);
 
1102
        }
 
1103
    }
 
1104
  else
 
1105
    {
 
1106
      GString *filename;
 
1107
 
 
1108
      filename = g_string_sized_new(32);
 
1109
      log_template_format(self->filename_template, msg, &self->template_fname_options, LTZ_LOCAL, 0, NULL, filename);
 
1110
 
 
1111
      g_static_mutex_lock(&self->lock);
 
1112
      if (self->writer_hash)
 
1113
        next = g_hash_table_lookup(self->writer_hash, filename->str);
 
1114
      else
 
1115
        next = NULL;
 
1116
 
 
1117
      if (next)
 
1118
        {
 
1119
          log_pipe_ref(&next->super);
 
1120
          next->queue_pending = TRUE;
 
1121
          g_static_mutex_unlock(&self->lock);
 
1122
        }
 
1123
      else
 
1124
        {
 
1125
          g_static_mutex_unlock(&self->lock);
 
1126
          args[1] = filename;
 
1127
          next = main_loop_call((void *(*)(void *)) affile_dd_open_writer, args, TRUE);
 
1128
        }
 
1129
      g_string_free(filename, TRUE);
 
1130
    }
 
1131
  if (next)
 
1132
    {
 
1133
      log_pipe_queue(&next->super, msg, path_options);
 
1134
      next->queue_pending = FALSE;
 
1135
      log_pipe_unref(&next->super);
 
1136
    }
 
1137
  else
 
1138
    log_msg_drop(msg, path_options);
 
1139
}
 
1140
 
 
1141
static void
 
1142
affile_dd_free(LogPipe *s)
 
1143
{
 
1144
  AFFileDestDriver *self = (AFFileDestDriver *) s;
 
1145
  
 
1146
  /* NOTE: this must be NULL as deinit has freed it, otherwise we'd have circular references */
 
1147
  g_assert(self->single_writer == NULL && self->writer_hash == NULL);
 
1148
 
 
1149
  log_template_options_destroy(&self->template_fname_options);
 
1150
  log_template_unref(self->filename_template);
 
1151
  log_writer_options_destroy(&self->writer_options);
 
1152
  log_dest_driver_free(s);
 
1153
}
 
1154
 
 
1155
LogDriver *
 
1156
affile_dd_new(gchar *filename, guint32 flags)
 
1157
{
 
1158
  AFFileDestDriver *self = g_new0(AFFileDestDriver, 1);
 
1159
 
 
1160
  log_dest_driver_init_instance(&self->super);
 
1161
  self->super.super.super.init = affile_dd_init;
 
1162
  self->super.super.super.deinit = affile_dd_deinit;
 
1163
  self->super.super.super.queue = affile_dd_queue;
 
1164
  self->super.super.super.free_fn = affile_dd_free;
 
1165
  self->filename_template = log_template_new(configuration, NULL);
 
1166
  log_template_compile(self->filename_template, filename, NULL);
 
1167
  self->flags = flags;
 
1168
  self->file_uid = self->file_gid = -1;
 
1169
  self->file_perm = -1;
 
1170
  self->dir_uid = self->dir_gid = -1;
 
1171
  self->dir_perm = -1;
 
1172
  log_writer_options_defaults(&self->writer_options);
 
1173
  if (strchr(filename, '$') == NULL)
 
1174
    {
 
1175
      self->flags |= AFFILE_NO_EXPAND;
 
1176
    }
 
1177
  self->time_reap = -1;
 
1178
  log_template_options_defaults(&self->template_fname_options);
 
1179
  g_static_mutex_init(&self->lock);
 
1180
  return &self->super.super;
 
1181
}