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