util.c - quark - quark web server | |
git clone git://git.suckless.org/quark | |
Log | |
Files | |
Refs | |
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 < mi… | |
229 error = TOOSMALL; | |
230 else if ((ll == LLONG_MAX && errno == ERANGE) || ll > ma… | |
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 } |