Bump copyright years.
[darkstat] / daylog.c
1 /* darkstat 3
2 * copyright (c) 2007-2011 Emil Mikulic.
3 *
4 * daylog.c: daily usage log
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 "err.h"
20 #include "daylog.h"
21 #include "str.h"
22 #include "now.h"
23
24 static const char *daylog_fn = NULL;
25 static time_t today_time, tomorrow_time;
26 static uint64_t bytes_in, bytes_out, pkts_in, pkts_out;
27
28 #define DAYLOG_DATE_LEN 26 /* strlen("1900-01-01 00:00:00 +1234") + 1 */
29 static char datebuf[DAYLOG_DATE_LEN];
30
31 static char *
32 fmt_date(const time_t when)
33 {
34 time_t tmp = when;
35 if (strftime(datebuf, DAYLOG_DATE_LEN,
36 "%Y-%m-%d %H:%M:%S %z", localtime(&tmp) ) == 0)
37 errx(1, "strftime() failed in fmt_date()");
38 return (datebuf);
39 }
40
41 /* Given some time today, find the first second of tomorrow. */
42 static time_t
43 tomorrow(const time_t today)
44 {
45 time_t tmp = today;
46 struct tm tm, *lt;
47
48 lt = localtime(&tmp);
49 memcpy(&tm, lt, sizeof(tm));
50 tm.tm_sec = 0;
51 tm.tm_min = 0;
52 tm.tm_hour = 0;
53 tm.tm_mday = lt->tm_mday + 1; /* tomorrow */
54 return mktime(&tm);
55 }
56
57 static int
58 daylog_open(void)
59 {
60 return open(daylog_fn, O_WRONLY | O_APPEND | O_CREAT | O_NOFOLLOW, 0600);
61 }
62
63 static void
64 daylog_emit(void)
65 {
66 int fd = daylog_open();
67
68 if (fd != -1) {
69 struct str *buf = str_make();
70 char *s;
71 size_t len;
72 str_appendf(buf, "%s|%u|%qu|%qu|%qu|%qu\n",
73 fmt_date(today_time), (unsigned int)today_time,
74 bytes_in, bytes_out, pkts_in, pkts_out);
75 str_extract(buf, &len, &s);
76
77 (void)write(fd, s, len); /* ignore write errors */
78 close(fd);
79 free(s);
80 }
81 }
82
83 void
84 daylog_init(const char *filename)
85 {
86 int fd;
87 struct str *buf;
88 char *s;
89 size_t len;
90
91 daylog_fn = filename;
92 today_time = time(NULL);
93 tomorrow_time = tomorrow(today_time);
94 verbosef("today is %u, tomorrow is %u",
95 (unsigned int)today_time, (unsigned int)tomorrow_time);
96 bytes_in = bytes_out = pkts_in = pkts_out = 0;
97
98 fd = daylog_open();
99 if (fd == -1)
100 err(1, "couldn't open(\"%s\") for append", filename);
101
102 buf = str_make();
103 str_appendf(buf, "# logging started at %s (%u)\n",
104 fmt_date(today_time), (unsigned int)today_time);
105 str_extract(buf, &len, &s);
106 (void)write(fd, s, len); /* ignore write errors */
107 close(fd);
108 free(s);
109 }
110
111 void daylog_free(void)
112 {
113 int fd;
114 struct str *buf;
115 char *s;
116 size_t len;
117
118 today_time = time(NULL);
119
120 /* Emit what's currently accumulated. */
121 daylog_emit();
122
123 fd = daylog_open();
124 if (fd == -1) return;
125
126 buf = str_make();
127 str_appendf(buf, "# logging stopped at %s (%u)\n",
128 fmt_date(today_time), (unsigned int)today_time);
129 str_extract(buf, &len, &s);
130 (void)write(fd, s, len); /* ignore write errors */
131 close(fd);
132 free(s);
133 }
134
135 void
136 daylog_acct(uint64_t amount, enum graph_dir dir)
137 {
138 if (daylog_fn == NULL) return; /* disabled */
139
140 /* Check if we need to rotate. */
141 if (now >= tomorrow_time) {
142 daylog_emit();
143
144 today_time = now;
145 tomorrow_time = tomorrow(today_time);
146 bytes_in = bytes_out = pkts_in = pkts_out = 0;
147 verbosef("rotated daylog, tomorrow = %u",
148 (unsigned int)tomorrow_time);
149 }
150
151 /* Accounting. */
152 if (dir == GRAPH_IN) {
153 bytes_in += amount;
154 pkts_in++;
155 } else {
156 assert(dir == GRAPH_OUT);
157 bytes_out += amount;
158 pkts_out++;
159 }
160 }
161
162 /* vim:set ts=3 sw=3 tw=78 et: */