| | varnish-cache/bin/varnishd/cache/cache_ban_build.c |
| 0 |
|
/*- |
| 1 |
|
* Copyright (c) 2006 Verdens Gang AS |
| 2 |
|
* Copyright (c) 2006-2015 Varnish Software AS |
| 3 |
|
* All rights reserved. |
| 4 |
|
* |
| 5 |
|
* Author: Poul-Henning Kamp <phk@phk.freebsd.dk> |
| 6 |
|
* |
| 7 |
|
* SPDX-License-Identifier: BSD-2-Clause |
| 8 |
|
* |
| 9 |
|
* Redistribution and use in source and binary forms, with or without |
| 10 |
|
* modification, are permitted provided that the following conditions |
| 11 |
|
* are met: |
| 12 |
|
* 1. Redistributions of source code must retain the above copyright |
| 13 |
|
* notice, this list of conditions and the following disclaimer. |
| 14 |
|
* 2. Redistributions in binary form must reproduce the above copyright |
| 15 |
|
* notice, this list of conditions and the following disclaimer in the |
| 16 |
|
* documentation and/or other materials provided with the distribution. |
| 17 |
|
* |
| 18 |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| 19 |
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 20 |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 21 |
|
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE |
| 22 |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 23 |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 24 |
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 25 |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 26 |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 27 |
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 28 |
|
* SUCH DAMAGE. |
| 29 |
|
* |
| 30 |
|
*/ |
| 31 |
|
|
| 32 |
|
#include "config.h" |
| 33 |
|
|
| 34 |
|
#include <stdlib.h> |
| 35 |
|
|
| 36 |
|
#include "cache_varnishd.h" |
| 37 |
|
#include "cache_ban.h" |
| 38 |
|
|
| 39 |
|
#include "vend.h" |
| 40 |
|
#include "vtim.h" |
| 41 |
|
#include "vnum.h" |
| 42 |
|
|
| 43 |
|
void BAN_Build_Init(void); |
| 44 |
|
void BAN_Build_Fini(void); |
| 45 |
|
|
| 46 |
|
struct ban_proto { |
| 47 |
|
unsigned magic; |
| 48 |
|
#define BAN_PROTO_MAGIC 0xd8adc494 |
| 49 |
|
unsigned flags; /* BANS_FLAG_* */ |
| 50 |
|
|
| 51 |
|
struct vsb *vsb; |
| 52 |
|
char *err; |
| 53 |
|
}; |
| 54 |
|
|
| 55 |
|
/*-------------------------------------------------------------------- |
| 56 |
|
* Variables we can ban on |
| 57 |
|
*/ |
| 58 |
|
|
| 59 |
|
static const struct pvar { |
| 60 |
|
const char *name; |
| 61 |
|
unsigned flag; |
| 62 |
|
uint8_t tag; |
| 63 |
|
} pvars[] = { |
| 64 |
|
#define PVAR(a, b, c) { (a), (b), (c) }, |
| 65 |
|
#include "tbl/ban_vars.h" |
| 66 |
|
{ 0, 0, 0} |
| 67 |
|
}; |
| 68 |
|
|
| 69 |
|
/* operators allowed per argument (pvar.tag) */ |
| 70 |
|
static const unsigned arg_opervalid[BAN_ARGARRSZ + 1] = { |
| 71 |
|
#define ARGOPER(arg, mask) [BAN_ARGIDX(arg)] = (mask), |
| 72 |
|
#include "tbl/ban_arg_oper.h" |
| 73 |
|
[BAN_ARGARRSZ] = 0 |
| 74 |
|
}; |
| 75 |
|
|
| 76 |
|
// init'ed in _Init |
| 77 |
|
static const char *arg_operhelp[BAN_ARGARRSZ + 1]; |
| 78 |
|
|
| 79 |
|
// operators |
| 80 |
|
const char * const ban_oper[BAN_OPERARRSZ + 1] = { |
| 81 |
|
#define OPER(op, str) [BAN_OPERIDX(op)] = (str), |
| 82 |
|
#include "tbl/ban_oper.h" |
| 83 |
|
[BAN_OPERARRSZ] = NULL |
| 84 |
|
}; |
| 85 |
|
|
| 86 |
|
|
| 87 |
|
/*-------------------------------------------------------------------- |
| 88 |
|
*/ |
| 89 |
|
|
| 90 |
|
static char ban_build_err_no_mem[] = "No Memory"; |
| 91 |
|
|
| 92 |
|
/*-------------------------------------------------------------------- |
| 93 |
|
*/ |
| 94 |
|
|
| 95 |
|
struct ban_proto * |
| 96 |
43068 |
BAN_Build(void) |
| 97 |
|
{ |
| 98 |
|
struct ban_proto *bp; |
| 99 |
|
|
| 100 |
43068 |
ALLOC_OBJ(bp, BAN_PROTO_MAGIC); |
| 101 |
43068 |
if (bp == NULL) |
| 102 |
0 |
return (bp); |
| 103 |
43068 |
bp->vsb = VSB_new_auto(); |
| 104 |
43068 |
if (bp->vsb == NULL) { |
| 105 |
0 |
FREE_OBJ(bp); |
| 106 |
0 |
return (NULL); |
| 107 |
|
} |
| 108 |
43068 |
return (bp); |
| 109 |
43068 |
} |
| 110 |
|
|
| 111 |
|
// TODO: change to (struct ban_proto **) |
| 112 |
|
void |
| 113 |
43068 |
BAN_Abandon(struct ban_proto *bp) |
| 114 |
|
{ |
| 115 |
|
|
| 116 |
43068 |
CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC); |
| 117 |
43068 |
VSB_destroy(&bp->vsb); |
| 118 |
43068 |
FREE_OBJ(bp); |
| 119 |
43068 |
} |
| 120 |
|
|
| 121 |
|
/*-------------------------------------------------------------------- |
| 122 |
|
*/ |
| 123 |
|
|
| 124 |
|
static void |
| 125 |
5840 |
ban_add_lump(const struct ban_proto *bp, const void *p, uint32_t len) |
| 126 |
|
{ |
| 127 |
5840 |
uint8_t buf[PRNDUP(sizeof len)] = { 0xff }; |
| 128 |
|
|
| 129 |
33360 |
while (VSB_len(bp->vsb) & PALGN) |
| 130 |
27520 |
VSB_putc(bp->vsb, buf[0]); |
| 131 |
5840 |
vbe32enc(buf, len); |
| 132 |
5840 |
VSB_bcat(bp->vsb, buf, sizeof buf); |
| 133 |
5840 |
VSB_bcat(bp->vsb, p, len); |
| 134 |
5840 |
} |
| 135 |
|
|
| 136 |
|
/*-------------------------------------------------------------------- |
| 137 |
|
*/ |
| 138 |
|
|
| 139 |
|
static const char * |
| 140 |
720 |
ban_error(struct ban_proto *bp, const char *fmt, ...) |
| 141 |
|
{ |
| 142 |
|
va_list ap; |
| 143 |
|
|
| 144 |
720 |
CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC); |
| 145 |
720 |
AN(bp->vsb); |
| 146 |
|
|
| 147 |
|
/* First error is sticky */ |
| 148 |
720 |
if (bp->err == NULL) { |
| 149 |
720 |
if (fmt == ban_build_err_no_mem) { |
| 150 |
0 |
bp->err = ban_build_err_no_mem; |
| 151 |
0 |
} else { |
| 152 |
|
/* Record the error message in the vsb */ |
| 153 |
720 |
VSB_clear(bp->vsb); |
| 154 |
720 |
va_start(ap, fmt); |
| 155 |
720 |
VSB_vprintf(bp->vsb, fmt, ap); |
| 156 |
720 |
va_end(ap); |
| 157 |
720 |
AZ(VSB_finish(bp->vsb)); |
| 158 |
720 |
bp->err = VSB_data(bp->vsb); |
| 159 |
|
} |
| 160 |
720 |
} |
| 161 |
720 |
return (bp->err); |
| 162 |
|
} |
| 163 |
|
|
| 164 |
|
/*-------------------------------------------------------------------- |
| 165 |
|
* Parse and add a http argument specification |
| 166 |
|
* Output something which HTTP_GetHdr understands |
| 167 |
|
*/ |
| 168 |
|
|
| 169 |
|
static void |
| 170 |
1920 |
ban_parse_http(const struct ban_proto *bp, const char *a1) |
| 171 |
|
{ |
| 172 |
|
int l; |
| 173 |
|
|
| 174 |
1920 |
l = strlen(a1) + 1; |
| 175 |
1920 |
assert(l <= 127); |
| 176 |
1920 |
VSB_putc(bp->vsb, (char)l); |
| 177 |
1920 |
VSB_cat(bp->vsb, a1); |
| 178 |
1920 |
VSB_putc(bp->vsb, ':'); |
| 179 |
1920 |
VSB_putc(bp->vsb, '\0'); |
| 180 |
1920 |
} |
| 181 |
|
|
| 182 |
|
/*-------------------------------------------------------------------- |
| 183 |
|
* Parse and add a ban test specification |
| 184 |
|
*/ |
| 185 |
|
|
| 186 |
|
static const char * |
| 187 |
1200 |
ban_parse_regexp(struct ban_proto *bp, const char *a3) |
| 188 |
|
{ |
| 189 |
|
struct vsb vsb[1]; |
| 190 |
|
char errbuf[VRE_ERROR_LEN]; |
| 191 |
|
int errorcode, erroroffset; |
| 192 |
|
size_t sz; |
| 193 |
|
vre_t *re, *rex; |
| 194 |
|
|
| 195 |
1200 |
re = VRE_compile(a3, 0, &errorcode, &erroroffset, 0); |
| 196 |
1200 |
if (re == NULL) { |
| 197 |
40 |
AN(VSB_init(vsb, errbuf, sizeof errbuf)); |
| 198 |
40 |
AZ(VRE_error(vsb, errorcode)); |
| 199 |
40 |
AZ(VSB_finish(vsb)); |
| 200 |
40 |
VSB_fini(vsb); |
| 201 |
40 |
return (ban_error(bp, "Regex compile error: %s", errbuf)); |
| 202 |
|
} |
| 203 |
|
|
| 204 |
1160 |
rex = VRE_export(re, &sz); |
| 205 |
1160 |
AN(rex); |
| 206 |
1160 |
ban_add_lump(bp, rex, sz); |
| 207 |
1160 |
VRE_free(&rex); |
| 208 |
1160 |
VRE_free(&re); |
| 209 |
1160 |
return (0); |
| 210 |
1200 |
} |
| 211 |
|
|
| 212 |
|
static int |
| 213 |
5000 |
ban_parse_oper(const char *p) |
| 214 |
|
{ |
| 215 |
|
int i; |
| 216 |
|
|
| 217 |
10840 |
for (i = 0; i < BAN_OPERARRSZ; i++) { |
| 218 |
10680 |
if (!strcmp(p, ban_oper[i])) |
| 219 |
4840 |
return (BANS_OPER_OFF_ + i); |
| 220 |
5840 |
} |
| 221 |
160 |
return (-1); |
| 222 |
5000 |
} |
| 223 |
|
|
| 224 |
|
/*-------------------------------------------------------------------- |
| 225 |
|
* Add a (and'ed) test-condition to a ban |
| 226 |
|
*/ |
| 227 |
|
static const char * |
| 228 |
3560 |
ban_add_spec(struct ban_proto *bp, const struct pvar *pv, int op, const char *a3) |
| 229 |
|
{ |
| 230 |
|
|
| 231 |
3560 |
assert(! BANS_HAS_ARG2_DOUBLE(pv->tag)); |
| 232 |
|
|
| 233 |
3560 |
ban_add_lump(bp, a3, strlen(a3) + 1); |
| 234 |
3560 |
VSB_putc(bp->vsb, op); |
| 235 |
|
|
| 236 |
3560 |
if (! BANS_HAS_ARG2_SPEC(op)) |
| 237 |
2360 |
return (NULL); |
| 238 |
|
|
| 239 |
1200 |
return (ban_parse_regexp(bp, a3)); |
| 240 |
3560 |
} |
| 241 |
|
|
| 242 |
|
static const char * |
| 243 |
1120 |
ban_add_double(const struct ban_proto *bp, const struct pvar *pv, int op, double darg) |
| 244 |
|
{ |
| 245 |
|
uint64_t dtmp; |
| 246 |
|
uint8_t denc[sizeof darg]; |
| 247 |
|
|
| 248 |
1120 |
assert(BANS_HAS_ARG2_DOUBLE(pv->tag)); |
| 249 |
1120 |
assert(sizeof darg == sizeof dtmp); |
| 250 |
1120 |
assert(sizeof dtmp == sizeof denc); |
| 251 |
1120 |
memcpy(&dtmp, &darg, sizeof dtmp); |
| 252 |
1120 |
vbe64enc(denc, dtmp); |
| 253 |
|
|
| 254 |
1120 |
ban_add_lump(bp, denc, sizeof denc); |
| 255 |
1120 |
VSB_putc(bp->vsb, op); |
| 256 |
1120 |
return (NULL); |
| 257 |
|
} |
| 258 |
|
|
| 259 |
|
static const char * |
| 260 |
1200 |
ban_add_duration(struct ban_proto *bp, const struct pvar *pv, int op, const char *a3) |
| 261 |
|
{ |
| 262 |
|
double darg; |
| 263 |
|
|
| 264 |
1200 |
assert(pv->flag & BANS_FLAG_DURATION); |
| 265 |
1200 |
darg = VNUM_duration(a3); |
| 266 |
1200 |
if (isnan(darg)) { |
| 267 |
160 |
return (ban_error(bp, |
| 268 |
80 |
"expected duration <n.nn>[ms|s|m|h|d|w|y] got \"%s\"", a3)); |
| 269 |
|
} |
| 270 |
1120 |
return (ban_add_double(bp, pv, op, darg)); |
| 271 |
1200 |
} |
| 272 |
|
|
| 273 |
|
const char * |
| 274 |
5360 |
BAN_AddTest(struct ban_proto *bp, |
| 275 |
|
const char *a1, const char *a2, const char *a3) |
| 276 |
|
{ |
| 277 |
|
const struct pvar *pv; |
| 278 |
|
int op; |
| 279 |
|
|
| 280 |
5360 |
CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC); |
| 281 |
5360 |
AN(bp->vsb); |
| 282 |
5360 |
AN(a1); |
| 283 |
5360 |
AN(a2); |
| 284 |
5360 |
AN(a3); |
| 285 |
|
|
| 286 |
5360 |
if (bp->err != NULL) |
| 287 |
0 |
return (bp->err); |
| 288 |
|
|
| 289 |
21680 |
for (pv = pvars; pv->name != NULL; pv++) { |
| 290 |
21360 |
if (!(pv->flag & BANS_FLAG_HTTP) && !strcmp(a1, pv->name)) |
| 291 |
3080 |
break; |
| 292 |
18280 |
if ((pv->flag & BANS_FLAG_HTTP) && !strncmp(a1, pv->name, strlen(pv->name))) |
| 293 |
1960 |
break; |
| 294 |
16320 |
} |
| 295 |
|
|
| 296 |
5360 |
if (pv->name == NULL) |
| 297 |
640 |
return (ban_error(bp, |
| 298 |
320 |
"Unknown or unsupported field \"%s\"", a1)); |
| 299 |
|
|
| 300 |
5040 |
bp->flags |= pv->flag; |
| 301 |
|
|
| 302 |
5040 |
VSB_putc(bp->vsb, pv->tag); |
| 303 |
5040 |
if (pv->flag & BANS_FLAG_HTTP) { |
| 304 |
1960 |
if (strlen(a1 + strlen(pv->name)) < 1) |
| 305 |
80 |
return (ban_error(bp, |
| 306 |
40 |
"Missing header name: \"%s\"", pv->name)); |
| 307 |
1920 |
assert(BANS_HAS_ARG1_SPEC(pv->tag)); |
| 308 |
1920 |
ban_parse_http(bp, a1 + strlen(pv->name)); |
| 309 |
1920 |
} |
| 310 |
|
|
| 311 |
5000 |
op = ban_parse_oper(a2); |
| 312 |
5000 |
if (op < BANS_OPER_OFF_ || |
| 313 |
4840 |
((1U << BAN_OPERIDX(op)) & arg_opervalid[BAN_ARGIDX(pv->tag)]) == 0) |
| 314 |
480 |
return (ban_error(bp, |
| 315 |
|
"expected conditional (%s) got \"%s\"", |
| 316 |
240 |
arg_operhelp[BAN_ARGIDX(pv->tag)], a2)); |
| 317 |
|
|
| 318 |
4760 |
if (pv->flag & BANS_FLAG_DURATION) |
| 319 |
1200 |
return (ban_add_duration(bp, pv, op, a3)); |
| 320 |
|
else |
| 321 |
3560 |
return (ban_add_spec(bp, pv, op, a3)); |
| 322 |
5360 |
} |
| 323 |
|
|
| 324 |
|
/*-------------------------------------------------------------------- |
| 325 |
|
* We maintain ban_start as a pointer to the first element of the list |
| 326 |
|
* as a separate variable from the VTAILQ, to avoid depending on the |
| 327 |
|
* internals of the VTAILQ macros. We tacitly assume that a pointer |
| 328 |
|
* write is always atomic in doing so. |
| 329 |
|
* |
| 330 |
|
* Returns: |
| 331 |
|
* 0: Ban successfully inserted |
| 332 |
|
* -1: Ban not inserted due to shutdown in progress. The ban has been |
| 333 |
|
* deleted. |
| 334 |
|
*/ |
| 335 |
|
|
| 336 |
|
const char * |
| 337 |
42028 |
BAN_Commit(struct ban_proto *bp) |
| 338 |
|
{ |
| 339 |
|
struct ban *b, *bi; |
| 340 |
|
ssize_t ln; |
| 341 |
|
vtim_real t0; |
| 342 |
|
uint64_t u; |
| 343 |
|
|
| 344 |
42028 |
CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC); |
| 345 |
42028 |
AN(bp->vsb); |
| 346 |
42028 |
assert(sizeof u == sizeof t0); |
| 347 |
|
|
| 348 |
42028 |
if (ban_shutdown) |
| 349 |
0 |
return (ban_error(bp, "Shutting down")); |
| 350 |
|
|
| 351 |
42028 |
AZ(VSB_finish(bp->vsb)); |
| 352 |
42028 |
ln = VSB_len(bp->vsb); |
| 353 |
42028 |
assert(ln >= 0); |
| 354 |
|
|
| 355 |
42028 |
ALLOC_OBJ(b, BAN_MAGIC); |
| 356 |
42028 |
if (b == NULL) |
| 357 |
0 |
return (ban_error(bp, ban_build_err_no_mem)); |
| 358 |
42028 |
VTAILQ_INIT(&b->objcore); |
| 359 |
|
|
| 360 |
42028 |
b->spec = malloc(ln + BANS_HEAD_LEN); |
| 361 |
42028 |
if (b->spec == NULL) { |
| 362 |
0 |
free(b); |
| 363 |
0 |
return (ban_error(bp, ban_build_err_no_mem)); |
| 364 |
|
} |
| 365 |
|
|
| 366 |
42028 |
b->flags = bp->flags; |
| 367 |
|
|
| 368 |
42028 |
memset(b->spec, 0, BANS_HEAD_LEN); |
| 369 |
42028 |
t0 = VTIM_real(); |
| 370 |
42028 |
memcpy(&u, &t0, sizeof u); |
| 371 |
42028 |
vbe64enc(b->spec + BANS_TIMESTAMP, u); |
| 372 |
42028 |
b->spec[BANS_FLAGS] = b->flags & 0xff; |
| 373 |
42028 |
memcpy(b->spec + BANS_HEAD_LEN, VSB_data(bp->vsb), ln); |
| 374 |
42028 |
ln += BANS_HEAD_LEN; |
| 375 |
42028 |
vbe32enc(b->spec + BANS_LENGTH, ln); |
| 376 |
|
|
| 377 |
42028 |
Lck_Lock(&ban_mtx); |
| 378 |
42028 |
if (ban_shutdown) { |
| 379 |
|
/* We could have raced a shutdown */ |
| 380 |
0 |
Lck_Unlock(&ban_mtx); |
| 381 |
0 |
BAN_Free(b); |
| 382 |
0 |
return (ban_error(bp, "Shutting down")); |
| 383 |
|
} |
| 384 |
42028 |
bi = VTAILQ_FIRST(&ban_head); |
| 385 |
42028 |
VTAILQ_INSERT_HEAD(&ban_head, b, list); |
| 386 |
42028 |
ban_start = b; |
| 387 |
|
|
| 388 |
42028 |
VSC_C_main->bans++; |
| 389 |
42028 |
VSC_C_main->bans_added++; |
| 390 |
42028 |
bans_persisted_bytes += ln; |
| 391 |
42028 |
VSC_C_main->bans_persisted_bytes = bans_persisted_bytes; |
| 392 |
|
|
| 393 |
42028 |
if (b->flags & BANS_FLAG_OBJ) |
| 394 |
2480 |
VSC_C_main->bans_obj++; |
| 395 |
42028 |
if (b->flags & BANS_FLAG_REQ) |
| 396 |
1680 |
VSC_C_main->bans_req++; |
| 397 |
|
|
| 398 |
42028 |
if (bi != NULL) |
| 399 |
4000 |
ban_info_new(b->spec, ln); /* Notify stevedores */ |
| 400 |
|
|
| 401 |
42028 |
if (cache_param->ban_dups) { |
| 402 |
|
/* Hunt down duplicates, and mark them as completed */ |
| 403 |
55268 |
for (bi = VTAILQ_NEXT(b, list); bi != NULL; |
| 404 |
13240 |
bi = VTAILQ_NEXT(bi, list)) { |
| 405 |
13240 |
if (!(bi->flags & BANS_FLAG_COMPLETED) && |
| 406 |
9880 |
ban_equal(b->spec, bi->spec)) { |
| 407 |
520 |
ban_mark_completed(bi); |
| 408 |
520 |
VSC_C_main->bans_dups++; |
| 409 |
520 |
} |
| 410 |
13240 |
} |
| 411 |
42028 |
} |
| 412 |
42028 |
if (!(b->flags & BANS_FLAG_REQ)) |
| 413 |
40348 |
ban_kick_lurker(); |
| 414 |
42028 |
Lck_Unlock(&ban_mtx); |
| 415 |
|
|
| 416 |
42028 |
BAN_Abandon(bp); |
| 417 |
42028 |
return (NULL); |
| 418 |
42028 |
} |
| 419 |
|
|
| 420 |
|
static void |
| 421 |
342252 |
ban_build_arg_operhelp(struct vsb *vsb, int arg) |
| 422 |
|
{ |
| 423 |
|
unsigned mask; |
| 424 |
342252 |
const char *p = NULL, *n = NULL; |
| 425 |
|
int i; |
| 426 |
|
|
| 427 |
342252 |
ASSERT_BAN_ARG(arg); |
| 428 |
342252 |
mask = arg_opervalid[BAN_ARGIDX(arg)]; |
| 429 |
|
|
| 430 |
3080268 |
for (i = 0; i < BAN_OPERARRSZ; i++) { |
| 431 |
2738016 |
if ((mask & (1U << i)) == 0) |
| 432 |
988728 |
continue; |
| 433 |
1749288 |
if (p == NULL) |
| 434 |
342252 |
p = ban_oper[i]; |
| 435 |
1407036 |
else if (n == NULL) |
| 436 |
342252 |
n = ban_oper[i]; |
| 437 |
|
else { |
| 438 |
1064784 |
VSB_cat(vsb, p); |
| 439 |
1064784 |
VSB_cat(vsb, ", "); |
| 440 |
1064784 |
p = n; |
| 441 |
1064784 |
n = ban_oper[i]; |
| 442 |
|
} |
| 443 |
1749288 |
} |
| 444 |
|
|
| 445 |
342252 |
if (n) { |
| 446 |
342252 |
AN(p); |
| 447 |
342252 |
VSB_cat(vsb, p); |
| 448 |
342252 |
VSB_cat(vsb, " or "); |
| 449 |
342252 |
VSB_cat(vsb, n); |
| 450 |
342252 |
return; |
| 451 |
|
} |
| 452 |
|
|
| 453 |
0 |
AN(p); |
| 454 |
0 |
VSB_cat(vsb, p); |
| 455 |
342252 |
} |
| 456 |
|
|
| 457 |
|
void |
| 458 |
38028 |
BAN_Build_Init(void) { |
| 459 |
|
struct vsb *vsb; |
| 460 |
|
int i; |
| 461 |
|
|
| 462 |
38028 |
vsb = VSB_new_auto(); |
| 463 |
38028 |
AN(vsb); |
| 464 |
380280 |
for (i = BANS_ARG_OFF_; i < BANS_ARG_LIM; i ++) { |
| 465 |
342252 |
VSB_clear(vsb); |
| 466 |
342252 |
ban_build_arg_operhelp(vsb, i); |
| 467 |
342252 |
AZ(VSB_finish(vsb)); |
| 468 |
|
|
| 469 |
342252 |
arg_operhelp[BAN_ARGIDX(i)] = strdup(VSB_data(vsb)); |
| 470 |
342252 |
AN(arg_operhelp[BAN_ARGIDX(i)]); |
| 471 |
342252 |
} |
| 472 |
38028 |
arg_operhelp[BAN_ARGIDX(i)] = NULL; |
| 473 |
38028 |
VSB_destroy(&vsb); |
| 474 |
38028 |
} |
| 475 |
|
|
| 476 |
|
void |
| 477 |
37520 |
BAN_Build_Fini(void) { |
| 478 |
|
int i; |
| 479 |
|
|
| 480 |
375200 |
for (i = 0; i < BAN_ARGARRSZ; i++) |
| 481 |
337680 |
free(TRUST_ME(arg_operhelp[i])); |
| 482 |
37520 |
} |