Bug Summary

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'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name httpd.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/httpd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/httpd -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/httpd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/httpd/httpd.c
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
50int parent_configure(struct httpd *);
51void parent_configure_done(struct httpd *);
52void parent_reload(struct httpd *, unsigned int, const char *);
53void parent_reopen(struct httpd *);
54void parent_sig_handler(int, short, void *);
55void parent_shutdown(struct httpd *);
56int parent_dispatch_server(int, struct privsep_proc *,
57 struct imsg *);
58int parent_dispatch_logger(int, struct privsep_proc *,
59 struct imsg *);
60void parent_tls_ticket_rekey_start(struct server *);
61void parent_tls_ticket_rekey(int, short, void *);
62
63struct httpd *httpd_env;
64
65static struct privsep_proc procs[] = {
66 { "server", PROC_SERVER, parent_dispatch_server, server },
67 { "logger", PROC_LOGGER, parent_dispatch_logger, logger }
68};
69
70enum privsep_procid privsep_process;
71
72void
73parent_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
105usage(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
114int
115main(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
273int
274parent_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
331void
332parent_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
364void
365parent_reopen(struct httpd *env)
366{
367 proc_compose(env->sc_ps, PROC_LOGGER, IMSG_CTL_REOPEN, NULL((void*)0), 0);
368}
369
370void
371parent_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
391void
392parent_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
409int
410parent_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
426int
427parent_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
466void
467parent_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
479void
480parent_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
502void
503event_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
523int
524expand_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
556const char *
557url_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
597const char *
598canonicalize_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
652size_t
653path_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
681char *
682url_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
705char*
706escape_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
737void
738socket_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
758char *
759evbuffer_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
792char *
793get_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
805void *
806get_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
817int
818sockaddr_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
880uint32_t
881prefixlen2mask(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
892struct in6_addr *
893prefixlen2mask6(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
913int
914accept_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
931struct kv *
932kv_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
960int
961kv_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
988int
989kv_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
1007void
1008kv_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
1025struct kv *
1026kv_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
1044void
1045kv_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
1053void
1054kv_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
1063struct kv *
1064kv_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
1084int
1085kv_cmp(struct kv *a, struct kv *b)
1086{
1087 return (strcasecmp(a->kv_key, b->kv_key));
1088}
1089
1090RB_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
1092struct media_type *
1093media_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
1117void
1118media_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
1126void
1127media_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
1135struct media_type *
1136media_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
1160struct media_type *
1161media_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
1175int
1176media_cmp(struct media_type *a, struct media_type *b)
1177{
1178 return (strcasecmp(a->media_name, b->media_name));
1179}
1180
1181RB_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
1183struct auth *
1184auth_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
1203struct auth *
1204auth_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
1216void
1217auth_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
1223const char *
1224print_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
1234const char *
1235printb_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
1270void
1271getmonotime(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}