server: handle pcre2 now returning -1 for "no match"
[rb-79.git] / util.c
blob6d67bb841abeb172ddeeeda8a0d2597df15d7208
1 /*
2 * Copyright (c) 2017-2020, 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>
25 #include <netinet/in.h>
26 #include <sys/socket.h>
27 #include <sys/types.h>
29 #include "macros.h"
30 #include "rb79.h"
33 * How many characters are needed to hold "1141709097-06-13 06:26:07Z",
34 * which is the representation of 2^55 - 1, the largest time_t that
35 * this, rather reasonable system can hold.
37 #define ISO8601_MAX 30
40 * Convert t to a string, like "2000-01-01 23:59:59Z"
42 * Preconditions:
44 * - None.
46 * Postconditions:
48 * - Either a string in ISO 8601 format has been returned, or 0
49 * has been returned and an error message has been logged.
51 char *
52 util_iso8601_from_time_t(time_t t)
55 * XXX: If this becomes multithreaded, we have bigger
56 * problems, but we also need to use gmtime_r() or the
57 * equivalent.
59 struct tm *tm = gmtime(&t);
60 char *ret = 0;
62 if (!tm) {
63 ERROR_MESSAGE("gmtime");
65 return 0;
69 * Even if t > 2^55 - 1, this should only truncate the
70 * result, not corrupt memory.
72 if (!(ret = malloc(ISO8601_MAX + 1))) {
73 ERROR_MESSAGE("malloc");
75 return 0;
78 strftime(ret, ISO8601_MAX, "%F %H:%M:%SZ", tm);
80 return ret;
83 /* Put an IP address into a range-comparable form */
84 int
85 util_normalize_ip(const char *in, char **out)
87 int ret = -1;
88 size_t built_len = 0;
89 char *built = 0;
91 if (strchr(in, ':')) {
93 * If your C implementation doesn't implement the
94 * IPV6 functionality, you should be able to simply
95 * lop out this section entirely with no harm done.
97 struct in6_addr a = { 0 };
99 if (inet_pton(AF_INET6, in, &a) != 1) {
100 PERROR_MESSAGE("inet_pton");
101 goto done;
104 built_len = (4 * 8) + 7;
106 if (!(built = malloc(built_len + 1))) {
107 PERROR_MESSAGE("malloc");
108 goto done;
111 sprintf(built, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
112 "%02x%02x:%02x%02x:%02x%02x:%02x%02x", (unsigned
113 int) a.
114 s6_addr[0], (unsigned int) a.s6_addr[1], (unsigned
115 int)
116 a.s6_addr[2], (unsigned int) a.s6_addr[3], (unsigned
117 int)
118 a.s6_addr[4], (unsigned int) a.s6_addr[5], (unsigned
119 int)
120 a.s6_addr[6], (unsigned int) a.s6_addr[7], (unsigned
121 int)
122 a.s6_addr[8], (unsigned int) a.s6_addr[9], (unsigned
123 int)
124 a.s6_addr[10], (unsigned int) a.s6_addr[11], (unsigned
125 int)
126 a.s6_addr[12], (unsigned int) a.s6_addr[13], (unsigned
127 int)
128 a.s6_addr[14], (unsigned int) a.s6_addr[15]);
129 } else if (strchr(in, '.')) {
130 struct in_addr a = { 0 };
132 if (inet_pton(AF_INET, in, &a) != 1) {
133 PERROR_MESSAGE("inet_pton");
134 goto done;
137 built_len = (3 * 4) + 3;
139 if (!(built = malloc(built_len + 1))) {
140 PERROR_MESSAGE("malloc");
141 goto done;
144 sprintf(built, "%03u.%03u.%03u.%03u", /* */
145 (a.s_addr & 0x000000ff) >> 0, /* */
146 (a.s_addr & 0x0000ff00) >> 8, /* */
147 (a.s_addr & 0x00ff0000) >> 16, /* */
148 (a.s_addr & 0xff000000) >> 24 /* */
150 } else {
151 ERROR_MESSAGE("\"%s\" is not a valid IP address", in);
152 goto done;
155 ret = 0;
156 done:
158 if (ret) {
159 free(built);
160 } else {
161 *out = built;
164 return ret;
168 * Call wt_write_thread and wt_write_board on everything
170 * Note: this ACQUIRES all locks, which means it must be called
171 * with NO LOCKS acquired
174 util_rebuild(struct configuration *conf)
176 uint_fast8_t had_errors = 0;
178 for (size_t j = 0; j < conf->boards_num; ++j) {
179 uint_fast8_t need_to_unlock = 0;
180 uintmax_t *thread_ids = 0;
181 size_t thread_ids_num = 0;
182 size_t board_pages_num = 0;
184 if (lock_acquire(j) < 0) {
185 LOG("Error in lock_acquire (500)");
186 had_errors = 1;
187 goto done;
190 need_to_unlock = 1;
192 if (db_cull_and_report_threads(j, &thread_ids, &thread_ids_num,
193 &board_pages_num) < 0) {
194 LOG("Error in db_cull_and_report_threads (j = %zu)", j);
195 goto done_with_this_board;
198 for (size_t k = 0; k < thread_ids_num; ++k) {
199 if (wt_write_thread(j, thread_ids[k]) < 0) {
200 LOG("Error in wt_write_thread (j = %zu, "
201 "thread_ids[k] = %ju)", j, thread_ids[k]);
202 had_errors = 1;
206 wt_write_board(j, thread_ids, thread_ids_num, board_pages_num);
207 done_with_this_board:
209 if (need_to_unlock) {
210 lock_release(j);
214 if (lock_acquire_recent() < 0) {
215 LOG("Error in lock_acquire_recent (500)");
216 had_errors = 1;
217 goto done;
220 wt_write_recent_page();
221 lock_release_recent();
222 done:
224 return had_errors;