717d3738008bf846893c114d095e53dd66e025ee
[platform/core/system/dlog.git] / src / logger / logger.c
1 /*
2  * Copyright (c) 2016, Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *              http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #ifndef _GNU_SOURCE
18 #define _GNU_SOURCE
19 #endif
20
21 #include "logger_internal.h"
22 #include "logger_privileges.h"
23
24 #include <metrics.h>
25 #include <getopt.h>
26 #include <dynamic_config.h>
27 #include <qos_defaults.h>
28
29 /**
30  * @addtogroup DLOG_IMPLEMENTATION
31  * @{
32  * @defgroup DLOG_LOGGER Logger
33  * @brief Logger daemon
34  * @details The logger is the core component of the logging framework. It is responsible for collecting, processing and exposing logs.
35  * @{
36  */
37
38 // function prototypes
39 static int initialize_epoll_size(struct epoll_event **events, unsigned *size);
40
41 /** global state when logger is not interrupted by any handled signals */
42 static volatile sig_atomic_t g_logger_run = 1;
43
44 static const int DEFAULT_EPOLL_TIME_MS = 1000;
45
46 static const int DEFAULT_LAZY_POLLING_TOTAL_MS = 0;
47 static const int DEFAULT_LAZY_POLLING_SLEEP_MS = 1000;
48
49 static const int S_TO_MS = 1000;
50 static const int MS_TO_NS = 1000000;
51
52 struct backend_data g_backend = {};
53
54 static bool cond_reader_logger_free(void *ptr, void *user_data)
55 {
56         struct reader_logger *reader = (struct reader_logger *)ptr;
57         struct logger *logger = (struct logger *)user_data;
58         assert(reader);
59         // TODO: This is absurd, why isn't this in the reader_logger_free function?
60         if (reader->common.fd_entity_sink.fd >= 0)
61                 remove_fd_entity(&logger->epoll_common, &reader->common.fd_entity_sink);
62         if (reader->common.fd_entity_source.fd >= 0)
63                 remove_fd_entity(&logger->epoll_common, &reader->common.fd_entity_source);
64         reader_logger_free(reader);
65         return true;
66 }
67
68 // TODO: Consider inlining struct now_t everywhere
69 int get_now(struct now_t *now)
70 {
71         if (clock_gettime(CLOCK_MONOTONIC, &now->mono))
72                 return -errno;
73         if (clock_gettime(CLOCK_REALTIME, &now->real))
74                 return -errno;
75         return 0;
76 }
77
78 void qos_periodic_check(struct logger *server)
79 {
80         struct qos_module *const qos = &server->qos;
81         struct timespec ts_mono;
82         if (clock_gettime(CLOCK_MONOTONIC, &ts_mono))
83                 return;
84
85         if (ts_mono.tv_sec < qos->cancel_limits_at.tv_sec)
86                 return;
87         if (ts_mono.tv_sec == qos->cancel_limits_at.tv_sec
88         &&  ts_mono.tv_nsec < qos->cancel_limits_at.tv_nsec)
89                 return;
90
91         if (metrics_get_total(qos->log_metrics) >= qos->threshold)
92                 qos_apply_limits(qos);
93         else
94                 qos_relax_limits(qos);
95
96         qos_set_next_update_time(qos, ts_mono);
97         metrics_clear(qos->log_metrics);
98 }
99
100 /**
101  * @brief FD limit handler
102  * @details Checks whether the FD limit was reached and leaves logs about it if so
103  * @param[in] server The logger server
104  * @param[in] err errno from the call that failed to create an FD
105  */
106 void check_if_fd_limit_reached(struct logger *server, int err)
107 {
108         assert(server);
109
110         if (err != ENFILE && err != EMFILE)
111                 return;
112
113         printf("ERROR: dlog_logger fd limit reached!\n");
114
115         /* pick one representative buffer to send the log to;
116          * no point spamming all the buffers, especially since
117          * default dlogutil invocations display 3 buffers so
118          * it would appear multiple times */
119         struct log_buffer *const buf = server->buffers[LOG_ID_MAIN];
120         if (!buf)
121                 return;
122
123         struct dlogutil_entry_with_msg entry;
124         create_pipe_message(&entry,
125                 DLOG_FATAL, /* not really FATAL, but since we're at the FD limit
126                              * there are thousands of logging programs so this one
127                              * would likely get lost in the flood since developers
128                              * tend to overuse ERROR (and FATAL is the one above) */
129                 "DLOG",
130                 "\x1b[31m DLOG DAEMON FD LIMIT REACHED \x1b[0m" // make it stand out
131         );
132         struct now_t now;
133         int r = get_now(&now);
134         if (r < 0)
135                 return;
136         set_pipe_message_sent_timestamp((struct pipe_logger_entry *) &entry, &now.mono, &now.real);
137
138         if (buffer_append(&entry.header, buf))
139                 printf("ERROR: not enough memory either, please check platform settings as the daemon is seriously resource-starved!\n");
140 }
141
142 void flush_logfile_timely(struct log_file *file, struct timespec ts, int flush_time)
143 {
144         if (file->buffer.position > 0) {
145                 if (ts.tv_sec - file->buffer.oldest_log.tv_sec +
146                                         (ts.tv_nsec > file->buffer.oldest_log.tv_nsec ? 1 : 0) >
147                                 flush_time)
148                         logfile_flush(file);
149         }
150 }
151
152 void reader_notify_losing_log(const dlogutil_entry_s *le, void *reader_)
153 {
154         struct reader_pipe *reader = (struct reader_pipe *) reader_;
155         assert(le);
156         assert(reader);
157         reader_print_out_single_log(reader, (dlogutil_entry_s *)le);
158 }
159
160 /**
161  * @brief Add reader to log buffer
162  * @details Adds a reader to the log buffers reader list
163  * @param[in] log_buffer The buffer whither to add the reader
164  * @param[in] reader The reader to add to the buffer
165  * @return 0 on success, -ENOMEM on memory allocation error
166  */
167 int add_buffer_reader(struct log_buffer *buffer, struct reader_pipe *reader)
168 {
169         assert(reader);
170         assert(buffer);
171
172         reader->log_storage_reader_ptr = log_storage_new_reader(buffer->log_storage_ptr,
173                         reader->is_dumping, reader->monitor, reader_notify_losing_log, reader);
174
175         if (!reader->log_storage_reader_ptr)
176                 return -ENOMEM;
177
178         return list_add(&buffer->readers_pipe, reader) ? 0 : -ENOMEM;
179 }
180
181 int add_reader_pipe(struct logger *server, struct reader_pipe *reader)
182 {
183         assert(reader);
184         assert(server);
185
186         if (reader->common.fd_entity_sink.fd >= 0) {
187                 /* Readers who write to file have no sink FD entity (or, strictly
188                  * speaking, they do have one but it is not filled) since a file
189                  * is not eligible to be added to epoll. However, the entity primarily
190                  * serves to handle pipes getting clogged mid-write (which cannot
191                  * happen for files) and is not involved in starting a write,
192                  * which is handled by the source FD entity, not sink (and which is
193                  * also done periodically for all readers anyway regardless
194                  * of whether they've been added to epoll or not). The other use
195                  * case for epoll - the one where connection FDs leak for unused
196                  * buffers - is not a problem here because the daemon is not
197                  * supposed to ever stop writing to files. */
198
199                 int r = add_fd_entity(&server->epoll_common, &reader->common.fd_entity_sink);
200                 if (r < 0)
201                         return r;
202         }
203
204         int ret;
205         ret = add_buffer_reader(reader->buf_ptr, reader);
206         if (ret < 0 && reader->common.fd_entity_sink.fd >= 0)
207                 remove_fd_entity(&server->epoll_common, &reader->common.fd_entity_sink);
208
209         return ret;
210 }
211
212 static int add_reader_logger(struct logger *server, struct reader_logger *reader)
213 {
214         assert(reader);
215         assert(server);
216
217         if (reader->common.fd_entity_sink.fd >= 0) {
218                 /* Readers who write to file have no sink FD entity (or, strictly
219                  * speaking, they do have one but it is not filled) since a file
220                  * is not eligible to be added to epoll. However, the entity primarily
221                  * serves to handle pipes getting clogged mid-write (which cannot
222                  * happen for files) and is not involved in starting a write,
223                  * which is handled by the source FD entity, not sink (and which is
224                  * also done periodically for all readers anyway regardless
225                  * of whether they've been added to epoll or not). The other use
226                  * case for epoll - the one where connection FDs leak for unused
227                  * buffers - is not a problem here because the daemon is not
228                  * supposed to ever stop writing to files. */
229
230                 int r = add_fd_entity(&server->epoll_common, &reader->common.fd_entity_sink);
231                 if (r < 0)
232                         return r;
233         }
234
235         int ret;
236
237         assert(reader->common.fd_entity_source.fd >= 0);
238         ret = add_fd_entity(&server->epoll_common, &reader->common.fd_entity_source);
239         if (ret < 0)
240                 goto failure;
241
242         if (!list_add(&server->readers_logger, reader)) {
243                 remove_fd_entity(&server->epoll_common, &reader->common.fd_entity_source);
244                 ret = -ENOMEM;
245                 goto failure;
246         }
247
248         return 0;
249
250 failure:
251         if (reader->common.fd_entity_sink.fd >= 0)
252                 remove_fd_entity(&server->epoll_common, &reader->common.fd_entity_sink);
253
254         return ret;
255 }
256
257 int create_fifo_fds(struct logger *server, int pipe_fd[2], int flags, bool dump)
258 {
259         int ret = get_nonblocking_fifo(pipe_fd, flags);
260         if (ret < 0)
261                 return ret;
262
263         /* Speed up dumping dlogutils by increasing their pipe size,
264          * as otherwise this pipe's size becomes a major bottleneck.
265          *
266          * Continuous connections don't really care if the initial
267          * burst of "historic" logs is slow and the following flow
268          * of logs is just fine with a small pipe. Meanwhile they
269          * live for a long time during which they would take away
270          * from the valuable total pipe size. */
271         if (dump)
272                 if (fcntl(pipe_fd[1], F_SETPIPE_SZ, DUMPING_READER_PIPE_SIZE) < 0) {
273                         /* Ignore; this is just a performance optimisation
274                          * and doesn't affect functionality so while errors
275                          * are worrisome they not a big deal or something
276                          * we can do anything about, at any rate. */
277                 }
278
279         return ret;
280 }
281
282 static int create_logger_subreader_from_dlogutil_line(struct dlogutil_line_params *params)
283 {
284         if (params->file_path) {
285                 int retval = logfile_set_path(&params->file, params->file_path);
286                 if (retval < 0)
287                         return retval;
288
289                 retval = logfile_open(&params->file);
290                 if (retval < 0)
291                         return retval;
292         }
293
294         if (params->buf_id == LOG_ID_INVALID)
295                 return -EINVAL;
296
297         if (params->file.path == NULL)
298                 return -EINVAL;
299
300         struct reader_logger *const reader = g_backend.logger_readers[params->buf_id];
301         if (!reader)
302                 return -ENOENT;
303
304         return reader_logger_add_subreader_file(reader, params->filter, &params->file);
305 }
306
307 static int create_reader_pipe_from_dlogutil_line(struct dlogutil_line_params *params, struct logger *server, struct reader_pipe **rd)
308 {
309         assert(server);
310         assert(rd);
311
312         __attribute__((cleanup(reader_pipe_cleanup))) struct reader_pipe *reader = NULL;
313         int retval;
314
315         if (params->file_path) {
316                 retval = logfile_set_path(&params->file, params->file_path);
317                 if (retval < 0)
318                         return retval;
319
320                 retval = logfile_open(&params->file);
321                 if (retval < 0)
322                         return retval;
323         }
324
325         if (params->buf_id == LOG_ID_INVALID)
326                 return -EINVAL;
327
328         if (params->file.path == NULL)
329                 return -EINVAL;
330
331         retval = reader_pipe_init(&reader, params->buf_id, server, params->filter, &params->file, params->monitor, params->is_dumping);
332         if (retval != 0)
333                 return retval;
334
335         *rd = reader;
336         reader = NULL;
337
338         return 0;
339 }
340
341 /**
342  * @brief Service a socket request
343  * @details Handle a socket request
344  * @param[in] server The logger server
345  * @param[in] wr The writer who sent the request
346  * @param[in] event The event containing the request
347  * @return 0 on success, else -errno
348  */
349 int service_writer_socket(struct logger *server, struct writer *wr, struct epoll_event *event)
350 {
351         int r = 0;
352
353         assert(wr);
354         struct dlog_control_msg *const msg = (struct dlog_control_msg *) wr->buffer;
355
356         assert(event);
357         if (event->events & EPOLLIN)
358                 r = read(wr->fd_entity.fd, wr->buffer + wr->readed, sizeof wr->buffer - wr->readed);
359
360         if ((r == 0 || r == -1) && event->events & EPOLLHUP)
361                 return -EINVAL;
362
363         do {
364                 if (r > 0)
365                         wr->readed += r;
366
367                 /* The socket is SOCK_STREAM (see `listen_fd_create`), so one message
368                  * could be split into chunks returned across multiple read() calls. */
369                 if (wr->readed < sizeof(msg->length)
370                 ||  wr->readed < msg->length)
371                         goto dont_process_yet_and_read_more_data;
372
373                 assert(wr->service_socket);
374                 r = wr->service_socket(server, wr, msg);
375                 if (r <= 0)
376                         return r;
377
378 dont_process_yet_and_read_more_data:
379                 r = read(wr->fd_entity.fd, wr->buffer + wr->readed, sizeof wr->buffer - wr->readed);
380         } while (r > 0 || ((wr->readed >= sizeof(msg->length) && wr->readed >= msg->length)));
381
382         return (r >= 0 || errno == EAGAIN)  ? 0 : r;
383 }
384
385 /**
386  * @brief Service /dev/kmsg
387  * @details Read from the /dev/kmsg device
388  * @param[in] server The logger server
389  * @param[in] wr The writer who sent the request
390  * @param[in] event The relevant event
391  * @return 0 on success, else -errno
392  */
393 int service_writer_kmsg(struct logger *server, struct writer *wr, struct epoll_event *event)
394 {
395         (void) server;
396         if (event->events & EPOLLHUP)
397                 return -EBADF;
398         if (!(event->events & EPOLLIN))
399                 return 0;
400
401         /* The KMSG device returns just 1 log per read() so it is done in a loop.
402          * In theory this could starve everything else out if logs appeared faster
403          * than the daemon could process them, which would then necessitate some
404          * sort of throttling. In practice, KMSG doesn't really get flooded with
405          * logs the same way Android Logger devices are so the throttling is mostly
406          * there because we get it for free anyway and consistency doesn't hurt. */
407
408         int max_loop_iterations = g_backend.logger_device_throttling[LOG_ID_KMSG];
409         while (max_loop_iterations--) {
410                 int r = read(wr->fd_entity.fd, wr->buffer, sizeof wr->buffer - 1);
411
412                 if (r == -1 && (errno == EAGAIN || errno == EPIPE))
413                         return 0;
414                 else if ((r == 0 || r == -1) && event->events & EPOLLHUP)
415                         return -EINVAL;
416                 else if (r == 0)
417                         return -EBADF;
418                 else if (r == -1)
419                         return -errno;
420
421                 wr->buffer[r] = '\0';
422                 struct dlogutil_entry_with_msg lem;
423                 if (parse_kmsg_message(wr->buffer, &lem, r)) {
424                         // don't signal an error: KMSG writer is too important to remove; besides, it would not get fixed that way.
425                         return 0;
426                 }
427
428                 struct now_t now;
429                 r = get_now(&now);
430                 if (r < 0)
431                         return r;
432                 add_recv_timestamp(&lem.header, now);
433
434                 r = buffer_append(&lem.header, wr->buf_ptr);
435                 if (r < 0)
436                         return r;
437         }
438
439         return 0;
440 }
441
442 void remove_reader_fd_entities(struct logger *server, struct reader *reader)
443 {
444         assert(reader);
445
446         if (reader->fd_entity_sink.fd >= 0)
447                 remove_fd_entity(&server->epoll_common, &reader->fd_entity_sink);
448         if (reader->fd_entity_source.fd >= 0)
449                 remove_fd_entity(&server->epoll_common, &reader->fd_entity_source);
450 }
451
452 static bool cond_service_reader_pipe(void *ptr, void *user_data)
453 {
454         assert(ptr);
455         assert(user_data);
456         struct reader_pipe *reader = (struct reader_pipe *)ptr;
457         struct logger *logger = (struct logger *)user_data;
458
459         struct now_t now;
460         int r = get_now(&now);
461         if (r < 0) {
462                 remove_reader_fd_entities(logger, &reader->common);
463                 reader_pipe_free(reader);
464                 return true;
465         }
466         r = print_out_logs(reader, now);
467         if (r > 0) {
468                 remove_reader_fd_entities(logger, &reader->common);
469                 reader_pipe_free(reader);
470                 return true;
471         }
472
473         /* `service_reader()` returns -1 if everything was flushed, or 0 if
474          * a mild error happened that can be recovered from simply by waiting,
475          * the prime example being the pipe getting clogged. As soon as the
476          * reader is available again, we'd like to know about it to ensure
477          * logs are flushed as quickly as possible, which is why the EPOLLOUT.
478          *
479          * On the other hand, we don't want to remove readers from epoll even
480          * if they successfully flushed and have no logs to wait for. Consider
481          * the case where a buffer is unused (for example through libdlog's
482          * buffer disabling feature). If we relied on receiving an error on
483          * calling `write()` to learn that the connection had been closed,
484          * we would never learn about it because there would be no incoming
485          * logs to trigger the flush and so any FDs representing connections
486          * to such buffer would leak until a log finally arrived (which could
487          * be never). This is why waiting is also done on EPOLLHUP. */
488         if (modify_fd_entity(&logger->epoll_common, &reader->common.fd_entity_sink, (r == 0) ? EPOLLOUT : EPOLLHUP) < 0) {
489                 /* ignore, can't really happen and it's not
490                  * like we can do anything about it either */
491         }
492
493         flush_logfile_timely(&reader->file, now.mono, logger->buf_params.time);
494
495         return false;
496 }
497
498 static bool cond_service_reader_logger(void *ptr, void *user_data)
499 {
500         assert(ptr);
501         assert(user_data);
502         struct reader_logger *reader = (struct reader_logger *)ptr;
503         struct logger *logger = (struct logger *)user_data;
504
505         struct now_t now;
506         int r = get_now(&now);
507         if (r < 0) {
508                 remove_reader_fd_entities(logger, &reader->common);
509                 reader_logger_free(reader);
510                 return true;
511         }
512
513         r = service_reader_logger(reader, now);
514
515         if (r > 0) {
516                 remove_reader_fd_entities(logger, &reader->common);
517                 reader_logger_free(reader);
518                 return true;
519         }
520
521         /* `service_reader()` returns -1 if everything was flushed, or 0 if
522          * a mild error happened that can be recovered from simply by waiting,
523          * the prime example being the pipe getting clogged. As soon as the
524          * reader is available again, we'd like to know about it to ensure
525          * logs are flushed as quickly as possible, which is why the EPOLLOUT.
526          *
527          * On the other hand, we don't want to remove readers from epoll even
528          * if they successfully flushed and have no logs to wait for. Consider
529          * the case where a buffer is unused (for example through libdlog's
530          * buffer disabling feature). If we relied on receiving an error on
531          * calling `write()` to learn that the connection had been closed,
532          * we would never learn about it because there would be no incoming
533          * logs to trigger the flush and so any FDs representing connections
534          * to such buffer would leak until a log finally arrived (which could
535          * be never). This is why waiting is also done on EPOLLHUP. */
536         if (modify_fd_entity(&logger->epoll_common, &reader->common.fd_entity_sink, (r == 0) ? EPOLLOUT : EPOLLHUP) < 0) {
537                 /* ignore, can't really happen and it's not
538                  * like we can do anything about it either */
539         }
540
541         reader_logger_flush(reader, now.mono, logger->buf_params.time);
542         return false;
543 }
544
545 /**
546  * @brief Service syslog
547  * @details Read from the syslog socket
548  * @param[in] server The logger server
549  * @param[in] wr The writer who sent the request
550  * @param[in] event The relevant event
551  * @return 0 on success, else -errno
552  */
553 int service_writer_syslog(struct logger *server, struct writer *wr, struct epoll_event *event)
554 {
555         if (event->events & EPOLLHUP)
556                 return -EBADF;
557         if (!(event->events & EPOLLIN))
558                 return 0;
559
560         int r = read(wr->fd_entity.fd, wr->buffer, sizeof wr->buffer - 1);
561
562         if (r == -1 && (errno == EAGAIN || errno == EPIPE))
563                 return 0;
564         else if ((r == 0 || r == -1) && event->events & EPOLLHUP)
565                 return -EINVAL;
566         else if (r == 0)
567                 return -EBADF;
568         else if (r == -1)
569                 return -errno;
570
571         wr->buffer[r] = '\0';
572
573         struct dlogutil_entry_with_msg lem;
574         if (parse_syslog_datagram(wr->buffer, r + 1, &lem.header)) {
575                 /* don't return parse error as writers are removed then */
576                 return 0;
577         }
578
579         struct now_t now;
580         r = get_now(&now);
581         if (r < 0)
582                 return r;
583         add_recv_timestamp(&lem.header, now);
584
585         return buffer_append(&lem.header, wr->buf_ptr);
586 }
587
588 /**
589  * @brief Service all readers
590  * @details Update all readers with latest data
591  * @param[in] server The logger server
592  * @param[in] force_push Whether to force logs to be pushed to the readers
593  */
594 static void service_all_readers(struct logger *server)
595 {
596         for (int i = 0; i < LOG_ID_MAX; i++) {
597                 struct log_buffer *const buffer = server->buffers[i];
598                 if (!buffer)
599                         continue;
600
601                 list_remove_if(&buffer->readers_pipe, server, cond_service_reader_pipe);
602         }
603         list_remove_if(&server->readers_logger, server, cond_service_reader_logger);
604 }
605
606 /**
607  * @brief Add writer to server
608  * @details Adds a writer to the server's witers list and registers its event to epoll loop
609  * @param[in] l The server to add the writer to
610  * @param[in] writer The writer to add to the server and register its working_fd to epoll loop
611  */
612 void logger_add_writer(struct logger *l, struct writer *wr)
613 {
614         assert(l);
615         assert(wr);
616
617         list_add(&l->writers, wr);
618         add_fd_entity(&l->epoll_common, &wr->fd_entity);
619 }
620
621 int epoll_metadata_initialize(struct epoll_metadata *metadata)
622 {
623         metadata->fd = epoll_create1(0);
624         if (metadata->fd < 0)
625                 return -errno;
626
627         int r = initialize_epoll_size(&metadata->events, &metadata->events_size);
628         if (r < 0) {
629                 close(metadata->fd);
630                 metadata->fd = -1;
631                 return r;
632         }
633
634         metadata->cnt = 0;
635         return 0;
636 }
637
638 void epoll_metadata_destroy(struct epoll_metadata *metadata)
639 {
640         if (metadata->fd >= 0)
641                 close(metadata->fd);
642
643         free(metadata->events);
644 }
645
646 /**
647  * @brief Create the logger server
648  * @details Allocate the logger server's auxiliary structures (buffers etc.)
649  * @param[in] data Initialisation data
650  * @param[out] l The logger server
651  * @return 0 on success, -errno on failure
652  */
653 #ifndef UNIT_TEST
654 static
655 #endif
656 int logger_create(struct logger_config_data *data, struct logger *l)
657 {
658         memset(l, 0, sizeof *l);
659         l->epoll_socket.fd = -1;
660
661         int r = epoll_metadata_initialize(&l->epoll_common);
662         if (r < 0)
663                 return r;
664         r = epoll_metadata_initialize(&l->epoll_socket);
665         if (r < 0)
666                 return r;
667
668         l->epolltime = data->epoll_time;
669
670         l->lazy_polling_total = data->lazy_polling_total;
671         l->lazy_polling_sleep = data->lazy_polling_sleep;
672
673         l->buf_params = data->buf_params;
674
675         l->qos.log_metrics = metrics_create();
676         if (!l->qos.log_metrics)
677                 return -ENOMEM;
678
679         l->qos.max_throughput = data->qos_max_throughput;
680         l->qos.threshold = data->qos_threshold;
681         l->qos.threshold_reapply = data->qos_threshold_reapply;
682         l->qos.limit_duration = data->qos_limit_duration;
683         l->qos.file_path = data->qos_file_path;
684         data->qos_file_path = NULL;
685
686         // Check if the daemon is being launched for the first time since reboot
687         bool first_time;
688         if (data->first_time_file_path) {
689                 int fd = open(data->first_time_file_path, O_CREAT | O_EXCL | O_RDONLY, 0644);
690                 if (fd == -1) {
691                         if (errno == EEXIST)
692                                 first_time = false;
693                         else
694                                 return -errno;
695                 } else {
696                         first_time = true;
697                         close(fd);
698                 }
699         } else
700                 // If no path, assume first time
701                 first_time = true;
702
703         if (g_backend.use_logger_by_default)
704                 for (log_id_t id = 0; id < LOG_ID_MAX; ++id) {
705                         if (!is_core_buffer(id))
706                                 continue;
707
708                         int r = reader_logger_init(g_backend.logger_readers + id, id, l, !first_time);
709                         if (r < 0)
710                                 return r;
711                         if (!g_backend.logger_readers[id])
712                                 continue;
713
714                         if (qos_is_enabled(&l->qos)) {
715                                 r = reader_logger_add_subreader_metrics(g_backend.logger_readers[id], &l->qos);
716                                 if (r < 0)
717                                         return r;
718                         }
719
720                         r = add_reader_logger(l, g_backend.logger_readers[id]);
721                         if (r < 0)
722                                 return r;
723                 }
724
725         for (log_id_t id = 0; id < LOG_ID_MAX; id++)
726                 if (data->is_buffer_enabled[id]) {
727                         int r = buffer_create(&l->buffers[id], id, data->buffers + id);
728                         if (r < 0)
729                                 return r;
730                 }
731
732         for (log_id_t id = 0; id < LOG_ID_MAX; id++)
733                 if (l->buffers[id]) {
734                         add_fd_entity(&l->epoll_common, &l->buffers[id]->sock_ctl.fd_entity);
735                         add_fd_entity(&l->epoll_common, &l->buffers[id]->sock_conn.fd_entity);
736
737                         add_fd_entity(&l->epoll_socket, &l->buffers[id]->sock_ctl.fd_entity);
738                         add_fd_entity(&l->epoll_socket, &l->buffers[id]->sock_conn.fd_entity);
739                 }
740
741         /* TODO: make writers creation optional/configurable */
742         int (*writers_factories[LOG_ID_MAX])(struct writer **writer, struct log_buffer *log_buf) = {
743                 [LOG_ID_KMSG] = create_kmsg_writer,
744                 [LOG_ID_SYSLOG] = create_syslog_writer,
745         };
746         for (unsigned u = 0; u < NELEMS(writers_factories); ++u)
747                 if (writers_factories[u] && data->is_buffer_enabled[u]) {
748                         struct writer *wr;
749                         int r = writers_factories[u](&wr, l->buffers[u]);
750                         if (r < 0)
751                                 return r;
752
753                         logger_add_writer(l, wr);
754                 }
755
756         return 0;
757 }
758
759 static bool cond_writer_free(void *ptr, void *user_data)
760 {
761         writer_free((struct writer *)ptr, (struct logger *)user_data);
762         return true;
763 }
764
765 /**
766  * @brief Free logger
767  * @details Deallocate the logger and its auxiliary structures
768  * @param[in] l The logger server
769  */
770 #ifndef UNIT_TEST
771 static
772 #endif
773 void logger_free(struct logger *l)
774 {
775         assert(l);
776
777         list_remove_if(&l->writers, l, cond_writer_free);
778         list_remove_if(&l->readers_logger, l, cond_reader_logger_free);
779
780         int j;
781         for (j = 0; j < LOG_ID_MAX; j++)
782                 if (l->buffers[j])
783                         buffer_free(l->buffers[j], l);
784
785         epoll_metadata_destroy(&l->epoll_common);
786         epoll_metadata_destroy(&l->epoll_socket);
787
788         qos_free(&l->qos);
789 }
790
791 /**
792  * @brief Handle interrupting/terminating signals
793  * @details Clears global flag to stop main loop
794  * @param[in] signo signal number
795  */
796 static void handle_signals(int signo)
797 {
798         (void) signo;
799         g_logger_run = 0;
800 }
801
802 static void ensure_epoll_size(struct epoll_event **events, unsigned *size, unsigned wanted_size)
803 {
804         assert(events);
805         assert(size);
806
807         if (wanted_size <= *size)
808                 return;
809
810         typeof(*events) temp = realloc(*events, wanted_size * sizeof **events);
811         if (!temp)
812                 return;
813
814         *events = temp;
815         *size = wanted_size;
816 }
817
818 static int initialize_epoll_size(struct epoll_event **events, unsigned *size)
819 {
820         assert(events);
821         assert(size);
822
823         static const size_t default_size = 16U;
824         typeof(*events) ev = malloc(default_size * sizeof *ev);
825         if (!ev)
826                 return -ENOMEM;
827
828         *events = ev;
829         *size = default_size;
830         return 0;
831 }
832
833 void dispatch_epoll_event(struct logger *server, struct epoll_event *event)
834 {
835         struct fd_entity *const entity = (struct fd_entity *) event->data.ptr;
836         assert(entity->dispatch_event);
837         entity->dispatch_event(server, event, entity->dispatch_data);
838 }
839
840 int handle_epoll_events(struct logger *server, struct epoll_metadata *metadata, int timeout)
841 {
842         ensure_epoll_size(&metadata->events, &metadata->events_size, metadata->cnt);
843
844         int nfds = epoll_wait(metadata->fd, metadata->events, metadata->events_size, timeout);
845         if (nfds < 0)
846                 return errno == EINTR ? 0 : -errno;
847
848         for (int i = 0; i < nfds; i++)
849                 dispatch_epoll_event(server, metadata->events + i);
850
851         return 0;
852 }
853
854 int sleep_while_handling_socket(struct logger *server, struct epoll_metadata *metadata, int timeout)
855 {
856         struct timespec ts_start;
857         if (clock_gettime(CLOCK_MONOTONIC, &ts_start))
858                 return -errno;
859         struct timespec ts_current;
860
861         do {
862                 int r = handle_epoll_events(server, metadata, timeout);
863                 if (r < 0)
864                         return r;
865                 if (clock_gettime(CLOCK_MONOTONIC, &ts_current))
866                         return -errno;
867         } while (
868                 timeout > (ts_current.tv_sec  - ts_start.tv_sec ) *  S_TO_MS
869                         + (ts_current.tv_nsec - ts_start.tv_nsec) / MS_TO_NS
870         );
871
872         return 0;
873 }
874
875 void setup_signals(struct logger *server)
876 {
877         struct sigaction action = {
878                 .sa_handler = handle_signals,
879                 .sa_flags   = 0
880         };
881         sigemptyset(&action.sa_mask);
882
883         static const int handled_signals[] = { SIGINT, SIGTERM };
884         for (unsigned u = 0; u < NELEMS(handled_signals); ++u)
885                 sigaction(handled_signals[u], &action, NULL);
886 }
887
888 /**
889  * @brief Do logging
890  * @details The main logging loop
891  * @param[in] server The logger server
892  * @return 0 on success, else -errno
893  */
894 #ifndef UNIT_TEST
895 static
896 #endif
897 int do_logger(struct logger *server)
898 {
899         setup_signals(server);
900
901         bool use_lazy_polling = true;
902         while (g_logger_run) {
903                 if (server->lazy_polling_total >= 0) {
904                         server->lazy_polling_total -= server->lazy_polling_sleep;
905                         use_lazy_polling = (server->lazy_polling_total >= 0);
906                 }
907                 if (use_lazy_polling)
908                         sleep_while_handling_socket(server, &server->epoll_socket, server->lazy_polling_sleep);
909
910                 int r = handle_epoll_events(server, &server->epoll_common, server->epolltime * !use_lazy_polling);
911                 if (r < 0)
912                         break;
913
914                 service_all_readers(server);
915                 qos_periodic_check(server);
916         }
917
918         /* ensure all logs are written no matter when the program was interrupted */
919         server->exiting = 1;
920         service_all_readers(server);
921
922         return 0;
923 }
924
925 /**
926  * @brief Prepare socket data
927  * @details Extracts initialisation data specific to each socket
928  * @param[in] conf Config database
929  * @param[out] data Socket init config data
930  * @param[in] buf_name The name of the buffer the socket belongs to
931  * @param[in] type The name of the buffer type
932  * @return 0 on success, -errno on failure
933  */
934 int prepare_socket_data(const struct log_config *conf, struct socket_config_data *data, char *buf_name, const char *type)
935 {
936         char conf_key[MAX_CONF_KEY_LEN];
937         int r;
938
939         r = snprintf(conf_key, MAX_CONF_KEY_LEN, "%s_%s_sock", buf_name, type);
940         if (r < 0)
941                 return -errno;
942         const char * const path = log_config_get(conf, conf_key);
943
944         r = snprintf(conf_key, MAX_CONF_KEY_LEN, "%s_%s_sock_rights", buf_name, type);
945         if (r < 0)
946                 return -errno;
947         const char * const permissions_str = log_config_get(conf, conf_key);
948
949         if (!permissions_str || !path)
950                 return -ENOENT;
951
952         data->permissions = parse_permissions(permissions_str);
953         if (data->permissions <= 0)
954                 return -EINVAL;
955
956         strncpy(data->path, path, MAX_CONF_VAL_LEN - 1);
957
958         return 0;
959 }
960
961 /**
962  * @brief Prepare buffer data
963  * @details Extracts data specific for each buffer
964  * @param[in] conf Config database
965  * @param[out] data Buffer init config data
966  * @param[in] buf_id Index of the buffer to work with
967  * @return 0 on success, -errno on failure
968  */
969 int prepare_buffer_data(const struct log_config *conf, struct buffer_config_data *data, log_id_t buf_id)
970 {
971         char * const buf_name = log_name_by_id(buf_id);
972         char * validity_check_ptr;
973         char conf_key[MAX_CONF_KEY_LEN];
974         int r;
975
976         r = prepare_socket_data(conf, &data->conn_socket, buf_name, "conn");
977         if (r < 0)
978                 return r;
979
980         r = prepare_socket_data(conf, &data->ctl_socket, buf_name, "ctl");
981         if (r < 0)
982                 return r;
983
984         r = snprintf(conf_key, MAX_CONF_KEY_LEN, "%s_size", buf_name);
985         if (r < 0)
986                 return -errno;
987
988         const char * const size_str = log_config_get(conf, conf_key);
989         if (!size_str)
990                 return -ENOENT;
991
992         data->size = strtol(size_str, &validity_check_ptr, 10);
993         if (*validity_check_ptr)
994                 return -EINVAL;
995         if (data->size <= 0)
996                 return -EINVAL;
997
998         return 0;
999 }
1000
1001 /**
1002  * @brief Save logfile line
1003  * @detail Saves logfile config line in user_data list
1004  * @param[in] key Config entry key
1005  * @param[in] value Config entry value
1006  * @param[in] userdata Userdata
1007  */
1008 void save_logfile_config(char const *key, char const *value, void *userdata)
1009 {
1010         assert(userdata);
1011         if (strncmp(key, CONF_PREFIX, sizeof CONF_PREFIX - 1))
1012                 return;
1013
1014         struct logger_config_data *data = (struct logger_config_data *)userdata;
1015         void *cmd = (void *)strdup(value);
1016         if (cmd)
1017                 list_add(&data->logfile_configs, cmd);
1018         //ignore errors
1019 }
1020
1021 /**
1022  * @brief Initialize config data
1023  * @param[out] The data structure to fill with initial values
1024  */
1025 void initialize_config_data(struct logger_config_data *data)
1026 {
1027         memset(data, 0, sizeof *data);
1028 }
1029
1030 /**
1031  * @brief Prepare config data
1032  * @details Extracts relevant config data for logger initialisation
1033  * @param[out] data Parsed configuration
1034  * @return 0 on success, -errno on failure
1035  */
1036 int prepare_config_data(struct logger_config_data *data)
1037 {
1038         assert(data);
1039
1040         struct log_config conf;
1041         int ret = log_config_read(&conf);
1042         if (ret < 0)
1043                 return ret;
1044
1045         const dlogutil_sorting_order_e sort_by = get_order_from_config(&conf);
1046
1047         int throttling_default = log_config_get_int(&conf, "logger_dev_throttling", LOGGER_DEVICE_THROTTLING_DEFAULT);
1048         const char *const dynamic_config_dir = log_config_get(&conf, DYNAMIC_CONFIG_CONF_KEY);
1049
1050         const char * const backend = log_config_claim_backend(&conf);
1051         if (!backend) {
1052                 ret = -ENOENT;
1053                 goto end;
1054         }
1055
1056         for (int i = 0; i < LOG_ID_MAX; i++) {
1057                 char key[MAX_CONF_KEY_LEN];
1058                 const int r = snprintf(key, sizeof key, "logger_dev_throttling_%s", log_name_by_id((log_id_t)i));
1059                 if (r < 0)
1060                         continue;
1061
1062                 g_backend.logger_device_throttling[i] = max_int(1, log_config_get_int(&conf, key, throttling_default));
1063         }
1064
1065         if (dynamic_config_dir && dynamic_config_dir[0] == '/') {
1066                 data->dynamic_config_dir = strdup(dynamic_config_dir);
1067                 if (!data->dynamic_config_dir) {
1068                         ret = -ENOMEM;
1069                         goto end;
1070                 }
1071         } else {
1072                 data->dynamic_config_dir = NULL; // Technically unnecessary but no reason not to put it
1073         }
1074
1075         data->epoll_time = log_config_get_int(&conf, "epoll_time_ms", DEFAULT_EPOLL_TIME_MS);
1076         data->lazy_polling_total = log_config_get_int(&conf, "lazy_polling_total_ms", DEFAULT_LAZY_POLLING_TOTAL_MS);
1077         data->lazy_polling_sleep = log_config_get_int(&conf, "lazy_polling_sleep_ms", DEFAULT_LAZY_POLLING_SLEEP_MS);
1078
1079         const char *const qos_file_path = log_config_get(&conf, "qos_file_path");
1080         data->qos_file_path = qos_file_path ? strdup(qos_file_path) : NULL;
1081
1082         data->qos_limit_duration = log_config_get_int(&conf, "qos_refresh_rate_s", DEFAULT_QOS_LIMIT_DURATION_S);
1083         data->qos_max_throughput = log_config_get_int(&conf, "qos_max_throughput_logs", DEFAULT_QOS_THROUGHPUT_LOGS);
1084         data->qos_threshold = log_config_get_int(&conf, "qos_threshold_logs", DEFAULT_QOS_THRESHOLD_LOGS);
1085         data->qos_threshold_reapply = log_config_get_int(&conf, "qos_threshold_reapply_logs", DEFAULT_QOS_THRESHOLD_REAPPLY_LOGS);
1086
1087         struct {
1088                 void (*func)(struct qos_module *qos, struct metrics_pid_aggr_info *infos, int count);
1089                 const char *name;
1090         } const qos_methods[] = {
1091                 { qos_distribution_proportional_raw   , "proportional_raw"    },
1092                 { qos_distribution_proportional_talmud, "proportional_talmud" },
1093                 { qos_distribution_equal              , "equal"               },
1094                 { qos_distribution_equal_dual         , "equal_dual"          },
1095                 { qos_distribution_equal_multi        , "equal_multi"         },
1096         };
1097         qos_distribution_func = qos_distribution_equal_multi; // default
1098         const char *const qos_method = log_config_get(&conf, "qos_method");
1099         if (qos_method)
1100                 for (int i = 0; i < NELEMS(qos_methods); ++i)
1101                         if (!strcmp(qos_method, qos_methods[i].name))
1102                                 qos_distribution_func = qos_methods[i].func;
1103
1104         const char *const first_time_file_path = log_config_get(&conf, "first_time_file_path");
1105         data->first_time_file_path = first_time_file_path ? strdup(first_time_file_path) : NULL;
1106
1107         memset(data->is_buffer_enabled, 0, sizeof(data->is_buffer_enabled));
1108         if (!strcmp(backend, "pipe")) {
1109                 data->is_buffer_enabled[LOG_ID_MAIN] =
1110                         data->is_buffer_enabled[LOG_ID_RADIO] =
1111                         data->is_buffer_enabled[LOG_ID_SYSTEM] =
1112                         data->is_buffer_enabled[LOG_ID_APPS] = 1;
1113                 g_backend.use_logger_by_default = false;
1114         } else if (!strcmp(backend, "logger")) {
1115                 g_backend.use_logger_by_default = true;
1116                 for (log_id_t buf_id = 0; buf_id < LOG_ID_MAX; ++buf_id) {
1117                         const char *const logger_device = log_config_get(&conf, log_name_by_id(buf_id));
1118                         if (logger_device)
1119                                 strncpy(g_backend.logger_devices[buf_id], logger_device,
1120                                         NELEMS(g_backend.logger_devices[buf_id]) - 1);
1121                 }
1122         } else {
1123                 ret = -ENOENT;
1124                 goto end;
1125         }
1126         data->is_buffer_enabled[LOG_ID_KMSG] = log_config_get_boolean(&conf, "handle_kmsg", true);
1127         data->is_buffer_enabled[LOG_ID_SYSLOG] =
1128                 dev_log_sock_get() >= 0 || log_config_get_boolean(&conf, "syslog_force", false);
1129
1130         for (log_id_t buf_id = 0; buf_id < LOG_ID_MAX; ++buf_id) {
1131                 if (data->is_buffer_enabled[buf_id]) {
1132                         ret = prepare_buffer_data(&conf, data->buffers + buf_id, buf_id);
1133                         if (ret < 0)
1134                                 goto end;
1135                         data->buffers[buf_id].sort_by = sort_by;
1136                 }
1137         }
1138         data->logfile_configs = NULL;
1139         log_config_foreach(&conf, save_logfile_config, data);
1140
1141 end:
1142         log_config_free(&conf);
1143         return ret;
1144 }
1145
1146 static bool cond_string_free(void *ptr, void *user_data)
1147 {
1148         (void) user_data;
1149         free(ptr);
1150         return true;
1151 }
1152
1153 #ifndef UNIT_TEST
1154 static
1155 #endif
1156 void free_config_data(struct logger_config_data *data)
1157 {
1158         list_remove_if(&data->logfile_configs, NULL, cond_string_free);
1159         free(data->dynamic_config_dir);
1160         free(data->qos_file_path);
1161         free(data->first_time_file_path);
1162 }
1163
1164 /**
1165  * @brief Parse logfile line
1166  * @detail Parses a logfile config line
1167  * @param[in] key Config entry key
1168  * @param[in] value Config entry value
1169  * @param[in] userdata Userdata
1170  */
1171 void parse_logfile_config(void *value, void *userdata)
1172 {
1173         assert(value);
1174         assert(userdata);
1175
1176         struct logger *server = (struct logger *) userdata;
1177         char *configline = (char *) value;
1178
1179         __attribute__((cleanup(free_dlogutil_line_params))) struct dlogutil_line_params params;
1180         if (!initialize_dlogutil_line_params(&params, server->buf_params))
1181                 return;
1182
1183         get_dlogutil_line_params(configline, &params);
1184
1185         int r;
1186         if (g_backend.use_logger_by_default && is_core_buffer(params.buf_id)) {
1187                 r = create_logger_subreader_from_dlogutil_line(&params);
1188         } else {
1189                 struct reader_pipe *reader = NULL;
1190                 r = create_reader_pipe_from_dlogutil_line(&params, server, &reader);
1191                 if (r == 0)
1192                         add_reader_pipe(server, reader);
1193         }
1194
1195         if (r != 0) {
1196                 errno = -r;
1197                 printf("Warning: unable to add logutil reader for provided configuration. Ignoring.\n"
1198                        "  Config line: %s\n"
1199                        "  Reason given: %m\n",
1200                        configline);
1201         }
1202 }
1203
1204 #ifndef UNIT_TEST
1205 /**
1206  * @brief Print help
1207  * @details Prints basic usage tips
1208  */
1209 static void help(void)
1210 {
1211         printf("Usage: %s [options]\n"
1212                "\t-h    Show this help\n"
1213                "\t-b N  Set the size of the log buffer (in bytes)\n"
1214                "\t-t N  Set time between writes to file (in seconds)\n",
1215                program_invocation_short_name);
1216 }
1217
1218 /**
1219  * @brief Parse args
1220  * @details Parses execution parameters of the program
1221  * @param[in] argc Argument count
1222  * @param[in] argv Argument values
1223  * @param[out] b Buffering parameters
1224  * @return 0 or 1 on success, else -errno. Nonzero if the program is to close.
1225  */
1226 static int parse_args(int argc, char **argv, struct buf_params *b)
1227 {
1228         b->time = BUF_PARAM_TIME_DEFAULT;
1229         b->bytes = BUF_PARAM_BYTES_DEFAULT;
1230
1231         int option;
1232         while ((option = getopt(argc, argv, "hb:t:")) != -1) {
1233                 switch (option) {
1234                 case 't':
1235                         if (!isdigit(optarg[0]))
1236                                 return -EINVAL;
1237                         b->time = clamp_int(atoi(optarg), BUF_PARAM_TIME_MIN, BUF_PARAM_TIME_MAX);
1238                         break;
1239                 case 'b':
1240                         if (!isdigit(optarg[0]))
1241                                 return -EINVAL;
1242                         b->bytes = clamp_int(atoi(optarg), BUF_PARAM_BYTES_MIN, BUF_PARAM_BYTES_MAX);
1243                         break;
1244                 case 'h':
1245                         return 1;
1246                 default:
1247                         return -EINVAL;
1248                 }
1249         }
1250
1251         return 0;
1252 }
1253
1254 /**
1255  * @brief Finalize initialisation
1256  * @details Do misc stuff needed at the end of the initialisation
1257  * @param[in] data configuration dat to read logfiles config lines from
1258  * @param[in] server logger instance to configure
1259  * @return 0 on success, -errno on failure
1260  */
1261 static int finalize_init(struct logger_config_data *data, struct logger *server)
1262 {
1263         int r = sd_notify(0, "READY=1");
1264         if (r < 0)
1265                 return r;
1266
1267         //create files after resetting self privileges
1268         list_foreach(data->logfile_configs, server, parse_logfile_config);
1269
1270         return 0;
1271 }
1272
1273 static void precreate_logctl_file(struct logger_config_data *data)
1274 {
1275         __attribute__((cleanup(free_ptr))) char *logctl_file_path = NULL;
1276         if (asprintf(&logctl_file_path, "%s/%s", data->dynamic_config_dir, DYNAMIC_CONFIG_FILENAME) < 0)
1277                 // This is worrying but unimportant
1278                 return;
1279
1280         int fd = open(logctl_file_path, O_RDONLY | O_CREAT, 0644);
1281         if (fd < 0)
1282                 // Again, no big deal
1283                 return;
1284
1285         close(fd);
1286 }
1287
1288 bool early_termination(const struct logger_config_data *data, const struct logger *logger) {
1289         /* In order to check if the deamon will be doing nothing
1290          * and can quit instantaneously, we do three checks: */
1291
1292         /* 1. We make sure that there are no logger subreaders.
1293          * When the logger backend is being used, the daemon reads the data
1294          * in order to use it internally. The daemon always reads each buffer
1295          * to a separate reader and each concrete usage has its own subreader.
1296          * Therefore, we need to check if no subreaders exist. */
1297         for (list_head l = logger->readers_logger; l != NULL; list_next(&l)) {
1298                 struct reader_logger *reader = list_at(l);
1299                 if (reader->subs != NULL)
1300                         return false;
1301         }
1302
1303         /* 2. We make sure that no pipe-like buffer is enabled.
1304          * When the pipe backend is being used or pipe-like buffers
1305          * (i.e. KMSG, SYSLOG) are handled, the logger allocates space for them.
1306          * In this case, we cannot terminate even if the buffer is enabled
1307          * but unused at the moment, since it might be connected to
1308          * (for instance by dlogutil). */
1309         for (log_id_t id = 0; id < LOG_ID_MAX; id++)
1310                 if (data->is_buffer_enabled[id])
1311                         return false;
1312
1313         /* 3. We make sure that there are no writers.
1314          * In theory, previous checks are sufficient.
1315          * However, we do another check just to be sure
1316          * (since if there are writers, we shouldn't terminate).
1317          * Additionally, this could change in the future,
1318          * so let's hedge against someone forgetting that this function exists. */
1319         return logger->writers == NULL;
1320 }
1321
1322 /**
1323  * @brief The logger
1324  * @return 0 on success, nonzero on failure
1325  * @retval 1 Configuration error
1326  * @retval 2 Runtime error
1327  */
1328 int main(int argc, char **argv)
1329 {
1330         int r, ret;
1331
1332         signal(SIGPIPE, SIG_IGN);
1333
1334         r = reset_self_privileges();
1335         if (r < 0) {
1336                 errno = -r;
1337                 printf("Unable to drop privileges to build-time defaults (%m). Exiting.\n");
1338                 return DLOG_EXIT_ERR_RUNTIME;
1339         }
1340
1341         struct logger_config_data data;
1342         initialize_config_data(&data);
1343
1344         if ((r = parse_args(argc, argv, &data.buf_params)) != 0) {
1345                 help();
1346
1347                 if (r > 0)
1348                         return DLOG_EXIT_SUCCESS; // --help option
1349
1350                 errno = -r;
1351                 printf("Unable to parse command line args (%m). Exiting.\n");
1352                 return DLOG_EXIT_ERR_CONFIG;
1353         }
1354
1355         if ((r = prepare_config_data(&data)) != 0) {
1356                 errno = -r;
1357                 printf("Unable to prepare config (%m). Exiting.\n");
1358                 return DLOG_EXIT_ERR_CONFIG;
1359         }
1360
1361         precreate_logctl_file(&data);
1362
1363         struct logger server;
1364         if ((r = logger_create(&data, &server)) < 0) {
1365                 errno = -r;
1366                 printf("Unable to initialize logger with provided configuration (%m). Exiting.\n");
1367                 ret = DLOG_EXIT_ERR_CONFIG;
1368                 goto cleanup;
1369         }
1370
1371         if ((r = finalize_init(&data, &server)) < 0) {
1372                 errno = -r;
1373                 printf("Unable to finalize initialisation (%m). Exiting.\n");
1374                 ret = DLOG_EXIT_ERR_CONFIG;
1375                 goto cleanup;
1376         }
1377
1378         if (early_termination(&data, &server)) {
1379                 printf("No work to do according to provided configuration. Exiting.\n");
1380                 ret = DLOG_EXIT_SUCCESS;
1381                 goto cleanup;
1382         }
1383
1384         if ((r = do_logger(&server)) < 0) {
1385                 errno = -r;
1386                 printf("Runtime failure (%m). Exiting.\n");
1387                 ret = DLOG_EXIT_ERR_RUNTIME;
1388                 goto cleanup;
1389         }
1390
1391         ret = DLOG_EXIT_SUCCESS;
1392
1393 cleanup:
1394         free_config_data(&data);
1395         logger_free(&server);
1396         return ret;
1397 }
1398 #endif
1399
1400 /**
1401  * @}
1402  * @}
1403  */