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