File: | src/usr.sbin/httpd/httpd.c |
Warning: | line 533, column 6 Although the value stored to 'q' is used in the enclosing expression, the value is never actually read from 'q' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: httpd.c,v 1.71 2021/01/27 07:21:52 deraadt Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org> |
5 | * |
6 | * Permission to use, copy, modify, and distribute this software for any |
7 | * purpose with or without fee is hereby granted, provided that the above |
8 | * copyright notice and this permission notice appear in all copies. |
9 | * |
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 | */ |
18 | |
19 | #include <sys/types.h> |
20 | #include <sys/queue.h> |
21 | #include <sys/socket.h> |
22 | #include <sys/stat.h> |
23 | #include <sys/resource.h> |
24 | |
25 | #include <netinet/in.h> |
26 | #include <arpa/inet.h> |
27 | |
28 | #include <stdio.h> |
29 | #include <stdlib.h> |
30 | #include <stdarg.h> |
31 | #include <string.h> |
32 | #include <signal.h> |
33 | #include <getopt.h> |
34 | #include <netdb.h> |
35 | #include <fnmatch.h> |
36 | #include <err.h> |
37 | #include <errno(*__errno()).h> |
38 | #include <event.h> |
39 | #include <syslog.h> |
40 | #include <unistd.h> |
41 | #include <ctype.h> |
42 | #include <pwd.h> |
43 | |
44 | #include "httpd.h" |
45 | |
46 | #define MAXIMUM(a, b)(((a) > (b)) ? (a) : (b)) (((a) > (b)) ? (a) : (b)) |
47 | |
48 | __dead__attribute__((__noreturn__)) void usage(void); |
49 | |
50 | int parent_configure(struct httpd *); |
51 | void parent_configure_done(struct httpd *); |
52 | void parent_reload(struct httpd *, unsigned int, const char *); |
53 | void parent_reopen(struct httpd *); |
54 | void parent_sig_handler(int, short, void *); |
55 | void parent_shutdown(struct httpd *); |
56 | int parent_dispatch_server(int, struct privsep_proc *, |
57 | struct imsg *); |
58 | int parent_dispatch_logger(int, struct privsep_proc *, |
59 | struct imsg *); |
60 | void parent_tls_ticket_rekey_start(struct server *); |
61 | void parent_tls_ticket_rekey(int, short, void *); |
62 | |
63 | struct httpd *httpd_env; |
64 | |
65 | static struct privsep_proc procs[] = { |
66 | { "server", PROC_SERVER, parent_dispatch_server, server }, |
67 | { "logger", PROC_LOGGER, parent_dispatch_logger, logger } |
68 | }; |
69 | |
70 | enum privsep_procid privsep_process; |
71 | |
72 | void |
73 | parent_sig_handler(int sig, short event, void *arg) |
74 | { |
75 | struct privsep *ps = arg; |
76 | |
77 | switch (sig) { |
78 | case SIGTERM15: |
79 | case SIGINT2: |
80 | parent_shutdown(ps->ps_env); |
81 | break; |
82 | case SIGHUP1: |
83 | log_info("%s: reload requested with SIGHUP", __func__); |
84 | |
85 | /* |
86 | * This is safe because libevent uses async signal handlers |
87 | * that run in the event loop and not in signal context. |
88 | */ |
89 | parent_reload(ps->ps_env, CONFIG_RELOAD0x00, NULL((void*)0)); |
90 | break; |
91 | case SIGPIPE13: |
92 | /* ignore */ |
93 | break; |
94 | case SIGUSR130: |
95 | log_info("%s: reopen requested with SIGUSR1", __func__); |
96 | |
97 | parent_reopen(ps->ps_env); |
98 | break; |
99 | default: |
100 | fatalx("unexpected signal"); |
101 | } |
102 | } |
103 | |
104 | __dead__attribute__((__noreturn__)) void |
105 | usage(void) |
106 | { |
107 | extern char *__progname; |
108 | |
109 | fprintf(stderr(&__sF[2]), "usage: %s [-dnv] [-D macro=value] [-f file]\n", |
110 | __progname); |
111 | exit(1); |
112 | } |
113 | |
114 | int |
115 | main(int argc, char *argv[]) |
116 | { |
117 | int c; |
118 | unsigned int proc; |
119 | int debug = 0, verbose = 0; |
120 | uint32_t opts = 0; |
121 | struct httpd *env; |
122 | struct privsep *ps; |
123 | const char *conffile = CONF_FILE"/etc/httpd.conf"; |
124 | enum privsep_procid proc_id = PROC_PARENT; |
125 | int proc_instance = 0; |
126 | const char *errp, *title = NULL((void*)0); |
127 | int argc0 = argc; |
128 | |
129 | while ((c = getopt(argc, argv, "dD:nf:I:P:v")) != -1) { |
130 | switch (c) { |
131 | case 'd': |
132 | debug = 2; |
133 | break; |
134 | case 'D': |
135 | if (cmdline_symset(optarg) < 0) |
136 | log_warnx("could not parse macro definition %s", |
137 | optarg); |
138 | break; |
139 | case 'n': |
140 | debug = 2; |
141 | opts |= HTTPD_OPT_NOACTION0x04; |
142 | break; |
143 | case 'f': |
144 | conffile = optarg; |
145 | break; |
146 | case 'v': |
147 | verbose++; |
148 | opts |= HTTPD_OPT_VERBOSE0x01; |
149 | break; |
150 | case 'P': |
151 | title = optarg; |
152 | proc_id = proc_getid(procs, nitems(procs)(sizeof((procs)) / sizeof((procs)[0])), title); |
153 | if (proc_id == PROC_MAX) |
154 | fatalx("invalid process name"); |
155 | break; |
156 | case 'I': |
157 | proc_instance = strtonum(optarg, 0, |
158 | PROC_MAX_INSTANCES32, &errp); |
159 | if (errp) |
160 | fatalx("invalid process instance"); |
161 | break; |
162 | default: |
163 | usage(); |
164 | } |
165 | } |
166 | |
167 | /* log to stderr until daemonized */ |
168 | log_init(debug ? debug : 1, LOG_DAEMON(3<<3)); |
169 | |
170 | argc -= optind; |
171 | if (argc > 0) |
172 | usage(); |
173 | |
174 | if ((env = calloc(1, sizeof(*env))) == NULL((void*)0) || |
175 | (ps = calloc(1, sizeof(*ps))) == NULL((void*)0)) |
176 | exit(1); |
177 | |
178 | httpd_env = env; |
179 | env->sc_ps = ps; |
180 | ps->ps_env = env; |
181 | TAILQ_INIT(&ps->ps_rcsocks)do { (&ps->ps_rcsocks)->tqh_first = ((void*)0); (& ps->ps_rcsocks)->tqh_last = &(&ps->ps_rcsocks )->tqh_first; } while (0); |
182 | env->sc_conffile = conffile; |
183 | env->sc_opts = opts; |
184 | |
185 | if (parse_config(env->sc_conffile, env) == -1) |
186 | exit(1); |
187 | |
188 | if (geteuid()) |
189 | errx(1, "need root privileges"); |
190 | |
191 | if ((ps->ps_pw = getpwnam(HTTPD_USER"www")) == NULL((void*)0)) |
192 | errx(1, "unknown user %s", HTTPD_USER"www"); |
193 | |
194 | /* Configure the control socket */ |
195 | ps->ps_csock.cs_name = NULL((void*)0); |
196 | |
197 | log_init(debug, LOG_DAEMON(3<<3)); |
198 | log_setverbose(verbose); |
199 | |
200 | if (env->sc_opts & HTTPD_OPT_NOACTION0x04) |
201 | ps->ps_noaction = 1; |
202 | |
203 | ps->ps_instances[PROC_SERVER] = env->sc_prefork_server; |
204 | ps->ps_instance = proc_instance; |
205 | if (title != NULL((void*)0)) |
206 | ps->ps_title[proc_id] = title; |
207 | |
208 | if (env->sc_chroot == NULL((void*)0)) |
209 | env->sc_chroot = ps->ps_pw->pw_dir; |
210 | for (proc = 0; proc < nitems(procs)(sizeof((procs)) / sizeof((procs)[0])); proc++) |
211 | procs[proc].p_chroot = env->sc_chroot; |
212 | |
213 | if (env->sc_logdir == NULL((void*)0)) { |
214 | if (asprintf(&env->sc_logdir, "%s%s", env->sc_chroot, |
215 | HTTPD_LOGROOT"/logs") == -1) |
216 | errx(1, "malloc failed"); |
217 | } |
218 | |
219 | /* only the parent returns */ |
220 | proc_init(ps, procs, nitems(procs)(sizeof((procs)) / sizeof((procs)[0])), debug, argc0, argv, proc_id); |
221 | |
222 | log_procinit("parent"); |
223 | if (!debug && daemon(1, 0) == -1) |
224 | err(1, "failed to daemonize"); |
225 | |
226 | if (ps->ps_noaction == 0) |
227 | log_info("startup"); |
228 | |
229 | if (pledge("stdio rpath wpath cpath inet dns sendfd", NULL((void*)0)) == -1) |
230 | fatal("pledge"); |
231 | |
232 | event_init(); |
233 | |
234 | signal_set(&ps->ps_evsigint, SIGINT, parent_sig_handler, ps)event_set(&ps->ps_evsigint, 2, 0x08|0x10, parent_sig_handler , ps); |
235 | signal_set(&ps->ps_evsigterm, SIGTERM, parent_sig_handler, ps)event_set(&ps->ps_evsigterm, 15, 0x08|0x10, parent_sig_handler , ps); |
236 | signal_set(&ps->ps_evsighup, SIGHUP, parent_sig_handler, ps)event_set(&ps->ps_evsighup, 1, 0x08|0x10, parent_sig_handler , ps); |
237 | signal_set(&ps->ps_evsigpipe, SIGPIPE, parent_sig_handler, ps)event_set(&ps->ps_evsigpipe, 13, 0x08|0x10, parent_sig_handler , ps); |
238 | signal_set(&ps->ps_evsigusr1, SIGUSR1, parent_sig_handler, ps)event_set(&ps->ps_evsigusr1, 30, 0x08|0x10, parent_sig_handler , ps); |
239 | |
240 | signal_add(&ps->ps_evsigint, NULL)event_add(&ps->ps_evsigint, ((void*)0)); |
241 | signal_add(&ps->ps_evsigterm, NULL)event_add(&ps->ps_evsigterm, ((void*)0)); |
242 | signal_add(&ps->ps_evsighup, NULL)event_add(&ps->ps_evsighup, ((void*)0)); |
243 | signal_add(&ps->ps_evsigpipe, NULL)event_add(&ps->ps_evsigpipe, ((void*)0)); |
244 | signal_add(&ps->ps_evsigusr1, NULL)event_add(&ps->ps_evsigusr1, ((void*)0)); |
245 | |
246 | proc_connect(ps); |
247 | |
248 | if (load_config(env->sc_conffile, env) == -1) { |
249 | proc_kill(env->sc_ps); |
250 | exit(1); |
251 | } |
252 | |
253 | if (env->sc_opts & HTTPD_OPT_NOACTION0x04) { |
254 | fprintf(stderr(&__sF[2]), "configuration OK\n"); |
255 | proc_kill(env->sc_ps); |
256 | exit(0); |
257 | } |
258 | |
259 | /* initialize the TLS session id to a random key for all procs */ |
260 | arc4random_buf(env->sc_tls_sid, sizeof(env->sc_tls_sid)); |
261 | |
262 | if (parent_configure(env) == -1) |
263 | fatalx("configuration failed"); |
264 | |
265 | event_dispatch(); |
266 | |
267 | parent_shutdown(env); |
268 | /* NOTREACHED */ |
269 | |
270 | return (0); |
271 | } |
272 | |
273 | int |
274 | parent_configure(struct httpd *env) |
275 | { |
276 | int id; |
277 | struct ctl_flags cf; |
278 | int ret = -1; |
279 | struct server *srv; |
280 | struct media_type *media; |
281 | struct auth *auth; |
282 | |
283 | RB_FOREACH(media, mediatypes, env->sc_mediatypes)for ((media) = mediatypes_RB_MINMAX(env->sc_mediatypes, -1 ); (media) != ((void*)0); (media) = mediatypes_RB_NEXT(media) ) { |
284 | if (config_setmedia(env, media) == -1) |
285 | fatal("send media"); |
286 | } |
287 | |
288 | TAILQ_FOREACH(auth, env->sc_auth, auth_entry)for((auth) = ((env->sc_auth)->tqh_first); (auth) != ((void *)0); (auth) = ((auth)->auth_entry.tqe_next)) { |
289 | if (config_setauth(env, auth) == -1) |
290 | fatal("send auth"); |
291 | } |
292 | |
293 | /* First send the servers... */ |
294 | TAILQ_FOREACH(srv, env->sc_servers, srv_entry)for((srv) = ((env->sc_servers)->tqh_first); (srv) != (( void*)0); (srv) = ((srv)->srv_entry.tqe_next)) { |
295 | if (srv->srv_conf.flags & SRVFLAG_LOCATION0x00000020) |
296 | continue; |
297 | /* start the rekey of the tls ticket keys */ |
298 | if (srv->srv_conf.flags & SRVFLAG_TLS0x00002000 && |
299 | srv->srv_conf.tls_ticket_lifetime) |
300 | parent_tls_ticket_rekey_start(srv); |
301 | if (config_setserver(env, srv) == -1) |
302 | fatal("send server"); |
303 | } |
304 | /* ...and now send the locations */ |
305 | TAILQ_FOREACH(srv, env->sc_servers, srv_entry)for((srv) = ((env->sc_servers)->tqh_first); (srv) != (( void*)0); (srv) = ((srv)->srv_entry.tqe_next)) { |
306 | if ((srv->srv_conf.flags & SRVFLAG_LOCATION0x00000020) == 0) |
307 | continue; |
308 | if (config_setserver(env, srv) == -1) |
309 | fatal("send location"); |
310 | } |
311 | |
312 | /* The servers need to reload their config. */ |
313 | env->sc_reload = env->sc_prefork_server + 1; |
314 | |
315 | for (id = 0; id < PROC_MAX; id++) { |
316 | if (id == privsep_process) |
317 | continue; |
318 | cf.cf_opts = env->sc_opts; |
319 | cf.cf_flags = env->sc_flags; |
320 | memcpy(cf.cf_tls_sid, env->sc_tls_sid, sizeof(cf.cf_tls_sid)); |
321 | |
322 | proc_compose(env->sc_ps, id, IMSG_CFG_DONE, &cf, sizeof(cf)); |
323 | } |
324 | |
325 | ret = 0; |
326 | |
327 | config_purge(env, CONFIG_ALL0xff & ~CONFIG_SERVERS0x02); |
328 | return (ret); |
329 | } |
330 | |
331 | void |
332 | parent_reload(struct httpd *env, unsigned int reset, const char *filename) |
333 | { |
334 | if (env->sc_reload) { |
335 | log_debug("%s: already in progress: %d pending", |
336 | __func__, env->sc_reload); |
337 | return; |
338 | } |
339 | |
340 | /* Switch back to the default config file */ |
341 | if (filename == NULL((void*)0) || *filename == '\0') |
342 | filename = env->sc_conffile; |
343 | |
344 | log_debug("%s: level %d config file %s", __func__, reset, filename); |
345 | |
346 | config_purge(env, CONFIG_ALL0xff); |
347 | |
348 | if (reset == CONFIG_RELOAD0x00) { |
349 | if (load_config(filename, env) == -1) { |
350 | log_debug("%s: failed to load config file %s", |
351 | __func__, filename); |
352 | } |
353 | |
354 | config_setreset(env, CONFIG_ALL0xff); |
355 | |
356 | if (parent_configure(env) == -1) { |
357 | log_debug("%s: failed to commit config from %s", |
358 | __func__, filename); |
359 | } |
360 | } else |
361 | config_setreset(env, reset); |
362 | } |
363 | |
364 | void |
365 | parent_reopen(struct httpd *env) |
366 | { |
367 | proc_compose(env->sc_ps, PROC_LOGGER, IMSG_CTL_REOPEN, NULL((void*)0), 0); |
368 | } |
369 | |
370 | void |
371 | parent_configure_done(struct httpd *env) |
372 | { |
373 | int id; |
374 | |
375 | if (env->sc_reload == 0) { |
376 | log_warnx("%s: configuration already finished", __func__); |
377 | return; |
378 | } |
379 | |
380 | env->sc_reload--; |
381 | if (env->sc_reload == 0) { |
382 | for (id = 0; id < PROC_MAX; id++) { |
383 | if (id == privsep_process) |
384 | continue; |
385 | |
386 | proc_compose(env->sc_ps, id, IMSG_CTL_START, NULL((void*)0), 0); |
387 | } |
388 | } |
389 | } |
390 | |
391 | void |
392 | parent_shutdown(struct httpd *env) |
393 | { |
394 | config_purge(env, CONFIG_ALL0xff); |
395 | |
396 | proc_kill(env->sc_ps); |
397 | control_cleanup(&env->sc_ps->ps_csock); |
398 | if (env->sc_ps->ps_csock.cs_name != NULL((void*)0)) |
399 | (void)unlink(env->sc_ps->ps_csock.cs_name); |
400 | |
401 | free(env->sc_ps); |
402 | free(env); |
403 | |
404 | log_info("parent terminating, pid %d", getpid()); |
405 | |
406 | exit(0); |
407 | } |
408 | |
409 | int |
410 | parent_dispatch_server(int fd, struct privsep_proc *p, struct imsg *imsg) |
411 | { |
412 | struct privsep *ps = p->p_ps; |
413 | struct httpd *env = ps->ps_env; |
414 | |
415 | switch (imsg->hdr.type) { |
416 | case IMSG_CFG_DONE: |
417 | parent_configure_done(env); |
418 | break; |
419 | default: |
420 | return (-1); |
421 | } |
422 | |
423 | return (0); |
424 | } |
425 | |
426 | int |
427 | parent_dispatch_logger(int fd, struct privsep_proc *p, struct imsg *imsg) |
428 | { |
429 | struct privsep *ps = p->p_ps; |
430 | struct httpd *env = ps->ps_env; |
431 | unsigned int v; |
432 | char *str = NULL((void*)0); |
433 | |
434 | switch (imsg->hdr.type) { |
435 | case IMSG_CTL_RESET: |
436 | IMSG_SIZE_CHECK(imsg, &v)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof (*&v)) fatalx("bad length imsg received"); } while (0); |
437 | memcpy(&v, imsg->data, sizeof(v)); |
438 | parent_reload(env, v, NULL((void*)0)); |
439 | break; |
440 | case IMSG_CTL_RELOAD: |
441 | if (IMSG_DATA_SIZE(imsg)((imsg)->hdr.len - sizeof(struct imsg_hdr)) > 0) |
442 | str = get_string(imsg->data, IMSG_DATA_SIZE(imsg)((imsg)->hdr.len - sizeof(struct imsg_hdr))); |
443 | parent_reload(env, CONFIG_RELOAD0x00, str); |
444 | free(str); |
445 | break; |
446 | case IMSG_CTL_SHUTDOWN: |
447 | parent_shutdown(env); |
448 | break; |
449 | case IMSG_CTL_REOPEN: |
450 | parent_reopen(env); |
451 | break; |
452 | case IMSG_CFG_DONE: |
453 | parent_configure_done(env); |
454 | break; |
455 | case IMSG_LOG_OPEN: |
456 | if (logger_open_priv(imsg) == -1) |
457 | fatalx("failed to open log file"); |
458 | break; |
459 | default: |
460 | return (-1); |
461 | } |
462 | |
463 | return (0); |
464 | } |
465 | |
466 | void |
467 | parent_tls_ticket_rekey_start(struct server *srv) |
468 | { |
469 | struct timeval tv; |
470 | |
471 | server_generate_ticket_key(&srv->srv_conf); |
472 | |
473 | evtimer_set(&srv->srv_evt, parent_tls_ticket_rekey, srv)event_set(&srv->srv_evt, -1, 0, parent_tls_ticket_rekey , srv); |
474 | timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0; |
475 | tv.tv_sec = srv->srv_conf.tls_ticket_lifetime / 4; |
476 | evtimer_add(&srv->srv_evt, &tv)event_add(&srv->srv_evt, &tv); |
477 | } |
478 | |
479 | void |
480 | parent_tls_ticket_rekey(int fd, short events, void *arg) |
481 | { |
482 | struct server *srv = arg; |
483 | struct timeval tv; |
484 | |
485 | server_generate_ticket_key(&srv->srv_conf); |
486 | proc_compose_imsg(httpd_env->sc_ps, PROC_SERVER, -1, |
487 | IMSG_TLSTICKET_REKEY, -1, -1, &srv->srv_conf.tls_ticket_key, |
488 | sizeof(srv->srv_conf.tls_ticket_key)); |
489 | explicit_bzero(&srv->srv_conf.tls_ticket_key, |
490 | sizeof(srv->srv_conf.tls_ticket_key)); |
491 | |
492 | evtimer_set(&srv->srv_evt, parent_tls_ticket_rekey, srv)event_set(&srv->srv_evt, -1, 0, parent_tls_ticket_rekey , srv); |
493 | timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0; |
494 | tv.tv_sec = srv->srv_conf.tls_ticket_lifetime / 4; |
495 | evtimer_add(&srv->srv_evt, &tv)event_add(&srv->srv_evt, &tv); |
496 | } |
497 | |
498 | /* |
499 | * Utility functions |
500 | */ |
501 | |
502 | void |
503 | event_again(struct event *ev, int fd, short event, |
504 | void (*fn)(int, short, void *), |
505 | struct timeval *start, struct timeval *end, void *arg) |
506 | { |
507 | struct timeval tv_next, tv_now, tv; |
508 | |
509 | getmonotime(&tv_now); |
510 | memcpy(&tv_next, end, sizeof(tv_next)); |
511 | timersub(&tv_now, start, &tv_now)do { (&tv_now)->tv_sec = (&tv_now)->tv_sec - (start )->tv_sec; (&tv_now)->tv_usec = (&tv_now)->tv_usec - (start)->tv_usec; if ((&tv_now)->tv_usec < 0) { (&tv_now)->tv_sec--; (&tv_now)->tv_usec += 1000000 ; } } while (0); |
512 | timersub(&tv_next, &tv_now, &tv_next)do { (&tv_next)->tv_sec = (&tv_next)->tv_sec - ( &tv_now)->tv_sec; (&tv_next)->tv_usec = (&tv_next )->tv_usec - (&tv_now)->tv_usec; if ((&tv_next) ->tv_usec < 0) { (&tv_next)->tv_sec--; (&tv_next )->tv_usec += 1000000; } } while (0); |
513 | |
514 | memset(&tv, 0, sizeof(tv)); |
515 | if (timercmp(&tv_next, &tv, >)(((&tv_next)->tv_sec == (&tv)->tv_sec) ? ((& tv_next)->tv_usec > (&tv)->tv_usec) : ((&tv_next )->tv_sec > (&tv)->tv_sec))) |
516 | memcpy(&tv, &tv_next, sizeof(tv)); |
517 | |
518 | event_del(ev); |
519 | event_set(ev, fd, event, fn, arg); |
520 | event_add(ev, &tv); |
521 | } |
522 | |
523 | int |
524 | expand_string(char *label, size_t len, const char *srch, const char *repl) |
525 | { |
526 | char *tmp; |
527 | char *p, *q; |
528 | |
529 | if ((tmp = calloc(1, len)) == NULL((void*)0)) { |
530 | log_debug("%s: calloc", __func__); |
531 | return (-1); |
532 | } |
533 | p = q = label; |
Although the value stored to 'q' is used in the enclosing expression, the value is never actually read from 'q' | |
534 | while ((q = strstr(p, srch)) != NULL((void*)0)) { |
535 | *q = '\0'; |
536 | if ((strlcat(tmp, p, len) >= len) || |
537 | (strlcat(tmp, repl, len) >= len)) { |
538 | log_debug("%s: string too long", __func__); |
539 | free(tmp); |
540 | return (-1); |
541 | } |
542 | q += strlen(srch); |
543 | p = q; |
544 | } |
545 | if (strlcat(tmp, p, len) >= len) { |
546 | log_debug("%s: string too long", __func__); |
547 | free(tmp); |
548 | return (-1); |
549 | } |
550 | (void)strlcpy(label, tmp, len); /* always fits */ |
551 | free(tmp); |
552 | |
553 | return (0); |
554 | } |
555 | |
556 | const char * |
557 | url_decode(char *url) |
558 | { |
559 | char *p, *q; |
560 | char hex[3]; |
561 | unsigned long x; |
562 | |
563 | hex[2] = '\0'; |
564 | p = q = url; |
565 | |
566 | while (*p != '\0') { |
567 | switch (*p) { |
568 | case '%': |
569 | /* Encoding character is followed by two hex chars */ |
570 | if (!(isxdigit((unsigned char)p[1]) && |
571 | isxdigit((unsigned char)p[2]))) |
572 | return (NULL((void*)0)); |
573 | |
574 | hex[0] = p[1]; |
575 | hex[1] = p[2]; |
576 | |
577 | /* |
578 | * We don't have to validate "hex" because it is |
579 | * guaranteed to include two hex chars followed by nul. |
580 | */ |
581 | x = strtoul(hex, NULL((void*)0), 16); |
582 | *q = (char)x; |
583 | p += 2; |
584 | break; |
585 | default: |
586 | *q = *p; |
587 | break; |
588 | } |
589 | p++; |
590 | q++; |
591 | } |
592 | *q = '\0'; |
593 | |
594 | return (url); |
595 | } |
596 | |
597 | const char * |
598 | canonicalize_path(const char *input, char *path, size_t len) |
599 | { |
600 | const char *i; |
601 | char *p, *start, *end; |
602 | |
603 | /* assuming input starts with '/' and is nul-terminated */ |
604 | i = input; |
605 | p = path; |
606 | |
607 | if (*input != '/' || len < 3) |
608 | return (NULL((void*)0)); |
609 | |
610 | start = p; |
611 | end = p + (len - 1); |
612 | |
613 | while (*i != '\0') { |
614 | /* Detect truncation */ |
615 | if (p >= end) |
616 | return (NULL((void*)0)); |
617 | |
618 | /* 1. check for special path elements */ |
619 | if (i[0] == '/') { |
620 | if (i[1] == '/') { |
621 | /* a) skip repeating '//' slashes */ |
622 | while (i[1] == '/') |
623 | i++; |
624 | continue; |
625 | } else if (i[1] == '.' && i[2] == '.' && |
626 | (i[3] == '/' || i[3] == '\0')) { |
627 | /* b) revert '..' to previous directory */ |
628 | i += 3; |
629 | while (p > start && *p != '/') |
630 | p--; |
631 | *p = '\0'; |
632 | continue; |
633 | } else if (i[1] == '.' && |
634 | (i[2] == '/' || i[2] == '\0')) { |
635 | /* c) skip unnecessary '.' current dir */ |
636 | i += 2; |
637 | continue; |
638 | } |
639 | } |
640 | |
641 | /* 2. copy any other characters */ |
642 | *p++ = *i; |
643 | i++; |
644 | } |
645 | if (p == start) |
646 | *p++ = '/'; |
647 | *p++ = '\0'; |
648 | |
649 | return (path); |
650 | } |
651 | |
652 | size_t |
653 | path_info(char *path) |
654 | { |
655 | char *p, *start, *end, ch; |
656 | struct stat st; |
657 | int ret; |
658 | |
659 | start = path; |
660 | end = start + strlen(path); |
661 | |
662 | for (p = end; p > start; p--) { |
663 | /* Scan every path component from the end and at each '/' */ |
664 | if (p < end && *p != '/') |
665 | continue; |
666 | |
667 | /* Temporarily cut the path component out */ |
668 | ch = *p; |
669 | *p = '\0'; |
670 | ret = stat(path, &st); |
671 | *p = ch; |
672 | |
673 | /* Break if the initial path component was found */ |
674 | if (ret == 0) |
675 | break; |
676 | } |
677 | |
678 | return (p - start); |
679 | } |
680 | |
681 | char * |
682 | url_encode(const char *src) |
683 | { |
684 | static char hex[] = "0123456789ABCDEF"; |
685 | char *dp, *dst; |
686 | unsigned char c; |
687 | |
688 | /* We need 3 times the memory if every letter is encoded. */ |
689 | if ((dst = calloc(3, strlen(src) + 1)) == NULL((void*)0)) |
690 | return (NULL((void*)0)); |
691 | |
692 | for (dp = dst; *src != 0; src++) { |
693 | c = (unsigned char) *src; |
694 | if (c == ' ' || c == '#' || c == '%' || c == '?' || c == '"' || |
695 | c == '&' || c == '<' || c <= 0x1f || c >= 0x7f) { |
696 | *dp++ = '%'; |
697 | *dp++ = hex[c >> 4]; |
698 | *dp++ = hex[c & 0x0f]; |
699 | } else |
700 | *dp++ = *src; |
701 | } |
702 | return (dst); |
703 | } |
704 | |
705 | char* |
706 | escape_html(const char* src) |
707 | { |
708 | char *dp, *dst; |
709 | |
710 | /* We need 5 times the memory if every letter is "&" */ |
711 | if ((dst = calloc(5, strlen(src) + 1)) == NULL((void*)0)) |
712 | return NULL((void*)0); |
713 | |
714 | for (dp = dst; *src != 0; src++) { |
715 | if (*src == '<') { |
716 | *dp++ = '&'; |
717 | *dp++ = 'l'; |
718 | *dp++ = 't'; |
719 | *dp++ = ';'; |
720 | } else if (*src == '>') { |
721 | *dp++ = '&'; |
722 | *dp++ = 'g'; |
723 | *dp++ = 't'; |
724 | *dp++ = ';'; |
725 | } else if (*src == '&') { |
726 | *dp++ = '&'; |
727 | *dp++ = 'a'; |
728 | *dp++ = 'm'; |
729 | *dp++ = 'p'; |
730 | *dp++ = ';'; |
731 | } else |
732 | *dp++ = *src; |
733 | } |
734 | return (dst); |
735 | } |
736 | |
737 | void |
738 | socket_rlimit(int maxfd) |
739 | { |
740 | struct rlimit rl; |
741 | |
742 | if (getrlimit(RLIMIT_NOFILE8, &rl) == -1) |
743 | fatal("%s: failed to get resource limit", __func__); |
744 | log_debug("%s: max open files %llu", __func__, rl.rlim_max); |
745 | |
746 | /* |
747 | * Allow the maximum number of open file descriptors for this |
748 | * login class (which should be the class "daemon" by default). |
749 | */ |
750 | if (maxfd == -1) |
751 | rl.rlim_cur = rl.rlim_max; |
752 | else |
753 | rl.rlim_cur = MAXIMUM(rl.rlim_max, (rlim_t)maxfd)(((rl.rlim_max) > ((rlim_t)maxfd)) ? (rl.rlim_max) : ((rlim_t )maxfd)); |
754 | if (setrlimit(RLIMIT_NOFILE8, &rl) == -1) |
755 | fatal("%s: failed to set resource limit", __func__); |
756 | } |
757 | |
758 | char * |
759 | evbuffer_getline(struct evbuffer *evb) |
760 | { |
761 | uint8_t *ptr = EVBUFFER_DATA(evb)(evb)->buffer; |
762 | size_t len = EVBUFFER_LENGTH(evb)(evb)->off; |
763 | char *str; |
764 | size_t i; |
765 | |
766 | /* Safe version of evbuffer_readline() */ |
767 | if ((str = get_string(ptr, len)) == NULL((void*)0)) |
768 | return (NULL((void*)0)); |
769 | |
770 | for (i = 0; str[i] != '\0'; i++) { |
771 | if (str[i] == '\r' || str[i] == '\n') |
772 | break; |
773 | } |
774 | |
775 | if (i == len) { |
776 | free(str); |
777 | return (NULL((void*)0)); |
778 | } |
779 | |
780 | str[i] = '\0'; |
781 | |
782 | if ((i + 1) < len) { |
783 | if (ptr[i] == '\r' && ptr[i + 1] == '\n') |
784 | i++; |
785 | } |
786 | |
787 | evbuffer_drain(evb, ++i); |
788 | |
789 | return (str); |
790 | } |
791 | |
792 | char * |
793 | get_string(uint8_t *ptr, size_t len) |
794 | { |
795 | size_t i; |
796 | |
797 | for (i = 0; i < len; i++) |
798 | if (!(isprint((unsigned char)ptr[i]) || |
799 | isspace((unsigned char)ptr[i]))) |
800 | break; |
801 | |
802 | return strndup(ptr, i); |
803 | } |
804 | |
805 | void * |
806 | get_data(uint8_t *ptr, size_t len) |
807 | { |
808 | uint8_t *data; |
809 | |
810 | if ((data = malloc(len)) == NULL((void*)0)) |
811 | return (NULL((void*)0)); |
812 | memcpy(data, ptr, len); |
813 | |
814 | return (data); |
815 | } |
816 | |
817 | int |
818 | sockaddr_cmp(struct sockaddr *a, struct sockaddr *b, int prefixlen) |
819 | { |
820 | struct sockaddr_in *a4, *b4; |
821 | struct sockaddr_in6 *a6, *b6; |
822 | uint32_t av[4], bv[4], mv[4]; |
823 | |
824 | if (a->sa_family == AF_UNSPEC0 || b->sa_family == AF_UNSPEC0) |
825 | return (0); |
826 | else if (a->sa_family > b->sa_family) |
827 | return (1); |
828 | else if (a->sa_family < b->sa_family) |
829 | return (-1); |
830 | |
831 | if (prefixlen == -1) |
832 | memset(&mv, 0xff, sizeof(mv)); |
833 | |
834 | switch (a->sa_family) { |
835 | case AF_INET2: |
836 | a4 = (struct sockaddr_in *)a; |
837 | b4 = (struct sockaddr_in *)b; |
838 | |
839 | av[0] = a4->sin_addr.s_addr; |
840 | bv[0] = b4->sin_addr.s_addr; |
841 | if (prefixlen != -1) |
842 | mv[0] = prefixlen2mask(prefixlen); |
843 | |
844 | if ((av[0] & mv[0]) > (bv[0] & mv[0])) |
845 | return (1); |
846 | if ((av[0] & mv[0]) < (bv[0] & mv[0])) |
847 | return (-1); |
848 | break; |
849 | case AF_INET624: |
850 | a6 = (struct sockaddr_in6 *)a; |
851 | b6 = (struct sockaddr_in6 *)b; |
852 | |
853 | memcpy(&av, &a6->sin6_addr.s6_addr__u6_addr.__u6_addr8, 16); |
854 | memcpy(&bv, &b6->sin6_addr.s6_addr__u6_addr.__u6_addr8, 16); |
855 | if (prefixlen != -1) |
856 | prefixlen2mask6(prefixlen, mv); |
857 | |
858 | if ((av[3] & mv[3]) > (bv[3] & mv[3])) |
859 | return (1); |
860 | if ((av[3] & mv[3]) < (bv[3] & mv[3])) |
861 | return (-1); |
862 | if ((av[2] & mv[2]) > (bv[2] & mv[2])) |
863 | return (1); |
864 | if ((av[2] & mv[2]) < (bv[2] & mv[2])) |
865 | return (-1); |
866 | if ((av[1] & mv[1]) > (bv[1] & mv[1])) |
867 | return (1); |
868 | if ((av[1] & mv[1]) < (bv[1] & mv[1])) |
869 | return (-1); |
870 | if ((av[0] & mv[0]) > (bv[0] & mv[0])) |
871 | return (1); |
872 | if ((av[0] & mv[0]) < (bv[0] & mv[0])) |
873 | return (-1); |
874 | break; |
875 | } |
876 | |
877 | return (0); |
878 | } |
879 | |
880 | uint32_t |
881 | prefixlen2mask(uint8_t prefixlen) |
882 | { |
883 | if (prefixlen == 0) |
884 | return (0); |
885 | |
886 | if (prefixlen > 32) |
887 | prefixlen = 32; |
888 | |
889 | return (htonl(0xffffffff << (32 - prefixlen))(__uint32_t)(__builtin_constant_p(0xffffffff << (32 - prefixlen )) ? (__uint32_t)(((__uint32_t)(0xffffffff << (32 - prefixlen )) & 0xff) << 24 | ((__uint32_t)(0xffffffff << (32 - prefixlen)) & 0xff00) << 8 | ((__uint32_t)(0xffffffff << (32 - prefixlen)) & 0xff0000) >> 8 | ((__uint32_t )(0xffffffff << (32 - prefixlen)) & 0xff000000) >> 24) : __swap32md(0xffffffff << (32 - prefixlen)))); |
890 | } |
891 | |
892 | struct in6_addr * |
893 | prefixlen2mask6(uint8_t prefixlen, uint32_t *mask) |
894 | { |
895 | static struct in6_addr s6; |
896 | int i; |
897 | |
898 | if (prefixlen > 128) |
899 | prefixlen = 128; |
900 | |
901 | memset(&s6, 0, sizeof(s6)); |
902 | for (i = 0; i < prefixlen / 8; i++) |
903 | s6.s6_addr__u6_addr.__u6_addr8[i] = 0xff; |
904 | i = prefixlen % 8; |
905 | if (i) |
906 | s6.s6_addr__u6_addr.__u6_addr8[prefixlen / 8] = 0xff00 >> i; |
907 | |
908 | memcpy(mask, &s6, sizeof(s6)); |
909 | |
910 | return (&s6); |
911 | } |
912 | |
913 | int |
914 | accept_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen, |
915 | int reserve, volatile int *counter) |
916 | { |
917 | int ret; |
918 | if (getdtablecount() + reserve + |
919 | *counter >= getdtablesize()) { |
920 | errno(*__errno()) = EMFILE24; |
921 | return (-1); |
922 | } |
923 | |
924 | if ((ret = accept4(sockfd, addr, addrlen, SOCK_NONBLOCK0x4000)) > -1) { |
925 | (*counter)++; |
926 | DPRINTF("%s: inflight incremented, now %d",__func__, *counter)do {} while(0); |
927 | } |
928 | return (ret); |
929 | } |
930 | |
931 | struct kv * |
932 | kv_add(struct kvtree *keys, char *key, char *value) |
933 | { |
934 | struct kv *kv, *oldkv; |
935 | |
936 | if (key == NULL((void*)0)) |
937 | return (NULL((void*)0)); |
938 | if ((kv = calloc(1, sizeof(*kv))) == NULL((void*)0)) |
939 | return (NULL((void*)0)); |
940 | if ((kv->kv_key = strdup(key)) == NULL((void*)0)) { |
941 | free(kv); |
942 | return (NULL((void*)0)); |
943 | } |
944 | if (value != NULL((void*)0) && |
945 | (kv->kv_value = strdup(value)) == NULL((void*)0)) { |
946 | free(kv->kv_key); |
947 | free(kv); |
948 | return (NULL((void*)0)); |
949 | } |
950 | TAILQ_INIT(&kv->kv_children)do { (&kv->kv_children)->tqh_first = ((void*)0); (& kv->kv_children)->tqh_last = &(&kv->kv_children )->tqh_first; } while (0); |
951 | |
952 | if ((oldkv = RB_INSERT(kvtree, keys, kv)kvtree_RB_INSERT(keys, kv)) != NULL((void*)0)) { |
953 | TAILQ_INSERT_TAIL(&oldkv->kv_children, kv, kv_entry)do { (kv)->kv_entry.tqe_next = ((void*)0); (kv)->kv_entry .tqe_prev = (&oldkv->kv_children)->tqh_last; *(& oldkv->kv_children)->tqh_last = (kv); (&oldkv->kv_children )->tqh_last = &(kv)->kv_entry.tqe_next; } while (0); |
954 | kv->kv_parent = oldkv; |
955 | } |
956 | |
957 | return (kv); |
958 | } |
959 | |
960 | int |
961 | kv_set(struct kv *kv, char *fmt, ...) |
962 | { |
963 | va_list ap; |
964 | char *value = NULL((void*)0); |
965 | struct kv *ckv; |
966 | int ret; |
967 | |
968 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
969 | ret = vasprintf(&value, fmt, ap); |
970 | va_end(ap)__builtin_va_end(ap); |
971 | if (ret == -1) |
972 | return (-1); |
973 | |
974 | /* Remove all children */ |
975 | while ((ckv = TAILQ_FIRST(&kv->kv_children)((&kv->kv_children)->tqh_first)) != NULL((void*)0)) { |
976 | TAILQ_REMOVE(&kv->kv_children, ckv, kv_entry)do { if (((ckv)->kv_entry.tqe_next) != ((void*)0)) (ckv)-> kv_entry.tqe_next->kv_entry.tqe_prev = (ckv)->kv_entry. tqe_prev; else (&kv->kv_children)->tqh_last = (ckv) ->kv_entry.tqe_prev; *(ckv)->kv_entry.tqe_prev = (ckv)-> kv_entry.tqe_next; ; ; } while (0); |
977 | kv_free(ckv); |
978 | free(ckv); |
979 | } |
980 | |
981 | /* Set the new value */ |
982 | free(kv->kv_value); |
983 | kv->kv_value = value; |
984 | |
985 | return (0); |
986 | } |
987 | |
988 | int |
989 | kv_setkey(struct kv *kv, char *fmt, ...) |
990 | { |
991 | va_list ap; |
992 | char *key = NULL((void*)0); |
993 | int ret; |
994 | |
995 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
996 | ret = vasprintf(&key, fmt, ap); |
997 | va_end(ap)__builtin_va_end(ap); |
998 | if (ret == -1) |
999 | return (-1); |
1000 | |
1001 | free(kv->kv_key); |
1002 | kv->kv_key = key; |
1003 | |
1004 | return (0); |
1005 | } |
1006 | |
1007 | void |
1008 | kv_delete(struct kvtree *keys, struct kv *kv) |
1009 | { |
1010 | struct kv *ckv; |
1011 | |
1012 | RB_REMOVE(kvtree, keys, kv)kvtree_RB_REMOVE(keys, kv); |
1013 | |
1014 | /* Remove all children */ |
1015 | while ((ckv = TAILQ_FIRST(&kv->kv_children)((&kv->kv_children)->tqh_first)) != NULL((void*)0)) { |
1016 | TAILQ_REMOVE(&kv->kv_children, ckv, kv_entry)do { if (((ckv)->kv_entry.tqe_next) != ((void*)0)) (ckv)-> kv_entry.tqe_next->kv_entry.tqe_prev = (ckv)->kv_entry. tqe_prev; else (&kv->kv_children)->tqh_last = (ckv) ->kv_entry.tqe_prev; *(ckv)->kv_entry.tqe_prev = (ckv)-> kv_entry.tqe_next; ; ; } while (0); |
1017 | kv_free(ckv); |
1018 | free(ckv); |
1019 | } |
1020 | |
1021 | kv_free(kv); |
1022 | free(kv); |
1023 | } |
1024 | |
1025 | struct kv * |
1026 | kv_extend(struct kvtree *keys, struct kv *kv, char *value) |
1027 | { |
1028 | char *newvalue; |
1029 | |
1030 | if (kv == NULL((void*)0)) { |
1031 | return (NULL((void*)0)); |
1032 | } else if (kv->kv_value != NULL((void*)0)) { |
1033 | if (asprintf(&newvalue, "%s%s", kv->kv_value, value) == -1) |
1034 | return (NULL((void*)0)); |
1035 | |
1036 | free(kv->kv_value); |
1037 | kv->kv_value = newvalue; |
1038 | } else if ((kv->kv_value = strdup(value)) == NULL((void*)0)) |
1039 | return (NULL((void*)0)); |
1040 | |
1041 | return (kv); |
1042 | } |
1043 | |
1044 | void |
1045 | kv_purge(struct kvtree *keys) |
1046 | { |
1047 | struct kv *kv; |
1048 | |
1049 | while ((kv = RB_MIN(kvtree, keys)kvtree_RB_MINMAX(keys, -1)) != NULL((void*)0)) |
1050 | kv_delete(keys, kv); |
1051 | } |
1052 | |
1053 | void |
1054 | kv_free(struct kv *kv) |
1055 | { |
1056 | free(kv->kv_key); |
1057 | kv->kv_key = NULL((void*)0); |
1058 | free(kv->kv_value); |
1059 | kv->kv_value = NULL((void*)0); |
1060 | memset(kv, 0, sizeof(*kv)); |
1061 | } |
1062 | |
1063 | struct kv * |
1064 | kv_find(struct kvtree *keys, struct kv *kv) |
1065 | { |
1066 | struct kv *match; |
1067 | const char *key; |
1068 | |
1069 | if (kv->kv_flags & KV_FLAG_GLOBBING0x02) { |
1070 | /* Test header key using shell globbing rules */ |
1071 | key = kv->kv_key == NULL((void*)0) ? "" : kv->kv_key; |
1072 | RB_FOREACH(match, kvtree, keys)for ((match) = kvtree_RB_MINMAX(keys, -1); (match) != ((void* )0); (match) = kvtree_RB_NEXT(match)) { |
1073 | if (fnmatch(key, match->kv_key, FNM_CASEFOLD0x10) == 0) |
1074 | break; |
1075 | } |
1076 | } else { |
1077 | /* Fast tree-based lookup only works without globbing */ |
1078 | match = RB_FIND(kvtree, keys, kv)kvtree_RB_FIND(keys, kv); |
1079 | } |
1080 | |
1081 | return (match); |
1082 | } |
1083 | |
1084 | int |
1085 | kv_cmp(struct kv *a, struct kv *b) |
1086 | { |
1087 | return (strcasecmp(a->kv_key, b->kv_key)); |
1088 | } |
1089 | |
1090 | RB_GENERATE(kvtree, kv, kv_node, kv_cmp)void kvtree_RB_INSERT_COLOR(struct kvtree *head, struct kv *elm ) { struct kv *parent, *gparent, *tmp; while ((parent = (elm) ->kv_node.rbe_parent) && (parent)->kv_node.rbe_color == 1) { gparent = (parent)->kv_node.rbe_parent; if (parent == (gparent)->kv_node.rbe_left) { tmp = (gparent)->kv_node .rbe_right; if (tmp && (tmp)->kv_node.rbe_color == 1) { (tmp)->kv_node.rbe_color = 0; do { (parent)->kv_node .rbe_color = 0; (gparent)->kv_node.rbe_color = 1; } while ( 0); elm = gparent; continue; } if ((parent)->kv_node.rbe_right == elm) { do { (tmp) = (parent)->kv_node.rbe_right; if (( (parent)->kv_node.rbe_right = (tmp)->kv_node.rbe_left)) { ((tmp)->kv_node.rbe_left)->kv_node.rbe_parent = (parent ); } do {} while (0); if (((tmp)->kv_node.rbe_parent = (parent )->kv_node.rbe_parent)) { if ((parent) == ((parent)->kv_node .rbe_parent)->kv_node.rbe_left) ((parent)->kv_node.rbe_parent )->kv_node.rbe_left = (tmp); else ((parent)->kv_node.rbe_parent )->kv_node.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->kv_node.rbe_left = (parent); (parent)->kv_node .rbe_parent = (tmp); do {} while (0); if (((tmp)->kv_node. rbe_parent)) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->kv_node.rbe_color = 0; (gparent)->kv_node.rbe_color = 1; } while (0); do { (tmp) = (gparent)->kv_node.rbe_left; if (((gparent)->kv_node .rbe_left = (tmp)->kv_node.rbe_right)) { ((tmp)->kv_node .rbe_right)->kv_node.rbe_parent = (gparent); } do {} while (0); if (((tmp)->kv_node.rbe_parent = (gparent)->kv_node .rbe_parent)) { if ((gparent) == ((gparent)->kv_node.rbe_parent )->kv_node.rbe_left) ((gparent)->kv_node.rbe_parent)-> kv_node.rbe_left = (tmp); else ((gparent)->kv_node.rbe_parent )->kv_node.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->kv_node.rbe_right = (gparent); (gparent)-> kv_node.rbe_parent = (tmp); do {} while (0); if (((tmp)->kv_node .rbe_parent)) do {} while (0); } while (0); } else { tmp = (gparent )->kv_node.rbe_left; if (tmp && (tmp)->kv_node. rbe_color == 1) { (tmp)->kv_node.rbe_color = 0; do { (parent )->kv_node.rbe_color = 0; (gparent)->kv_node.rbe_color = 1; } while (0); elm = gparent; continue; } if ((parent)-> kv_node.rbe_left == elm) { do { (tmp) = (parent)->kv_node. rbe_left; if (((parent)->kv_node.rbe_left = (tmp)->kv_node .rbe_right)) { ((tmp)->kv_node.rbe_right)->kv_node.rbe_parent = (parent); } do {} while (0); if (((tmp)->kv_node.rbe_parent = (parent)->kv_node.rbe_parent)) { if ((parent) == ((parent )->kv_node.rbe_parent)->kv_node.rbe_left) ((parent)-> kv_node.rbe_parent)->kv_node.rbe_left = (tmp); else ((parent )->kv_node.rbe_parent)->kv_node.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->kv_node.rbe_right = ( parent); (parent)->kv_node.rbe_parent = (tmp); do {} while (0); if (((tmp)->kv_node.rbe_parent)) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)-> kv_node.rbe_color = 0; (gparent)->kv_node.rbe_color = 1; } while (0); do { (tmp) = (gparent)->kv_node.rbe_right; if ( ((gparent)->kv_node.rbe_right = (tmp)->kv_node.rbe_left )) { ((tmp)->kv_node.rbe_left)->kv_node.rbe_parent = (gparent ); } do {} while (0); if (((tmp)->kv_node.rbe_parent = (gparent )->kv_node.rbe_parent)) { if ((gparent) == ((gparent)-> kv_node.rbe_parent)->kv_node.rbe_left) ((gparent)->kv_node .rbe_parent)->kv_node.rbe_left = (tmp); else ((gparent)-> kv_node.rbe_parent)->kv_node.rbe_right = (tmp); } else (head )->rbh_root = (tmp); (tmp)->kv_node.rbe_left = (gparent ); (gparent)->kv_node.rbe_parent = (tmp); do {} while (0); if (((tmp)->kv_node.rbe_parent)) do {} while (0); } while (0); } } (head->rbh_root)->kv_node.rbe_color = 0; } void kvtree_RB_REMOVE_COLOR(struct kvtree *head, struct kv *parent , struct kv *elm) { struct kv *tmp; while ((elm == ((void*)0) || (elm)->kv_node.rbe_color == 0) && elm != (head )->rbh_root) { if ((parent)->kv_node.rbe_left == elm) { tmp = (parent)->kv_node.rbe_right; if ((tmp)->kv_node. rbe_color == 1) { do { (tmp)->kv_node.rbe_color = 0; (parent )->kv_node.rbe_color = 1; } while (0); do { (tmp) = (parent )->kv_node.rbe_right; if (((parent)->kv_node.rbe_right = (tmp)->kv_node.rbe_left)) { ((tmp)->kv_node.rbe_left)-> kv_node.rbe_parent = (parent); } do {} while (0); if (((tmp)-> kv_node.rbe_parent = (parent)->kv_node.rbe_parent)) { if ( (parent) == ((parent)->kv_node.rbe_parent)->kv_node.rbe_left ) ((parent)->kv_node.rbe_parent)->kv_node.rbe_left = (tmp ); else ((parent)->kv_node.rbe_parent)->kv_node.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->kv_node .rbe_left = (parent); (parent)->kv_node.rbe_parent = (tmp) ; do {} while (0); if (((tmp)->kv_node.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->kv_node.rbe_right; } if (((tmp)->kv_node.rbe_left == ((void*)0) || ((tmp)->kv_node .rbe_left)->kv_node.rbe_color == 0) && ((tmp)-> kv_node.rbe_right == ((void*)0) || ((tmp)->kv_node.rbe_right )->kv_node.rbe_color == 0)) { (tmp)->kv_node.rbe_color = 1; elm = parent; parent = (elm)->kv_node.rbe_parent; } else { if ((tmp)->kv_node.rbe_right == ((void*)0) || ((tmp)-> kv_node.rbe_right)->kv_node.rbe_color == 0) { struct kv *oleft ; if ((oleft = (tmp)->kv_node.rbe_left)) (oleft)->kv_node .rbe_color = 0; (tmp)->kv_node.rbe_color = 1; do { (oleft) = (tmp)->kv_node.rbe_left; if (((tmp)->kv_node.rbe_left = (oleft)->kv_node.rbe_right)) { ((oleft)->kv_node.rbe_right )->kv_node.rbe_parent = (tmp); } do {} while (0); if (((oleft )->kv_node.rbe_parent = (tmp)->kv_node.rbe_parent)) { if ((tmp) == ((tmp)->kv_node.rbe_parent)->kv_node.rbe_left ) ((tmp)->kv_node.rbe_parent)->kv_node.rbe_left = (oleft ); else ((tmp)->kv_node.rbe_parent)->kv_node.rbe_right = (oleft); } else (head)->rbh_root = (oleft); (oleft)->kv_node .rbe_right = (tmp); (tmp)->kv_node.rbe_parent = (oleft); do {} while (0); if (((oleft)->kv_node.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->kv_node.rbe_right; } (tmp )->kv_node.rbe_color = (parent)->kv_node.rbe_color; (parent )->kv_node.rbe_color = 0; if ((tmp)->kv_node.rbe_right) ((tmp)->kv_node.rbe_right)->kv_node.rbe_color = 0; do { (tmp) = (parent)->kv_node.rbe_right; if (((parent)->kv_node .rbe_right = (tmp)->kv_node.rbe_left)) { ((tmp)->kv_node .rbe_left)->kv_node.rbe_parent = (parent); } do {} while ( 0); if (((tmp)->kv_node.rbe_parent = (parent)->kv_node. rbe_parent)) { if ((parent) == ((parent)->kv_node.rbe_parent )->kv_node.rbe_left) ((parent)->kv_node.rbe_parent)-> kv_node.rbe_left = (tmp); else ((parent)->kv_node.rbe_parent )->kv_node.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->kv_node.rbe_left = (parent); (parent)->kv_node .rbe_parent = (tmp); do {} while (0); if (((tmp)->kv_node. rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root ; break; } } else { tmp = (parent)->kv_node.rbe_left; if ( (tmp)->kv_node.rbe_color == 1) { do { (tmp)->kv_node.rbe_color = 0; (parent)->kv_node.rbe_color = 1; } while (0); do { ( tmp) = (parent)->kv_node.rbe_left; if (((parent)->kv_node .rbe_left = (tmp)->kv_node.rbe_right)) { ((tmp)->kv_node .rbe_right)->kv_node.rbe_parent = (parent); } do {} while ( 0); if (((tmp)->kv_node.rbe_parent = (parent)->kv_node. rbe_parent)) { if ((parent) == ((parent)->kv_node.rbe_parent )->kv_node.rbe_left) ((parent)->kv_node.rbe_parent)-> kv_node.rbe_left = (tmp); else ((parent)->kv_node.rbe_parent )->kv_node.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->kv_node.rbe_right = (parent); (parent)-> kv_node.rbe_parent = (tmp); do {} while (0); if (((tmp)->kv_node .rbe_parent)) do {} while (0); } while (0); tmp = (parent)-> kv_node.rbe_left; } if (((tmp)->kv_node.rbe_left == ((void *)0) || ((tmp)->kv_node.rbe_left)->kv_node.rbe_color == 0) && ((tmp)->kv_node.rbe_right == ((void*)0) || ( (tmp)->kv_node.rbe_right)->kv_node.rbe_color == 0)) { ( tmp)->kv_node.rbe_color = 1; elm = parent; parent = (elm)-> kv_node.rbe_parent; } else { if ((tmp)->kv_node.rbe_left == ((void*)0) || ((tmp)->kv_node.rbe_left)->kv_node.rbe_color == 0) { struct kv *oright; if ((oright = (tmp)->kv_node.rbe_right )) (oright)->kv_node.rbe_color = 0; (tmp)->kv_node.rbe_color = 1; do { (oright) = (tmp)->kv_node.rbe_right; if (((tmp) ->kv_node.rbe_right = (oright)->kv_node.rbe_left)) { (( oright)->kv_node.rbe_left)->kv_node.rbe_parent = (tmp); } do {} while (0); if (((oright)->kv_node.rbe_parent = (tmp )->kv_node.rbe_parent)) { if ((tmp) == ((tmp)->kv_node. rbe_parent)->kv_node.rbe_left) ((tmp)->kv_node.rbe_parent )->kv_node.rbe_left = (oright); else ((tmp)->kv_node.rbe_parent )->kv_node.rbe_right = (oright); } else (head)->rbh_root = (oright); (oright)->kv_node.rbe_left = (tmp); (tmp)-> kv_node.rbe_parent = (oright); do {} while (0); if (((oright) ->kv_node.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->kv_node.rbe_left; } (tmp)->kv_node.rbe_color = (parent)->kv_node.rbe_color; (parent)->kv_node.rbe_color = 0; if ((tmp)->kv_node.rbe_left) ((tmp)->kv_node.rbe_left )->kv_node.rbe_color = 0; do { (tmp) = (parent)->kv_node .rbe_left; if (((parent)->kv_node.rbe_left = (tmp)->kv_node .rbe_right)) { ((tmp)->kv_node.rbe_right)->kv_node.rbe_parent = (parent); } do {} while (0); if (((tmp)->kv_node.rbe_parent = (parent)->kv_node.rbe_parent)) { if ((parent) == ((parent )->kv_node.rbe_parent)->kv_node.rbe_left) ((parent)-> kv_node.rbe_parent)->kv_node.rbe_left = (tmp); else ((parent )->kv_node.rbe_parent)->kv_node.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->kv_node.rbe_right = ( parent); (parent)->kv_node.rbe_parent = (tmp); do {} while (0); if (((tmp)->kv_node.rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root; break; } } } if (elm) (elm)-> kv_node.rbe_color = 0; } struct kv * kvtree_RB_REMOVE(struct kvtree *head, struct kv *elm) { struct kv *child, *parent, *old = elm ; int color; if ((elm)->kv_node.rbe_left == ((void*)0)) child = (elm)->kv_node.rbe_right; else if ((elm)->kv_node.rbe_right == ((void*)0)) child = (elm)->kv_node.rbe_left; else { struct kv *left; elm = (elm)->kv_node.rbe_right; while ((left = ( elm)->kv_node.rbe_left)) elm = left; child = (elm)->kv_node .rbe_right; parent = (elm)->kv_node.rbe_parent; color = (elm )->kv_node.rbe_color; if (child) (child)->kv_node.rbe_parent = parent; if (parent) { if ((parent)->kv_node.rbe_left == elm) (parent)->kv_node.rbe_left = child; else (parent)-> kv_node.rbe_right = child; do {} while (0); } else (head)-> rbh_root = child; if ((elm)->kv_node.rbe_parent == old) parent = elm; (elm)->kv_node = (old)->kv_node; if ((old)-> kv_node.rbe_parent) { if (((old)->kv_node.rbe_parent)-> kv_node.rbe_left == old) ((old)->kv_node.rbe_parent)->kv_node .rbe_left = elm; else ((old)->kv_node.rbe_parent)->kv_node .rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; ((old)->kv_node.rbe_left)->kv_node.rbe_parent = elm; if ((old)->kv_node.rbe_right) ((old)->kv_node.rbe_right )->kv_node.rbe_parent = elm; if (parent) { left = parent; do { do {} while (0); } while ((left = (left)->kv_node.rbe_parent )); } goto color; } parent = (elm)->kv_node.rbe_parent; color = (elm)->kv_node.rbe_color; if (child) (child)->kv_node .rbe_parent = parent; if (parent) { if ((parent)->kv_node. rbe_left == elm) (parent)->kv_node.rbe_left = child; else ( parent)->kv_node.rbe_right = child; do {} while (0); } else (head)->rbh_root = child; color: if (color == 0) kvtree_RB_REMOVE_COLOR (head, parent, child); return (old); } struct kv * kvtree_RB_INSERT (struct kvtree *head, struct kv *elm) { struct kv *tmp; struct kv *parent = ((void*)0); int comp = 0; tmp = (head)->rbh_root ; while (tmp) { parent = tmp; comp = (kv_cmp)(elm, parent); if (comp < 0) tmp = (tmp)->kv_node.rbe_left; else if (comp > 0) tmp = (tmp)->kv_node.rbe_right; else return (tmp) ; } do { (elm)->kv_node.rbe_parent = parent; (elm)->kv_node .rbe_left = (elm)->kv_node.rbe_right = ((void*)0); (elm)-> kv_node.rbe_color = 1; } while (0); if (parent != ((void*)0)) { if (comp < 0) (parent)->kv_node.rbe_left = elm; else (parent)->kv_node.rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; kvtree_RB_INSERT_COLOR(head, elm) ; return (((void*)0)); } struct kv * kvtree_RB_FIND(struct kvtree *head, struct kv *elm) { struct kv *tmp = (head)->rbh_root ; int comp; while (tmp) { comp = kv_cmp(elm, tmp); if (comp < 0) tmp = (tmp)->kv_node.rbe_left; else if (comp > 0) tmp = (tmp)->kv_node.rbe_right; else return (tmp); } return ( ((void*)0)); } struct kv * kvtree_RB_NFIND(struct kvtree *head , struct kv *elm) { struct kv *tmp = (head)->rbh_root; struct kv *res = ((void*)0); int comp; while (tmp) { comp = kv_cmp( elm, tmp); if (comp < 0) { res = tmp; tmp = (tmp)->kv_node .rbe_left; } else if (comp > 0) tmp = (tmp)->kv_node.rbe_right ; else return (tmp); } return (res); } struct kv * kvtree_RB_NEXT (struct kv *elm) { if ((elm)->kv_node.rbe_right) { elm = ( elm)->kv_node.rbe_right; while ((elm)->kv_node.rbe_left ) elm = (elm)->kv_node.rbe_left; } else { if ((elm)->kv_node .rbe_parent && (elm == ((elm)->kv_node.rbe_parent) ->kv_node.rbe_left)) elm = (elm)->kv_node.rbe_parent; else { while ((elm)->kv_node.rbe_parent && (elm == ((elm )->kv_node.rbe_parent)->kv_node.rbe_right)) elm = (elm) ->kv_node.rbe_parent; elm = (elm)->kv_node.rbe_parent; } } return (elm); } struct kv * kvtree_RB_PREV(struct kv *elm) { if ((elm)->kv_node.rbe_left) { elm = (elm)->kv_node. rbe_left; while ((elm)->kv_node.rbe_right) elm = (elm)-> kv_node.rbe_right; } else { if ((elm)->kv_node.rbe_parent && (elm == ((elm)->kv_node.rbe_parent)->kv_node.rbe_right )) elm = (elm)->kv_node.rbe_parent; else { while ((elm)-> kv_node.rbe_parent && (elm == ((elm)->kv_node.rbe_parent )->kv_node.rbe_left)) elm = (elm)->kv_node.rbe_parent; elm = (elm)->kv_node.rbe_parent; } } return (elm); } struct kv * kvtree_RB_MINMAX(struct kvtree *head, int val) { struct kv *tmp = (head)->rbh_root; struct kv *parent = ((void*)0); while (tmp) { parent = tmp; if (val < 0) tmp = (tmp)->kv_node .rbe_left; else tmp = (tmp)->kv_node.rbe_right; } return ( parent); }; |
1091 | |
1092 | struct media_type * |
1093 | media_add(struct mediatypes *types, struct media_type *media) |
1094 | { |
1095 | struct media_type *entry; |
1096 | |
1097 | if ((entry = RB_FIND(mediatypes, types, media)mediatypes_RB_FIND(types, media)) != NULL((void*)0)) { |
1098 | log_debug("%s: duplicated entry for \"%s\"", __func__, |
1099 | media->media_name); |
1100 | return (NULL((void*)0)); |
1101 | } |
1102 | |
1103 | if ((entry = malloc(sizeof(*media))) == NULL((void*)0)) |
1104 | return (NULL((void*)0)); |
1105 | |
1106 | memcpy(entry, media, sizeof(*entry)); |
1107 | if (media->media_encoding != NULL((void*)0) && |
1108 | (entry->media_encoding = strdup(media->media_encoding)) == NULL((void*)0)) { |
1109 | free(entry); |
1110 | return (NULL((void*)0)); |
1111 | } |
1112 | RB_INSERT(mediatypes, types, entry)mediatypes_RB_INSERT(types, entry); |
1113 | |
1114 | return (entry); |
1115 | } |
1116 | |
1117 | void |
1118 | media_delete(struct mediatypes *types, struct media_type *media) |
1119 | { |
1120 | RB_REMOVE(mediatypes, types, media)mediatypes_RB_REMOVE(types, media); |
1121 | |
1122 | free(media->media_encoding); |
1123 | free(media); |
1124 | } |
1125 | |
1126 | void |
1127 | media_purge(struct mediatypes *types) |
1128 | { |
1129 | struct media_type *media; |
1130 | |
1131 | while ((media = RB_MIN(mediatypes, types)mediatypes_RB_MINMAX(types, -1)) != NULL((void*)0)) |
1132 | media_delete(types, media); |
1133 | } |
1134 | |
1135 | struct media_type * |
1136 | media_find(struct mediatypes *types, const char *file) |
1137 | { |
1138 | struct media_type *match, media; |
1139 | char *p; |
1140 | |
1141 | /* Last component of the file name */ |
1142 | p = strchr(file, '\0'); |
1143 | while (p > file && p[-1] != '.' && p[-1] != '/') |
1144 | p--; |
1145 | if (*p == '\0') |
1146 | return (NULL((void*)0)); |
1147 | |
1148 | if (strlcpy(media.media_name, p, |
1149 | sizeof(media.media_name)) >= |
1150 | sizeof(media.media_name)) { |
1151 | return (NULL((void*)0)); |
1152 | } |
1153 | |
1154 | /* Find media type by extension name */ |
1155 | match = RB_FIND(mediatypes, types, &media)mediatypes_RB_FIND(types, &media); |
1156 | |
1157 | return (match); |
1158 | } |
1159 | |
1160 | struct media_type * |
1161 | media_find_config(struct httpd *env, struct server_config *srv_conf, |
1162 | const char *file) |
1163 | { |
1164 | struct media_type *match; |
1165 | |
1166 | if ((match = media_find(env->sc_mediatypes, file)) != NULL((void*)0)) |
1167 | return (match); |
1168 | else if (srv_conf->flags & SRVFLAG_DEFAULT_TYPE0x00800000) |
1169 | return (&srv_conf->default_type); |
1170 | |
1171 | /* fallback to the global default type */ |
1172 | return (&env->sc_default_type); |
1173 | } |
1174 | |
1175 | int |
1176 | media_cmp(struct media_type *a, struct media_type *b) |
1177 | { |
1178 | return (strcasecmp(a->media_name, b->media_name)); |
1179 | } |
1180 | |
1181 | RB_GENERATE(mediatypes, media_type, media_entry, media_cmp)void mediatypes_RB_INSERT_COLOR(struct mediatypes *head, struct media_type *elm) { struct media_type *parent, *gparent, *tmp ; while ((parent = (elm)->media_entry.rbe_parent) && (parent)->media_entry.rbe_color == 1) { gparent = (parent )->media_entry.rbe_parent; if (parent == (gparent)->media_entry .rbe_left) { tmp = (gparent)->media_entry.rbe_right; if (tmp && (tmp)->media_entry.rbe_color == 1) { (tmp)-> media_entry.rbe_color = 0; do { (parent)->media_entry.rbe_color = 0; (gparent)->media_entry.rbe_color = 1; } while (0); elm = gparent; continue; } if ((parent)->media_entry.rbe_right == elm) { do { (tmp) = (parent)->media_entry.rbe_right; if (((parent)->media_entry.rbe_right = (tmp)->media_entry .rbe_left)) { ((tmp)->media_entry.rbe_left)->media_entry .rbe_parent = (parent); } do {} while (0); if (((tmp)->media_entry .rbe_parent = (parent)->media_entry.rbe_parent)) { if ((parent ) == ((parent)->media_entry.rbe_parent)->media_entry.rbe_left ) ((parent)->media_entry.rbe_parent)->media_entry.rbe_left = (tmp); else ((parent)->media_entry.rbe_parent)->media_entry .rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp) ->media_entry.rbe_left = (parent); (parent)->media_entry .rbe_parent = (tmp); do {} while (0); if (((tmp)->media_entry .rbe_parent)) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->media_entry.rbe_color = 0; (gparent)->media_entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)->media_entry.rbe_left; if (((gparent)-> media_entry.rbe_left = (tmp)->media_entry.rbe_right)) { (( tmp)->media_entry.rbe_right)->media_entry.rbe_parent = ( gparent); } do {} while (0); if (((tmp)->media_entry.rbe_parent = (gparent)->media_entry.rbe_parent)) { if ((gparent) == ( (gparent)->media_entry.rbe_parent)->media_entry.rbe_left ) ((gparent)->media_entry.rbe_parent)->media_entry.rbe_left = (tmp); else ((gparent)->media_entry.rbe_parent)->media_entry .rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp) ->media_entry.rbe_right = (gparent); (gparent)->media_entry .rbe_parent = (tmp); do {} while (0); if (((tmp)->media_entry .rbe_parent)) do {} while (0); } while (0); } else { tmp = (gparent )->media_entry.rbe_left; if (tmp && (tmp)->media_entry .rbe_color == 1) { (tmp)->media_entry.rbe_color = 0; do { ( parent)->media_entry.rbe_color = 0; (gparent)->media_entry .rbe_color = 1; } while (0); elm = gparent; continue; } if (( parent)->media_entry.rbe_left == elm) { do { (tmp) = (parent )->media_entry.rbe_left; if (((parent)->media_entry.rbe_left = (tmp)->media_entry.rbe_right)) { ((tmp)->media_entry .rbe_right)->media_entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->media_entry.rbe_parent = (parent)->media_entry .rbe_parent)) { if ((parent) == ((parent)->media_entry.rbe_parent )->media_entry.rbe_left) ((parent)->media_entry.rbe_parent )->media_entry.rbe_left = (tmp); else ((parent)->media_entry .rbe_parent)->media_entry.rbe_right = (tmp); } else (head) ->rbh_root = (tmp); (tmp)->media_entry.rbe_right = (parent ); (parent)->media_entry.rbe_parent = (tmp); do {} while ( 0); if (((tmp)->media_entry.rbe_parent)) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent )->media_entry.rbe_color = 0; (gparent)->media_entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)->media_entry.rbe_right ; if (((gparent)->media_entry.rbe_right = (tmp)->media_entry .rbe_left)) { ((tmp)->media_entry.rbe_left)->media_entry .rbe_parent = (gparent); } do {} while (0); if (((tmp)->media_entry .rbe_parent = (gparent)->media_entry.rbe_parent)) { if ((gparent ) == ((gparent)->media_entry.rbe_parent)->media_entry.rbe_left ) ((gparent)->media_entry.rbe_parent)->media_entry.rbe_left = (tmp); else ((gparent)->media_entry.rbe_parent)->media_entry .rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp) ->media_entry.rbe_left = (gparent); (gparent)->media_entry .rbe_parent = (tmp); do {} while (0); if (((tmp)->media_entry .rbe_parent)) do {} while (0); } while (0); } } (head->rbh_root )->media_entry.rbe_color = 0; } void mediatypes_RB_REMOVE_COLOR (struct mediatypes *head, struct media_type *parent, struct media_type *elm) { struct media_type *tmp; while ((elm == ((void*)0) || (elm)->media_entry.rbe_color == 0) && elm != (head )->rbh_root) { if ((parent)->media_entry.rbe_left == elm ) { tmp = (parent)->media_entry.rbe_right; if ((tmp)->media_entry .rbe_color == 1) { do { (tmp)->media_entry.rbe_color = 0; ( parent)->media_entry.rbe_color = 1; } while (0); do { (tmp ) = (parent)->media_entry.rbe_right; if (((parent)->media_entry .rbe_right = (tmp)->media_entry.rbe_left)) { ((tmp)->media_entry .rbe_left)->media_entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->media_entry.rbe_parent = (parent)->media_entry .rbe_parent)) { if ((parent) == ((parent)->media_entry.rbe_parent )->media_entry.rbe_left) ((parent)->media_entry.rbe_parent )->media_entry.rbe_left = (tmp); else ((parent)->media_entry .rbe_parent)->media_entry.rbe_right = (tmp); } else (head) ->rbh_root = (tmp); (tmp)->media_entry.rbe_left = (parent ); (parent)->media_entry.rbe_parent = (tmp); do {} while ( 0); if (((tmp)->media_entry.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->media_entry.rbe_right; } if (( (tmp)->media_entry.rbe_left == ((void*)0) || ((tmp)->media_entry .rbe_left)->media_entry.rbe_color == 0) && ((tmp)-> media_entry.rbe_right == ((void*)0) || ((tmp)->media_entry .rbe_right)->media_entry.rbe_color == 0)) { (tmp)->media_entry .rbe_color = 1; elm = parent; parent = (elm)->media_entry. rbe_parent; } else { if ((tmp)->media_entry.rbe_right == ( (void*)0) || ((tmp)->media_entry.rbe_right)->media_entry .rbe_color == 0) { struct media_type *oleft; if ((oleft = (tmp )->media_entry.rbe_left)) (oleft)->media_entry.rbe_color = 0; (tmp)->media_entry.rbe_color = 1; do { (oleft) = (tmp )->media_entry.rbe_left; if (((tmp)->media_entry.rbe_left = (oleft)->media_entry.rbe_right)) { ((oleft)->media_entry .rbe_right)->media_entry.rbe_parent = (tmp); } do {} while (0); if (((oleft)->media_entry.rbe_parent = (tmp)->media_entry .rbe_parent)) { if ((tmp) == ((tmp)->media_entry.rbe_parent )->media_entry.rbe_left) ((tmp)->media_entry.rbe_parent )->media_entry.rbe_left = (oleft); else ((tmp)->media_entry .rbe_parent)->media_entry.rbe_right = (oleft); } else (head )->rbh_root = (oleft); (oleft)->media_entry.rbe_right = (tmp); (tmp)->media_entry.rbe_parent = (oleft); do {} while (0); if (((oleft)->media_entry.rbe_parent)) do {} while ( 0); } while (0); tmp = (parent)->media_entry.rbe_right; } ( tmp)->media_entry.rbe_color = (parent)->media_entry.rbe_color ; (parent)->media_entry.rbe_color = 0; if ((tmp)->media_entry .rbe_right) ((tmp)->media_entry.rbe_right)->media_entry .rbe_color = 0; do { (tmp) = (parent)->media_entry.rbe_right ; if (((parent)->media_entry.rbe_right = (tmp)->media_entry .rbe_left)) { ((tmp)->media_entry.rbe_left)->media_entry .rbe_parent = (parent); } do {} while (0); if (((tmp)->media_entry .rbe_parent = (parent)->media_entry.rbe_parent)) { if ((parent ) == ((parent)->media_entry.rbe_parent)->media_entry.rbe_left ) ((parent)->media_entry.rbe_parent)->media_entry.rbe_left = (tmp); else ((parent)->media_entry.rbe_parent)->media_entry .rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp) ->media_entry.rbe_left = (parent); (parent)->media_entry .rbe_parent = (tmp); do {} while (0); if (((tmp)->media_entry .rbe_parent)) do {} while (0); } while (0); elm = (head)-> rbh_root; break; } } else { tmp = (parent)->media_entry.rbe_left ; if ((tmp)->media_entry.rbe_color == 1) { do { (tmp)-> media_entry.rbe_color = 0; (parent)->media_entry.rbe_color = 1; } while (0); do { (tmp) = (parent)->media_entry.rbe_left ; if (((parent)->media_entry.rbe_left = (tmp)->media_entry .rbe_right)) { ((tmp)->media_entry.rbe_right)->media_entry .rbe_parent = (parent); } do {} while (0); if (((tmp)->media_entry .rbe_parent = (parent)->media_entry.rbe_parent)) { if ((parent ) == ((parent)->media_entry.rbe_parent)->media_entry.rbe_left ) ((parent)->media_entry.rbe_parent)->media_entry.rbe_left = (tmp); else ((parent)->media_entry.rbe_parent)->media_entry .rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp) ->media_entry.rbe_right = (parent); (parent)->media_entry .rbe_parent = (tmp); do {} while (0); if (((tmp)->media_entry .rbe_parent)) do {} while (0); } while (0); tmp = (parent)-> media_entry.rbe_left; } if (((tmp)->media_entry.rbe_left == ((void*)0) || ((tmp)->media_entry.rbe_left)->media_entry .rbe_color == 0) && ((tmp)->media_entry.rbe_right == ((void*)0) || ((tmp)->media_entry.rbe_right)->media_entry .rbe_color == 0)) { (tmp)->media_entry.rbe_color = 1; elm = parent; parent = (elm)->media_entry.rbe_parent; } else { if ((tmp)->media_entry.rbe_left == ((void*)0) || ((tmp)-> media_entry.rbe_left)->media_entry.rbe_color == 0) { struct media_type *oright; if ((oright = (tmp)->media_entry.rbe_right )) (oright)->media_entry.rbe_color = 0; (tmp)->media_entry .rbe_color = 1; do { (oright) = (tmp)->media_entry.rbe_right ; if (((tmp)->media_entry.rbe_right = (oright)->media_entry .rbe_left)) { ((oright)->media_entry.rbe_left)->media_entry .rbe_parent = (tmp); } do {} while (0); if (((oright)->media_entry .rbe_parent = (tmp)->media_entry.rbe_parent)) { if ((tmp) == ((tmp)->media_entry.rbe_parent)->media_entry.rbe_left) ((tmp)->media_entry.rbe_parent)->media_entry.rbe_left = (oright); else ((tmp)->media_entry.rbe_parent)->media_entry .rbe_right = (oright); } else (head)->rbh_root = (oright); (oright)->media_entry.rbe_left = (tmp); (tmp)->media_entry .rbe_parent = (oright); do {} while (0); if (((oright)->media_entry .rbe_parent)) do {} while (0); } while (0); tmp = (parent)-> media_entry.rbe_left; } (tmp)->media_entry.rbe_color = (parent )->media_entry.rbe_color; (parent)->media_entry.rbe_color = 0; if ((tmp)->media_entry.rbe_left) ((tmp)->media_entry .rbe_left)->media_entry.rbe_color = 0; do { (tmp) = (parent )->media_entry.rbe_left; if (((parent)->media_entry.rbe_left = (tmp)->media_entry.rbe_right)) { ((tmp)->media_entry .rbe_right)->media_entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->media_entry.rbe_parent = (parent)->media_entry .rbe_parent)) { if ((parent) == ((parent)->media_entry.rbe_parent )->media_entry.rbe_left) ((parent)->media_entry.rbe_parent )->media_entry.rbe_left = (tmp); else ((parent)->media_entry .rbe_parent)->media_entry.rbe_right = (tmp); } else (head) ->rbh_root = (tmp); (tmp)->media_entry.rbe_right = (parent ); (parent)->media_entry.rbe_parent = (tmp); do {} while ( 0); if (((tmp)->media_entry.rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root; break; } } } if (elm) ( elm)->media_entry.rbe_color = 0; } struct media_type * mediatypes_RB_REMOVE (struct mediatypes *head, struct media_type *elm) { struct media_type *child, *parent, *old = elm; int color; if ((elm)->media_entry .rbe_left == ((void*)0)) child = (elm)->media_entry.rbe_right ; else if ((elm)->media_entry.rbe_right == ((void*)0)) child = (elm)->media_entry.rbe_left; else { struct media_type * left; elm = (elm)->media_entry.rbe_right; while ((left = ( elm)->media_entry.rbe_left)) elm = left; child = (elm)-> media_entry.rbe_right; parent = (elm)->media_entry.rbe_parent ; color = (elm)->media_entry.rbe_color; if (child) (child) ->media_entry.rbe_parent = parent; if (parent) { if ((parent )->media_entry.rbe_left == elm) (parent)->media_entry.rbe_left = child; else (parent)->media_entry.rbe_right = child; do {} while (0); } else (head)->rbh_root = child; if ((elm)-> media_entry.rbe_parent == old) parent = elm; (elm)->media_entry = (old)->media_entry; if ((old)->media_entry.rbe_parent ) { if (((old)->media_entry.rbe_parent)->media_entry.rbe_left == old) ((old)->media_entry.rbe_parent)->media_entry.rbe_left = elm; else ((old)->media_entry.rbe_parent)->media_entry .rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; ((old)->media_entry.rbe_left)->media_entry.rbe_parent = elm; if ((old)->media_entry.rbe_right) ((old)->media_entry .rbe_right)->media_entry.rbe_parent = elm; if (parent) { left = parent; do { do {} while (0); } while ((left = (left)-> media_entry.rbe_parent)); } goto color; } parent = (elm)-> media_entry.rbe_parent; color = (elm)->media_entry.rbe_color ; if (child) (child)->media_entry.rbe_parent = parent; if ( parent) { if ((parent)->media_entry.rbe_left == elm) (parent )->media_entry.rbe_left = child; else (parent)->media_entry .rbe_right = child; do {} while (0); } else (head)->rbh_root = child; color: if (color == 0) mediatypes_RB_REMOVE_COLOR(head , parent, child); return (old); } struct media_type * mediatypes_RB_INSERT (struct mediatypes *head, struct media_type *elm) { struct media_type *tmp; struct media_type *parent = ((void*)0); int comp = 0; tmp = (head)->rbh_root; while (tmp) { parent = tmp; comp = (media_cmp )(elm, parent); if (comp < 0) tmp = (tmp)->media_entry. rbe_left; else if (comp > 0) tmp = (tmp)->media_entry.rbe_right ; else return (tmp); } do { (elm)->media_entry.rbe_parent = parent; (elm)->media_entry.rbe_left = (elm)->media_entry .rbe_right = ((void*)0); (elm)->media_entry.rbe_color = 1; } while (0); if (parent != ((void*)0)) { if (comp < 0) (parent )->media_entry.rbe_left = elm; else (parent)->media_entry .rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; mediatypes_RB_INSERT_COLOR(head, elm); return (((void *)0)); } struct media_type * mediatypes_RB_FIND(struct mediatypes *head, struct media_type *elm) { struct media_type *tmp = (head )->rbh_root; int comp; while (tmp) { comp = media_cmp(elm, tmp); if (comp < 0) tmp = (tmp)->media_entry.rbe_left; else if (comp > 0) tmp = (tmp)->media_entry.rbe_right; else return (tmp); } return (((void*)0)); } struct media_type * mediatypes_RB_NFIND(struct mediatypes *head, struct media_type *elm) { struct media_type *tmp = (head)->rbh_root; struct media_type *res = ((void*)0); int comp; while (tmp) { comp = media_cmp(elm, tmp); if (comp < 0) { res = tmp; tmp = (tmp )->media_entry.rbe_left; } else if (comp > 0) tmp = (tmp )->media_entry.rbe_right; else return (tmp); } return (res ); } struct media_type * mediatypes_RB_NEXT(struct media_type *elm) { if ((elm)->media_entry.rbe_right) { elm = (elm)-> media_entry.rbe_right; while ((elm)->media_entry.rbe_left) elm = (elm)->media_entry.rbe_left; } else { if ((elm)-> media_entry.rbe_parent && (elm == ((elm)->media_entry .rbe_parent)->media_entry.rbe_left)) elm = (elm)->media_entry .rbe_parent; else { while ((elm)->media_entry.rbe_parent && (elm == ((elm)->media_entry.rbe_parent)->media_entry.rbe_right )) elm = (elm)->media_entry.rbe_parent; elm = (elm)->media_entry .rbe_parent; } } return (elm); } struct media_type * mediatypes_RB_PREV (struct media_type *elm) { if ((elm)->media_entry.rbe_left ) { elm = (elm)->media_entry.rbe_left; while ((elm)->media_entry .rbe_right) elm = (elm)->media_entry.rbe_right; } else { if ((elm)->media_entry.rbe_parent && (elm == ((elm)-> media_entry.rbe_parent)->media_entry.rbe_right)) elm = (elm )->media_entry.rbe_parent; else { while ((elm)->media_entry .rbe_parent && (elm == ((elm)->media_entry.rbe_parent )->media_entry.rbe_left)) elm = (elm)->media_entry.rbe_parent ; elm = (elm)->media_entry.rbe_parent; } } return (elm); } struct media_type * mediatypes_RB_MINMAX(struct mediatypes * head, int val) { struct media_type *tmp = (head)->rbh_root ; struct media_type *parent = ((void*)0); while (tmp) { parent = tmp; if (val < 0) tmp = (tmp)->media_entry.rbe_left; else tmp = (tmp)->media_entry.rbe_right; } return (parent ); }; |
1182 | |
1183 | struct auth * |
1184 | auth_add(struct serverauth *serverauth, struct auth *auth) |
1185 | { |
1186 | struct auth *entry; |
1187 | |
1188 | TAILQ_FOREACH(entry, serverauth, auth_entry)for((entry) = ((serverauth)->tqh_first); (entry) != ((void *)0); (entry) = ((entry)->auth_entry.tqe_next)) { |
1189 | if (strcmp(entry->auth_htpasswd, auth->auth_htpasswd) == 0) |
1190 | return (entry); |
1191 | } |
1192 | |
1193 | if ((entry = calloc(1, sizeof(*entry))) == NULL((void*)0)) |
1194 | return (NULL((void*)0)); |
1195 | |
1196 | memcpy(entry, auth, sizeof(*entry)); |
1197 | |
1198 | TAILQ_INSERT_TAIL(serverauth, entry, auth_entry)do { (entry)->auth_entry.tqe_next = ((void*)0); (entry)-> auth_entry.tqe_prev = (serverauth)->tqh_last; *(serverauth )->tqh_last = (entry); (serverauth)->tqh_last = &(entry )->auth_entry.tqe_next; } while (0); |
1199 | |
1200 | return (entry); |
1201 | } |
1202 | |
1203 | struct auth * |
1204 | auth_byid(struct serverauth *serverauth, uint32_t id) |
1205 | { |
1206 | struct auth *auth; |
1207 | |
1208 | TAILQ_FOREACH(auth, serverauth, auth_entry)for((auth) = ((serverauth)->tqh_first); (auth) != ((void*) 0); (auth) = ((auth)->auth_entry.tqe_next)) { |
1209 | if (auth->auth_id == id) |
1210 | return (auth); |
1211 | } |
1212 | |
1213 | return (NULL((void*)0)); |
1214 | } |
1215 | |
1216 | void |
1217 | auth_free(struct serverauth *serverauth, struct auth *auth) |
1218 | { |
1219 | TAILQ_REMOVE(serverauth, auth, auth_entry)do { if (((auth)->auth_entry.tqe_next) != ((void*)0)) (auth )->auth_entry.tqe_next->auth_entry.tqe_prev = (auth)-> auth_entry.tqe_prev; else (serverauth)->tqh_last = (auth)-> auth_entry.tqe_prev; *(auth)->auth_entry.tqe_prev = (auth) ->auth_entry.tqe_next; ; ; } while (0); |
1220 | } |
1221 | |
1222 | |
1223 | const char * |
1224 | print_host(struct sockaddr_storage *ss, char *buf, size_t len) |
1225 | { |
1226 | if (getnameinfo((struct sockaddr *)ss, ss->ss_len, |
1227 | buf, len, NULL((void*)0), 0, NI_NUMERICHOST1) != 0) { |
1228 | buf[0] = '\0'; |
1229 | return (NULL((void*)0)); |
1230 | } |
1231 | return (buf); |
1232 | } |
1233 | |
1234 | const char * |
1235 | printb_flags(const uint32_t v, const char *bits) |
1236 | { |
1237 | static char buf[2][BUFSIZ1024]; |
1238 | static int idx = 0; |
1239 | int i, any = 0; |
1240 | char c, *p, *r; |
1241 | |
1242 | p = r = buf[++idx % 2]; |
1243 | memset(p, 0, BUFSIZ1024); |
1244 | |
1245 | if (bits) { |
1246 | bits++; |
1247 | while ((i = *bits++)) { |
1248 | if (v & (1 << (i - 1))) { |
1249 | if (any) { |
1250 | *p++ = ','; |
1251 | *p++ = ' '; |
1252 | } |
1253 | any = 1; |
1254 | for (; (c = *bits) > 32; bits++) { |
1255 | if (c == '_') |
1256 | *p++ = ' '; |
1257 | else |
1258 | *p++ = |
1259 | tolower((unsigned char)c); |
1260 | } |
1261 | } else |
1262 | for (; *bits > 32; bits++) |
1263 | ; |
1264 | } |
1265 | } |
1266 | |
1267 | return (r); |
1268 | } |
1269 | |
1270 | void |
1271 | getmonotime(struct timeval *tv) |
1272 | { |
1273 | struct timespec ts; |
1274 | |
1275 | if (clock_gettime(CLOCK_MONOTONIC3, &ts)) |
1276 | fatal("clock_gettime"); |
1277 | |
1278 | TIMESPEC_TO_TIMEVAL(tv, &ts)do { (tv)->tv_sec = (&ts)->tv_sec; (tv)->tv_usec = (&ts)->tv_nsec / 1000; } while (0); |
1279 | } |