misc: update copyright years
[rb-79.git] / util.c
blob513d3fa3bf836a6a660506b7e7fb19581008b973
1 /*
2 * Copyright (c) 2017-2018, De Rais <derais@cock.li>
4 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
18 #include <stdint.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <time.h>
24 #include <arpa/inet.h>
26 #include "macros.h"
27 #include "rb79.h"
30 * How many characters are needed to hold "1141709097-06-13 06:26:07Z",
31 * which is the representation of 2^55 - 1, the largest time_t that
32 * this, rather reasonable system can hold.
34 #define ISO8601_MAX 30
37 * Convert t to a string, like "2000-01-01 23:59:59Z"
39 * Preconditions:
41 * - None.
43 * Postconditions:
45 * - Either a string in ISO 8601 format has been returned, or 0
46 * has been returned and an error message has been logged.
48 char * util_iso8601_from_time_t(time_t t)
51 * XXX: If this becomes multithreaded, we have bigger
52 * problems, but we also need to use gmtime_r() or the
53 * equivalent.
55 struct tm *tm = gmtime(&t);
56 char *ret = 0;
58 if (!tm) {
59 ERROR_MESSAGE("gmtime");
61 return 0;
65 * Even if t > 2^55 - 1, this should only truncate the
66 * result, not corrupt memory.
68 if (!(ret = malloc(ISO8601_MAX + 1))) {
69 ERROR_MESSAGE("malloc");
71 return 0;
74 strftime(ret, ISO8601_MAX, "%F %H:%M:%SZ", tm);
76 return ret;
79 /* Put an IP address into a range-comparable form */
80 int util_normalize_ip(const char *in, char **out)
82 int ret = -1;
83 size_t built_len = 0;
84 char *built = 0;
86 if (strchr(in, ':')) {
88 * If your C implementation doesn't implement the
89 * IPV6 functionality, you should be able to simply
90 * lop out this section entirely with no harm done.
92 struct in6_addr a = { 0 };
94 if (inet_pton(AF_INET6, in, &a) != 1) {
95 PERROR_MESSAGE("inet_pton");
96 goto done;
99 built_len = (4 * 8) + 7;
101 if (!(built = malloc(built_len + 1))) {
102 PERROR_MESSAGE("malloc");
103 goto done;
106 sprintf(built, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
107 "%02x%02x:%02x%02x:%02x%02x:%02x%02x", (unsigned
108 int) a.
109 s6_addr[0], (unsigned int) a.s6_addr[1], (unsigned
110 int)
111 a.s6_addr[2], (unsigned int) a.s6_addr[3], (unsigned
112 int)
113 a.s6_addr[4], (unsigned int) a.s6_addr[5], (unsigned
114 int)
115 a.s6_addr[6], (unsigned int) a.s6_addr[7], (unsigned
116 int)
117 a.s6_addr[8], (unsigned int) a.s6_addr[9], (unsigned
118 int)
119 a.s6_addr[10], (unsigned int) a.s6_addr[11], (unsigned
120 int)
121 a.s6_addr[12], (unsigned int) a.s6_addr[13], (unsigned
122 int)
123 a.s6_addr[14], (unsigned int) a.s6_addr[15]);
124 } else if (strchr(in, '.')) {
125 struct in_addr a = { 0 };
127 if (inet_pton(AF_INET, in, &a) != 1) {
128 PERROR_MESSAGE("inet_pton");
129 goto done;
132 built_len = (3 * 4) + 3;
134 if (!(built = malloc(built_len + 1))) {
135 PERROR_MESSAGE("malloc");
136 goto done;
139 sprintf(built, "%03u.%03u.%03u.%03u", /* */
140 (a.s_addr & 0x000000ff) >> 0, /* */
141 (a.s_addr & 0x0000ff00) >> 8, /* */
142 (a.s_addr & 0x00ff0000) >> 16, /* */
143 (a.s_addr & 0xff000000) >> 24 /* */
145 } else {
146 ERROR_MESSAGE("\"%s\" is not a valid IP address", in);
147 goto done;
150 ret = 0;
151 done:
153 if (ret) {
154 free(built);
155 } else {
156 *out = built;
159 return ret;
163 * Call wt_write_thread and wt_write_board on everything
165 * Note: this ACQUIRES all locks, which means it must be called
166 * with NO LOCKS acquired
168 int util_rebuild(struct configuration *conf)
170 uint_fast8_t had_errors = 0;
172 for (size_t j = 0; j < conf->boards_num; ++j) {
173 uint_fast8_t need_to_unlock = 0;
174 uintmax_t *thread_ids = 0;
175 size_t thread_ids_num = 0;
176 size_t board_pages_num = 0;
178 if (lock_acquire(j) < 0) {
179 LOG("Error in lock_acquire (500)");
180 had_errors = 1;
181 goto done;
184 need_to_unlock = 1;
186 if (db_cull_and_report_threads(j, &thread_ids, &thread_ids_num,
187 &board_pages_num) < 0) {
188 LOG("Error in db_cull_and_report_threads (j = %zu)", j);
189 goto done_with_this_board;
192 for (size_t k = 0; k < thread_ids_num; ++k) {
193 if (wt_write_thread(j, thread_ids[k]) < 0) {
194 LOG("Error in wt_write_thread (j = %zu, "
195 "thread_ids[k] = %ju)", j, thread_ids[k]);
196 had_errors = 1;
200 wt_write_board(j, thread_ids, thread_ids_num, board_pages_num);
201 done_with_this_board:
203 if (need_to_unlock) {
204 lock_release(j);
208 if (lock_acquire_recent() < 0) {
209 LOG("Error in lock_acquire_recent (500)");
210 had_errors = 1;
211 goto done;
214 wt_write_recent_page();
215 lock_release_recent();
216 done:
218 return had_errors;