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