Remove wheel submodule - will re-add later with new URL
[dmon:dmon.git] / dlog.c
1 /*
2  * dlog.c
3  * Copyright (C) 2010 Adrian Perez <aperez@igalia.com>
4  *
5  * Distributed under terms of the MIT license.
6  */
7
8 #include "wheel.h"
9 #include "util.h"
10 #include <stdlib.h>
11 #include <signal.h>
12 #include <unistd.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <fcntl.h>
16 #include <time.h>
17
18 #ifdef NO_MULTICALL
19 # define dlog_main main
20 #endif /* NO_MULTICALL */
21
22 #ifndef TSTAMP_FMT
23 #define TSTAMP_FMT "%Y-%m-%d/%H:%M:%S"
24 #endif /* !TSTAMP_FMT */
25
26 #ifndef TSTAMP_LEN
27 #define TSTAMP_LEN (5 + 3 + 3 + 3 + 3 + 3)
28 #endif /* !TSTAMP_LEN */
29
30
31 static wbool   timestamp = W_NO;
32 static wbool   buffered  = W_NO;
33 static w_io_t *log_io    = NULL;
34
35
36 static const w_opt_t dlog_options[] = {
37     { 0, 'b', "buffered", W_OPT_BOOL, &buffered,
38         "Buffered operation, do not use flush to disk after each line." },
39
40     { 0, 't', "timestamp", W_OPT_BOOL, &timestamp,
41         "Prepend a timestamp in YYYY-MM-DD/HH:MM:SS format to each line." },
42
43     W_OPT_END
44 };
45
46
47 static void
48 handle_signal (int signum)
49 {
50     if (buffered) {
51         w_io_flush (log_io);
52     }
53
54     if (log_io != w_stdout && log_io != w_stderr) {
55         w_io_close (log_io);
56         log_io = 0;
57     }
58
59     /*
60      * When handling HUP, we just sync and close the log file; in
61      * other cases (INT, TERM) we have to exit gracefully, too.
62      */
63     if (signum != SIGHUP) {
64         exit (EXIT_SUCCESS);
65     }
66 }
67
68
69 int
70 dlog_main (int argc, char **argv)
71 {
72     w_buf_t overflow = W_BUF;
73     w_buf_t linebuf = W_BUF;
74     char *env_opts = NULL;
75     struct sigaction sa;
76     unsigned consumed;
77
78     if ((env_opts = getenv ("DLOG_OPTIONS")) != NULL)
79         replace_args_string (env_opts, &argc, &argv);
80
81     consumed = w_opt_parse (dlog_options, NULL, NULL, "[logfile-path]", argc, argv);
82
83     if (consumed >= (unsigned) argc) {
84         log_io = w_stdout;
85     }
86     else {
87         w_io_close (w_stdout);
88     }
89
90     sigemptyset (&sa.sa_mask);
91     sa.sa_flags = 0;
92
93     sa.sa_handler = handle_signal;
94     safe_sigaction ("HUP", SIGHUP, &sa);
95
96     sa.sa_handler = handle_signal;
97     safe_sigaction ("INT", SIGINT, &sa);
98
99     sa.sa_handler = handle_signal;
100     safe_sigaction ("TERM", SIGTERM, &sa);
101
102     for (;;) {
103         ssize_t ret = w_io_read_line (w_stdin, &linebuf, &overflow, 0);
104
105         if (ret == W_IO_ERR)
106             w_die ("$s: error reading input: $E\n", argv[0]);
107
108         if (w_buf_length (&linebuf)) {
109             if (timestamp) {
110                 time_t now = time(NULL);
111                 char timebuf[TSTAMP_LEN+1];
112                 struct tm *time_gm = gmtime (&now);
113
114                 if (strftime (timebuf, TSTAMP_LEN+1, TSTAMP_FMT, time_gm) == 0)
115                     w_die ("$s: cannot format timestamp: $E\n", argv[0]);
116
117                 if (!log_io) {
118                     log_io = w_io_unix_open (argv[consumed],
119                                              O_CREAT | O_APPEND | O_WRONLY,
120                                              0666);
121                     if (!log_io)
122                         w_die ("$s: cannot open '$s': $E\n", argv[0], argv[consumed]);
123                 }
124                 w_io_format (log_io, "$s $B\n", timebuf, &linebuf);
125             }
126             else {
127                 if (!log_io) {
128                     log_io = w_io_unix_open (argv[consumed],
129                                              O_CREAT | O_APPEND | O_WRONLY,
130                                              0666);
131                     if (!log_io)
132                         w_die ("$s: cannot open '$s': $E\n", argv[0], argv[consumed]);
133                 }
134                 w_io_format (log_io, "$B\n", &linebuf);
135             }
136
137             if (!buffered) {
138                 w_io_flush (log_io);
139             }
140         }
141
142         w_buf_reset (&linebuf);
143
144         if (ret == W_IO_EOF) /* EOF reached */
145             break;
146     }
147
148     w_io_close (log_io);
149
150     exit (EXIT_SUCCESS);
151 }
152