util.c - quark - quark web server
(HTM) git clone git://git.suckless.org/quark
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) LICENSE
---
util.c (4808B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include <errno.h>
3 #include <limits.h>
4 #include <stdarg.h>
5 #include <stdint.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/types.h>
10 #include <time.h>
11
12 #ifdef __OpenBSD__
13 #include <unistd.h>
14 #endif /* __OpenBSD__ */
15
16 #include "util.h"
17
18 char *argv0;
19
20 static void
21 verr(const char *fmt, va_list ap)
22 {
23 if (argv0 && strncmp(fmt, "usage", sizeof("usage") - 1)) {
24 fprintf(stderr, "%s: ", argv0);
25 }
26
27 vfprintf(stderr, fmt, ap);
28
29 if (fmt[0] && fmt[strlen(fmt) - 1] == ':') {
30 fputc(' ', stderr);
31 perror(NULL);
32 } else {
33 fputc('\n', stderr);
34 }
35 }
36
37 void
38 warn(const char *fmt, ...)
39 {
40 va_list ap;
41
42 va_start(ap, fmt);
43 verr(fmt, ap);
44 va_end(ap);
45 }
46
47 void
48 die(const char *fmt, ...)
49 {
50 va_list ap;
51
52 va_start(ap, fmt);
53 verr(fmt, ap);
54 va_end(ap);
55
56 exit(1);
57 }
58
59 void
60 epledge(const char *promises, const char *execpromises)
61 {
62 (void)promises;
63 (void)execpromises;
64
65 #ifdef __OpenBSD__
66 if (pledge(promises, execpromises) == -1) {
67 die("pledge:");
68 }
69 #endif /* __OpenBSD__ */
70 }
71
72 void
73 eunveil(const char *path, const char *permissions)
74 {
75 (void)path;
76 (void)permissions;
77
78 #ifdef __OpenBSD__
79 if (unveil(path, permissions) == -1) {
80 die("unveil:");
81 }
82 #endif /* __OpenBSD__ */
83 }
84
85 int
86 timestamp(char *buf, size_t len, time_t t)
87 {
88 struct tm tm;
89
90 if (gmtime_r(&t, &tm) == NULL ||
91 strftime(buf, len, "%a, %d %b %Y %T GMT", &tm) == 0) {
92 return 1;
93 }
94
95 return 0;
96 }
97
98 int
99 esnprintf(char *str, size_t size, const char *fmt, ...)
100 {
101 va_list ap;
102 int ret;
103
104 va_start(ap, fmt);
105 ret = vsnprintf(str, size, fmt, ap);
106 va_end(ap);
107
108 return (ret < 0 || (size_t)ret >= size);
109 }
110
111 int
112 prepend(char *str, size_t size, const char *prefix)
113 {
114 size_t len = strlen(str), prefixlen = strlen(prefix);
115
116 if (len + prefixlen + 1 > size) {
117 return 1;
118 }
119
120 memmove(str + prefixlen, str, len + 1);
121 memcpy(str, prefix, prefixlen);
122
123 return 0;
124 }
125
126 int
127 spacetok(const char *s, char **t, size_t tlen)
128 {
129 const char *tok;
130 size_t i, j, toki, spaces;
131
132 /* fill token-array with NULL-pointers */
133 for (i = 0; i < tlen; i++) {
134 t[i] = NULL;
135 }
136 toki = 0;
137
138 /* don't allow NULL string or leading spaces */
139 if (!s || *s == ' ') {
140 return 1;
141 }
142 start:
143 /* skip spaces */
144 for (; *s == ' '; s++)
145 ;
146
147 /* don't allow trailing spaces */
148 if (*s == '\0') {
149 goto err;
150 }
151
152 /* consume token */
153 for (tok = s, spaces = 0; ; s++) {
154 if (*s == '\\' && *(s + 1) == ' ') {
155 spaces++;
156 s++;
157 continue;
158 } else if (*s == ' ') {
159 /* end of token */
160 goto token;
161 } else if (*s == '\0') {
162 /* end of string */
163 goto token;
164 }
165 }
166 token:
167 if (toki >= tlen) {
168 goto err;
169 }
170 if (!(t[toki] = malloc(s - tok - spaces + 1))) {
171 die("malloc:");
172 }
173 for (i = 0, j = 0; j < s - tok - spaces + 1; i++, j++) {
174 if (tok[i] == '\\' && tok[i + 1] == ' ') {
175 i++;
176 }
177 t[toki][j] = tok[i];
178 }
179 t[toki][s - tok - spaces] = '\0';
180 toki++;
181
182 if (*s == ' ') {
183 s++;
184 goto start;
185 }
186
187 return 0;
188 err:
189 for (i = 0; i < tlen; i++) {
190 free(t[i]);
191 t[i] = NULL;
192 }
193
194 return 1;
195 }
196
197
198
199 #define INVALID 1
200 #define TOOSMALL 2
201 #define TOOLARGE 3
202
203 long long
204 strtonum(const char *numstr, long long minval, long long maxval,
205 const char **errstrp)
206 {
207 long long ll = 0;
208 int error = 0;
209 char *ep;
210 struct errval {
211 const char *errstr;
212 int err;
213 } ev[4] = {
214 { NULL, 0 },
215 { "invalid", EINVAL },
216 { "too small", ERANGE },
217 { "too large", ERANGE },
218 };
219
220 ev[0].err = errno;
221 errno = 0;
222 if (minval > maxval) {
223 error = INVALID;
224 } else {
225 ll = strtoll(numstr, &ep, 10);
226 if (numstr == ep || *ep != '\0')
227 error = INVALID;
228 else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
229 error = TOOSMALL;
230 else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
231 error = TOOLARGE;
232 }
233 if (errstrp != NULL)
234 *errstrp = ev[error].errstr;
235 errno = ev[error].err;
236 if (error)
237 ll = 0;
238
239 return ll;
240 }
241
242 /*
243 * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
244 * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
245 */
246 #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
247
248 void *
249 reallocarray(void *optr, size_t nmemb, size_t size)
250 {
251 if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
252 nmemb > 0 && SIZE_MAX / nmemb < size) {
253 errno = ENOMEM;
254 return NULL;
255 }
256 return realloc(optr, size * nmemb);
257 }
258
259 int
260 buffer_appendf(struct buffer *buf, const char *suffixfmt, ...)
261 {
262 va_list ap;
263 int ret;
264
265 va_start(ap, suffixfmt);
266 ret = vsnprintf(buf->data + buf->len,
267 sizeof(buf->data) - buf->len, suffixfmt, ap);
268 va_end(ap);
269
270 if (ret < 0 || (size_t)ret >= (sizeof(buf->data) - buf->len)) {
271 /* truncation occured, discard and error out */
272 memset(buf->data + buf->len, 0,
273 sizeof(buf->data) - buf->len);
274 return 1;
275 }
276
277 /* increase buffer length by number of bytes written */
278 buf->len += ret;
279
280 return 0;
281 }