Report gettimeofday() for comparison.
[darkstat] / seclog.c
1 /* darkstat 3
2 * copyright (c) 2011 Dario Fiumicello.
3 *
4 * seclog.c: reports usage every second
5 *
6 * You may use, modify and redistribute this file under the terms of the
7 * GNU General Public License version 2. (see COPYING.GPL)
8 */
9
10 #define _GNU_SOURCE 1 /* for O_NOFOLLOW on Linux */
11
12 #include <sys/types.h>
13 #include <assert.h>
14 #include <fcntl.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18
19 #include "darkstat.h"
20 #include "err.h"
21 #include "daylog.h"
22 #include "seclog.h"
23 #include "str.h"
24 #include "now.h"
25
26 static const char *seclog_fn_base = NULL, *seclog_fn = NULL;
27 static time_t today_time, nextsec_time, tomorrow_time;
28 static uint64_t bytes_in, bytes_out, pkts_in, pkts_out;
29 static size_t seclog_fn_len;
30
31 #define SECLOG_DATE_YYYYMMDD_LEN 10 /* strlen(".19000101") + 1 */
32 static char date_yyyymmdd_buf[SECLOG_DATE_YYYYMMDD_LEN];
33
34 /* Given a timestamp returns the date formatted as YYYYMMDD */
35 char *
36 date_to_yyyymmdd(const time_t when)
37 {
38 time_t tmp = when;
39 if (strftime(date_yyyymmdd_buf, SECLOG_DATE_YYYYMMDD_LEN,
40 ".%Y%m%d", localtime(&tmp) ) == 0)
41 errx(1, "strftime() failed in date_to_yyyymmdd()");
42 return (date_yyyymmdd_buf);
43 }
44
45 /*Given a certain time it returnse time+1sec */
46 static time_t
47 nextsec(const time_t today)
48 {
49 time_t tmp = today;
50 struct tm tm, *lt;
51
52 lt = localtime(&tmp);
53 memcpy(&tm, lt, sizeof(tm));
54 tm.tm_sec = lt->tm_sec+1;
55 return mktime(&tm);
56 }
57
58 static int
59 seclog_open(void)
60 {
61 return open(seclog_fn, O_WRONLY | O_APPEND | O_CREAT | O_NOFOLLOW, 0600);
62 }
63
64 static void
65 seclog_emit(void)
66 {
67 int fd = seclog_open();
68
69 if (fd != -1) {
70 struct str *buf = str_make();
71 struct timeval tv;
72 char *s;
73 size_t len;
74 gettimeofday(&tv, NULL);
75 str_appendf(buf, "%s|%u|%qu.%qu|%qu|%qu|%qu|%qu\n",
76 fmt_date(today_time), (unsigned int)today_time,
77 (uint64_t)tv.tv_sec,
78 (uint64_t)tv.tv_usec,
79 bytes_in, bytes_out, pkts_in, pkts_out);
80 str_extract(buf, &len, &s);
81
82 (void)write(fd, s, len); /* ignore write errors */
83 free(s);
84
85 if (now >= tomorrow_time) {
86 /* If a new day is born close old file writing the closure comment, update
87 * the file name with the new day date and reopen it, writing an opening
88 * comment */
89 tomorrow_time = tomorrow(now);
90
91 buf = str_make();
92 str_appendf(buf, "# logging stopped at %s (%u)\n",
93 fmt_date(now), (unsigned int)now);
94 str_extract(buf, &len, &s);
95 (void)write(fd, s, len); /* ignore write errors */
96 close(fd);
97 free(s);
98
99 strncpy(seclog_fn, seclog_fn_base, seclog_fn_len);
100 strncat(seclog_fn, date_to_yyyymmdd(now), seclog_fn_len);
101
102 seclog_open();
103 if (fd == -1)
104 err(1, "couldn't open(\"%s\") for append", seclog_fn);
105
106 buf = str_make();
107 str_appendf(buf, "# logging started at %s (%u)\n",
108 fmt_date(now), (unsigned int)now);
109 str_extract(buf, &len, &s);
110 (void)write(fd, s, len); /* ignore write errors */
111 free(s);
112
113 }
114 close(fd);
115 }
116
117 }
118
119 void
120 seclog_init(const char *filename)
121 {
122 int fd;
123 struct str *buf;
124 char *s;
125 size_t len;
126
127 seclog_fn_base = filename;
128 seclog_fn_len = strlen(filename) + SECLOG_DATE_YYYYMMDD_LEN + 1;
129
130 seclog_fn = (char*) malloc(seclog_fn_len*sizeof(char));
131 if (seclog_fn == NULL)
132 err(1, "Memory allocation error! Run out of RAM?");
133 memset(seclog_fn, 0, seclog_fn_len*sizeof(char));
134
135 today_time = time(NULL);
136 nextsec_time = nextsec(today_time);
137 tomorrow_time = tomorrow(today_time);
138 verbosef("today is %u, today+1sec is %u tomorrow is %u",
139 (unsigned int)today_time, (unsigned int)nextsec_time,
140 (unsigned int)tomorrow);
141 bytes_in = bytes_out = pkts_in = pkts_out = 0;
142
143 strncpy(seclog_fn, seclog_fn_base, seclog_fn_len);
144 strncat(seclog_fn, date_to_yyyymmdd(now), seclog_fn_len);
145
146 fd = seclog_open();
147 if (fd == -1)
148 err(1, "couldn't open(\"%s\") for append", seclog_fn);
149
150 buf = str_make();
151 str_appendf(buf, "# logging started at %s (%u)\n",
152 fmt_date(today_time), (unsigned int)today_time);
153 str_extract(buf, &len, &s);
154 (void)write(fd, s, len); /* ignore write errors */
155 close(fd);
156 free(s);
157 }
158
159 void
160 seclog_free(void)
161 {
162 int fd;
163 struct str *buf;
164 char *s;
165 size_t len;
166
167 today_time = time(NULL);
168
169 /* Emit what's currently accumulated. */
170 seclog_emit();
171
172 fd = seclog_open();
173 if (fd == -1) return;
174
175 buf = str_make();
176 str_appendf(buf, "# logging stopped at %s (%u)\n",
177 fmt_date(today_time), (unsigned int)today_time);
178 str_extract(buf, &len, &s);
179 (void)write(fd, s, len); /* ignore write errors */
180 close(fd);
181 free(s);
182 free(seclog_fn);
183 }
184
185 void
186 seclog_acct(uint64_t amount, enum graph_dir dir)
187 {
188 if (seclog_fn_base == NULL) return; /* disabled */
189
190 /* Check if we need to rotate. */
191 if (now >= nextsec_time) {
192 seclog_emit();
193
194 today_time = now;
195 nextsec_time = nextsec(today_time);
196 bytes_in = bytes_out = pkts_in = pkts_out = 0;
197 verbosef("rotated seclog, nextsec = %u",
198 (unsigned int)nextsec_time);
199 }
200
201 /* Accounting. */
202 if (dir == GRAPH_IN) {
203 bytes_in += amount;
204 pkts_in++;
205 } else {
206 assert(dir == GRAPH_OUT);
207 bytes_out += amount;
208 pkts_out++;
209 }
210 }
211
212 /* vim:set ts=3 sw=3 tw=78 et: */
213