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