varnish-cache/bin/varnishd/mgt/mgt_param_tweak.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2011 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
 * Functions for tweaking parameters
31
 *
32
 */
33
34
#include "config.h"
35
36
#include <limits.h>
37
#include <math.h>
38
#include <stdio.h>
39
#include <stdlib.h>
40
#include <string.h>
41
42
#include "mgt/mgt.h"
43
44
#include "mgt/mgt_param.h"
45
#include "storage/storage.h"
46
#include "vav.h"
47
#include "vnum.h"
48
#include "vsl_priv.h"
49
50
const char * const JSON_FMT = (const char *)&JSON_FMT;
51
52
/*--------------------------------------------------------------------
53
 * Generic handling of double typed parameters
54
 */
55
56
typedef double parse_double_f(const char *, const char **);
57
58
static double
59 748560
parse_decimal(const char *p, const char **err)
60
{
61
        double v;
62
63 748560
        v = SF_Parse_Decimal(&p, 0, err);
64 748560
        if (errno == 0 && *p != '\0') {
65 40
                errno = EINVAL;
66 40
                *err = "Invalid number";
67 40
        }
68 748560
        return (v);
69
}
70
71
static int
72 7713840
tweak_generic_double(struct vsb *vsb, const char *arg, const struct parspec *pp,
73
    parse_double_f parse, const char *fmt)
74
{
75 7713840
        volatile double u, minv = VRT_DECIMAL_MIN, maxv = VRT_DECIMAL_MAX;
76 7713840
        volatile double *dest = pp->priv;
77
        const char *err;
78
79 7713840
        if (arg != NULL && arg != JSON_FMT) {
80 3908880
                if (pp->min != NULL) {
81 3908880
                        minv = parse(pp->min, &err);
82 3908880
                        if (errno) {
83 0
                                VSB_printf(vsb, "Min: %s (%s)\n", err, pp->min);
84 0
                                return (-1);
85
                        }
86 3908880
                }
87 3908880
                if (pp->max != NULL) {
88 1246840
                        maxv = parse(pp->max, &err);
89 1246840
                        if (errno) {
90 0
                                VSB_printf(vsb, "Max: %s (%s)\n", err, pp->max);
91 0
                                return (-1);
92
                        }
93 1246840
                }
94
95 3908880
                u = parse(arg, &err);
96 3908880
                if (errno) {
97 160
                        VSB_printf(vsb, "%s (%s)\n", err, arg);
98 160
                        return (-1);
99
                }
100 3908720
                if (u < minv) {
101 80
                        VSB_printf(vsb,
102 40
                            "Must be greater or equal to %s\n", pp->min);
103 40
                        return (-1);
104
                }
105 3908680
                if (u > maxv) {
106 80
                        VSB_printf(vsb,
107 40
                            "Must be less than or equal to %s\n", pp->max);
108 40
                        return (-1);
109
                }
110 3908640
                *dest = u;
111 3908640
        } else {
112 3804960
                VSB_printf(vsb, fmt, *dest);
113
        }
114 7713600
        return (0);
115 7713840
}
116
117
/*--------------------------------------------------------------------*/
118
119
static double
120 8316040
parse_duration(const char *p, const char **err)
121
{
122
        double v, r;
123
124 8316040
        v = SF_Parse_Decimal(&p, 0, err);
125 8316040
        if (*p == '\0')
126 7609000
                return (v);
127
128 707040
        r = VNUM_duration_unit(v, p, NULL);
129 707040
        if (isnan(r)) {
130 80
                errno = EINVAL;
131 80
                *err = "Invalid duration unit";
132 80
        }
133
134 707040
        return (r);
135 8316040
}
136
137
int v_matchproto_(tweak_t)
138 1919560
tweak_timeout(struct vsb *vsb, const struct parspec *par, const char *arg)
139
{
140 1919560
        volatile double *dest = par->priv;
141
142 1919560
        if (arg != NULL && !strcmp(arg, "never")) {
143 40
                *dest = INFINITY;
144 40
                return (0);
145
        }
146
147 1919520
        if (*dest == INFINITY && arg == NULL) {
148 0
                VSB_cat(vsb, "never");
149 0
                return (0);
150
        }
151
152 1919520
        if (*dest == INFINITY && arg == JSON_FMT) {
153 0
                VSB_cat(vsb, "\"never\"");
154 0
                return (0);
155
        }
156
157 1919520
        return (tweak_generic_double(vsb, arg, par, parse_duration, "%.3f"));
158 1919560
}
159
160
int v_matchproto_(tweak_t)
161 5419600
tweak_duration(struct vsb *vsb, const struct parspec *par, const char *arg)
162
{
163
164 5419600
        return (tweak_generic_double(vsb, arg, par, parse_duration, "%.3f"));
165
}
166
167
/*--------------------------------------------------------------------*/
168
169
int v_matchproto_(tweak_t)
170 249800
tweak_double(struct vsb *vsb, const struct parspec *par, const char *arg)
171
{
172
173 249800
        return (tweak_generic_double(vsb, arg, par, parse_decimal, "%g"));
174
}
175
176
/*--------------------------------------------------------------------*/
177
178
static int
179 492200
parse_boolean(struct vsb *vsb, const char *arg)
180
{
181
182 492200
        if (!strcasecmp(arg, "off"))
183 159040
                return (0);
184 333160
        if (!strcasecmp(arg, "disable"))
185 40
                return (0);
186 333120
        if (!strcasecmp(arg, "no"))
187 40
                return (0);
188 333080
        if (!strcasecmp(arg, "false"))
189 160
                return (0);
190 332920
        if (!strcasecmp(arg, "on"))
191 332360
                return (1);
192 560
        if (!strcasecmp(arg, "enable"))
193 40
                return (1);
194 520
        if (!strcasecmp(arg, "yes"))
195 40
                return (1);
196 480
        if (!strcasecmp(arg, "true"))
197 440
                return (1);
198
199 40
        VSB_cat(vsb, "use \"on\" or \"off\"\n");
200 40
        return (-1);
201 492200
}
202
203
int v_matchproto_(tweak_t)
204 913800
tweak_boolean(struct vsb *vsb, const struct parspec *par, const char *arg)
205
{
206
        volatile unsigned *dest;
207
        int val;
208
209 913800
        dest = par->priv;
210 913800
        if (arg != NULL && arg != JSON_FMT) {
211 492200
                val = parse_boolean(vsb, arg);
212 492200
                if (val < 0)
213 40
                        return (-1);
214 492160
                *dest = val;
215 913760
        } else if (arg == JSON_FMT) {
216 1200
                VSB_printf(vsb, "%s", *dest ? "true" : "false");
217 1200
        } else {
218 420400
                VSB_printf(vsb, "%s", *dest ? "on" : "off");
219
        }
220 913760
        return (0);
221 913800
}
222
223
/*--------------------------------------------------------------------*/
224
225
static int
226 6251760
tweak_generic_uint(struct vsb *vsb, volatile unsigned *dest, const char *arg,
227
    const char *min, const char *max,
228
    const char *min_reason, const char *max_reason)
229
{
230 6251760
        unsigned u, minv = 0, maxv = 0;
231
        char *p;
232
233 6251760
        if (arg != NULL && arg != JSON_FMT) {
234 3241840
                if (min != NULL) {
235 2866960
                        p = NULL;
236 2866960
                        minv = strtoul(min, &p, 0);
237 2866960
                        if (*arg == '\0' || *p != '\0') {
238 0
                                VSB_printf(vsb, "Illegal Min: %s\n", min);
239 0
                                return (-1);
240
                        }
241 2866960
                }
242 3241840
                if (max != NULL) {
243 1204000
                        p = NULL;
244 1204000
                        maxv = strtoul(max, &p, 0);
245 1204000
                        if (*arg == '\0' || *p != '\0') {
246 0
                                VSB_printf(vsb, "Illegal Max: %s\n", max);
247 0
                                return (-1);
248
                        }
249 1204000
                }
250 3241840
                p = NULL;
251 3241840
                if (!strcasecmp(arg, "unlimited"))
252 40
                        u = UINT_MAX;
253
                else {
254 3241800
                        u = strtoul(arg, &p, 0);
255 3241800
                        if (*arg == '\0' || *p != '\0') {
256 80
                                VSB_printf(vsb, "Not a number (%s)\n", arg);
257 80
                                return (-1);
258
                        }
259
                }
260 3241760
                if (min != NULL && u < minv) {
261 160
                        VSB_printf(vsb, "Must be at least %s", min);
262 160
                        if (min_reason != NULL)
263 80
                                VSB_printf(vsb, " (%s)", min_reason);
264 160
                        VSB_putc(vsb, '\n');
265 160
                        return (-1);
266
                }
267 3241600
                if (max != NULL && u > maxv) {
268 240
                        VSB_printf(vsb, "Must be no more than %s", max);
269 240
                        if (max_reason != NULL)
270 200
                                VSB_printf(vsb, " (%s)", max_reason);
271 240
                        VSB_putc(vsb, '\n');
272 240
                        return (-1);
273
                }
274 3241360
                *dest = u;
275 6251280
        } else if (*dest == UINT_MAX && arg != JSON_FMT) {
276 200
                VSB_cat(vsb, "unlimited");
277 200
        } else {
278 3009720
                VSB_printf(vsb, "%u", *dest);
279
        }
280 6251280
        return (0);
281 6251760
}
282
283
/*--------------------------------------------------------------------*/
284
285
int v_matchproto_(tweak_t)
286 5793480
tweak_uint(struct vsb *vsb, const struct parspec *par, const char *arg)
287
{
288
        volatile unsigned *dest;
289
290 5793480
        dest = par->priv;
291 11586960
        return (tweak_generic_uint(vsb, dest, arg, par->min, par->max,
292 5793480
            par->dyn_min_reason, par->dyn_max_reason));
293
}
294
295
int v_matchproto_(tweak_t)
296 249840
tweak_uint_orzero(struct vsb *vsb, const struct parspec *par, const char *arg)
297
{
298
        volatile unsigned *dest;
299
300 249840
        dest = par->priv;
301 249840
        if (arg != NULL && arg != JSON_FMT && ! strcmp(arg, "0")) {
302 41520
                VSB_cat(vsb, "0");
303 41520
                *dest = 0;
304 41520
                return (0);
305
        }
306 416640
        return (tweak_generic_uint(vsb, dest, arg, par->min, par->max,
307 208320
            par->dyn_min_reason, par->dyn_max_reason));
308 249840
}
309
310
/*--------------------------------------------------------------------*/
311
312
static void
313 2420640
fmt_bytes(struct vsb *vsb, uintmax_t t)
314
{
315
        const char *p;
316
317 2420640
        if (t == 0 || t & 0xff) {
318 832040
                VSB_printf(vsb, "%jub", t);
319 832040
                return;
320
        }
321 2172480
        for (p = "kMGTPEZY"; *p; p++) {
322 2172480
                if (t & 0x300) {
323 208640
                        VSB_printf(vsb, "%.2f%c", t / 1024.0, *p);
324 208640
                        return;
325
                }
326 1963840
                t /= 1024;
327 1963840
                if (t & 0x0ff) {
328 1379960
                        VSB_printf(vsb, "%ju%c", t, *p);
329 1379960
                        return;
330
                }
331 583880
        }
332 0
        VSB_cat(vsb, "(bogus number)");
333 2420640
}
334
335
static int
336 4948680
tweak_generic_bytes(struct vsb *vsb, volatile ssize_t *dest, const char *arg,
337
    const char *min, const char *max)
338
{
339 4948680
        uintmax_t r, rmin = 0, rmax = 0;
340
        const char *p;
341
342 4948680
        if (arg != NULL && arg != JSON_FMT) {
343 2525160
                if (min != NULL) {
344 2525160
                        p = VNUM_2bytes(min, &rmin, 0);
345 2525160
                        if (p != NULL) {
346 0
                                VSB_printf(vsb, "Invalid min-val: %s\n", min);
347 0
                                return (-1);
348
                        }
349 2525160
                }
350 2525160
                if (max != NULL) {
351 1360280
                        p = VNUM_2bytes(max, &rmax, 0);
352 1360280
                        if (p != NULL) {
353 0
                                VSB_printf(vsb, "Invalid max-val: %s\n", max);
354 0
                                return (-1);
355
                        }
356 1360280
                }
357 2525160
                p = VNUM_2bytes(arg, &r, 0);
358 2525160
                if (p != NULL) {
359 80
                        VSB_cat(vsb, "Could not convert to bytes.\n");
360 80
                        VSB_printf(vsb, "%s\n", p);
361 80
                        VSB_cat(vsb, "  Try something like '80k' or '120M'\n");
362 80
                        return (-1);
363
                }
364 2525080
                if ((uintmax_t)((ssize_t)r) != r) {
365 0
                        fmt_bytes(vsb, r);
366 0
                        VSB_cat(vsb, " is too large for this architecture.\n");
367 0
                        return (-1);
368
                }
369 2525080
                if (max != NULL && r > rmax) {
370 40
                        VSB_printf(vsb, "Must be no more than %s\n", max);
371 40
                        VSB_cat(vsb, "\n");
372 40
                        return (-1);
373
                }
374 2525040
                if (min != NULL && r < rmin) {
375 40
                        VSB_printf(vsb, "Must be at least %s\n", min);
376 40
                        return (-1);
377
                }
378 2525000
                *dest = r;
379 4948520
        } else if (arg == JSON_FMT) {
380 2880
                VSB_printf(vsb, "%zd", *dest);
381 2880
        } else {
382 2420640
                fmt_bytes(vsb, *dest);
383
        }
384 4948520
        return (0);
385 4948680
}
386
387
/*--------------------------------------------------------------------*/
388
389
int v_matchproto_(tweak_t)
390 955640
tweak_bytes(struct vsb *vsb, const struct parspec *par, const char *arg)
391
{
392
        volatile ssize_t *dest;
393
394 955640
        dest = par->priv;
395 955640
        return (tweak_generic_bytes(vsb, dest, arg, par->min, par->max));
396
}
397
398
/*--------------------------------------------------------------------*/
399
400
int v_matchproto_(tweak_t)
401 3576360
tweak_bytes_u(struct vsb *vsb, const struct parspec *par, const char *arg)
402
{
403
        volatile unsigned *d1;
404
        volatile ssize_t dest;
405
406 3576360
        d1 = par->priv;
407 3576360
        dest = *d1;
408 3576360
        if (tweak_generic_bytes(vsb, &dest, arg, par->min, par->max))
409 160
                return (-1);
410 3576200
        *d1 = dest;
411 3576200
        return (0);
412 3576360
}
413
414
/*--------------------------------------------------------------------
415
 * vsl_buffer and vsl_reclen have dependencies.
416
 */
417
418
int v_matchproto_(tweak_t)
419 166920
tweak_vsl_buffer(struct vsb *vsb, const struct parspec *par, const char *arg)
420
{
421
        volatile unsigned *d1;
422
        volatile ssize_t dest;
423
424 166920
        d1 = par->priv;
425 166920
        dest = *d1;
426 166920
        if (tweak_generic_bytes(vsb, &dest, arg, par->min, par->max))
427 0
                return (-1);
428 166920
        *d1 = dest;
429 166920
        MCF_ParamConf(MCF_MAXIMUM, "vsl_reclen", "%u", *d1 - 12);
430 166920
        return (0);
431 166920
}
432
433
int v_matchproto_(tweak_t)
434 249760
tweak_vsl_reclen(struct vsb *vsb, const struct parspec *par, const char *arg)
435
{
436
        volatile unsigned *d1;
437
        volatile ssize_t dest;
438
439 249760
        d1 = par->priv;
440 249760
        dest = *d1;
441 249760
        if (tweak_generic_bytes(vsb, &dest, arg, par->min, par->max))
442 0
                return (-1);
443 249760
        *d1 = dest;
444 249760
        MCF_ParamConf(MCF_MINIMUM, "vsl_buffer", "%u", *d1 + 12);
445 249760
        return (0);
446 249760
}
447
448
/*--------------------------------------------------------------------*/
449
450
int v_matchproto_(tweak_t)
451 456920
tweak_string(struct vsb *vsb, const struct parspec *par, const char *arg)
452
{
453 456920
        char **p = TRUST_ME(par->priv);
454
455 456920
        AN(p);
456 456920
        if (arg == NULL) {
457 210240
                VSB_quote(vsb, *p, -1, 0);
458 456920
        } else if (arg == JSON_FMT) {
459 600
                VSB_putc(vsb, '"');
460 600
                VSB_quote(vsb, *p, -1, VSB_QUOTE_JSON);
461 600
                VSB_putc(vsb, '"');
462 600
        } else {
463 246080
                REPLACE(*p, arg);
464
        }
465 456920
        return (0);
466
}
467
468
/*--------------------------------------------------------------------*/
469
470
int v_matchproto_(tweak_t)
471 251720
tweak_poolparam(struct vsb *vsb, const struct parspec *par, const char *arg)
472
{
473
        volatile struct poolparam *pp, px;
474
        struct parspec pt;
475
        char **av;
476 251720
        int retval = 0;
477
478 251720
        pp = par->priv;
479 251720
        if (arg == JSON_FMT) {
480 440
                VSB_cat(vsb, "{\n");
481 440
                VSB_indent(vsb, 8);
482 440
                VSB_printf(vsb, "\"min_pool\": %u,\n", pp->min_pool);
483 440
                VSB_printf(vsb, "\"max_pool\": %u,\n", pp->max_pool);
484 440
                VSB_printf(vsb, "\"max_age\": %g\n", pp->max_age);
485 440
                VSB_indent(vsb, -4);
486 440
                VSB_cat(vsb, "}");
487 251720
        } else if (arg == NULL) {
488 252400
                VSB_printf(vsb, "%u,%u,%g",
489 126200
                    pp->min_pool, pp->max_pool, pp->max_age);
490 126200
        } else {
491 125080
                av = VAV_Parse(arg, NULL, ARGV_COMMA);
492 125080
                do {
493 125080
                        if (av[0] != NULL) {
494 40
                                VSB_printf(vsb, "Parse error: %s", av[0]);
495 40
                                retval = -1;
496 40
                                break;
497
                        }
498 125040
                        if (av[1] == NULL || av[2] == NULL || av[3] == NULL) {
499 40
                                VSB_cat(vsb,
500
                                    "Three fields required:"
501
                                    " min_pool, max_pool and max_age\n");
502 40
                                retval = -1;
503 40
                                break;
504
                        }
505 125000
                        px = *pp;
506 250000
                        retval = tweak_generic_uint(vsb, &px.min_pool, av[1],
507 125000
                            par->min, par->max, par->dyn_min_reason,
508 125000
                            par->dyn_max_reason);
509 125000
                        if (retval)
510 40
                                break;
511 249920
                        retval = tweak_generic_uint(vsb, &px.max_pool, av[2],
512 124960
                            par->min, par->max, par->dyn_min_reason,
513 124960
                            par->dyn_max_reason);
514 124960
                        if (retval)
515 40
                                break;
516 124920
                        pt.priv = &px.max_age;
517 124920
                        pt.min = "0";
518 124920
                        pt.max = "1000000";
519 124920
                        retval = tweak_generic_double(vsb, av[3], &pt,
520
                            parse_decimal, "%.0f");
521 124920
                        if (retval)
522 40
                                break;
523 124880
                        if (px.min_pool > px.max_pool) {
524 40
                                VSB_cat(vsb,
525
                                    "min_pool cannot be larger"
526
                                    " than max_pool\n");
527 40
                                retval = -1;
528 40
                                break;
529
                        }
530 124840
                        *pp = px;
531 124840
                } while (0);
532 125080
                VAV_Free(av);
533
        }
534 251720
        return (retval);
535
}
536
537
/*--------------------------------------------------------------------
538
 * Thread pool tweaks.
539
 *
540
 * The min/max values automatically update the opposites appropriate
541
 * limit, so they don't end up crossing.
542
 */
543
544
int v_matchproto_(tweak_t)
545 288440
tweak_thread_pool_min(struct vsb *vsb, const struct parspec *par,
546
    const char *arg)
547
{
548 288440
        if (tweak_uint(vsb, par, arg))
549 80
                return (-1);
550
551 288360
        MCF_ParamConf(MCF_MINIMUM, "thread_pool_max",
552 288360
            "%u", mgt_param.wthread_min);
553 288360
        MCF_ParamConf(MCF_MAXIMUM, "thread_pool_reserve",
554 288360
            "%u", mgt_param.wthread_min * 950 / 1000);
555 288360
        return (0);
556 288440
}
557
558
int v_matchproto_(tweak_t)
559 84360
tweak_thread_pool_max(struct vsb *vsb, const struct parspec *par,
560
    const char *arg)
561
{
562
563 84360
        if (tweak_uint(vsb, par, arg))
564 80
                return (-1);
565
566 84280
        MCF_ParamConf(MCF_MAXIMUM, "thread_pool_min",
567 84280
            "%u", mgt_param.wthread_max);
568 84280
        return (0);
569 84360
}
570
571
/*--------------------------------------------------------------------
572
 * Tweak storage
573
 */
574
575
int v_matchproto_(tweak_t)
576 83720
tweak_storage(struct vsb *vsb, const struct parspec *par, const char *arg)
577
{
578
        struct stevedore *stv;
579
580
        /* XXX: If we want to remove the MUST_RESTART flag from the
581
         * h2_rxbuf_storage parameter, we could have a mechanism here
582
         * that when the child is running calls out through CLI to change
583
         * the stevedore being used. */
584
585 83720
        if (arg == NULL || arg == JSON_FMT)
586 42160
                return (tweak_string(vsb, par, arg));
587
588 41560
        if (!strcmp(arg, "Transient")) {
589
                /* Always allow setting to the special name
590
                 * "Transient". There will always be a stevedore with this
591
                 * name, but it may not have been configured at the time
592
                 * this is called. */
593 41520
        } else {
594
                /* Only allow setting the value to a known configured
595
                 * stevedore */
596 40
                STV_Foreach(stv) {
597 40
                        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
598 40
                        if (!strcmp(stv->ident, arg))
599 40
                                break;
600
                }
601 40
                if (stv == NULL) {
602 0
                        VSB_printf(vsb, "unknown storage backend '%s'", arg);
603 0
                        return (-1);
604
                }
605
        }
606 41560
        return (tweak_string(vsb, par, arg));
607 83720
}
608
609
/*--------------------------------------------------------------------
610
 * Tweak alias
611
 */
612
613
int v_matchproto_(tweak_t)
614 240
tweak_alias(struct vsb *vsb, const struct parspec *par, const char *arg)
615
{
616
        const struct parspec *orig;
617
        struct parspec alias[1];
618
619 240
        orig = TRUST_ME(par->priv);
620 240
        AN(orig);
621 240
        memcpy(alias, orig, sizeof *orig);
622 240
        alias->name = par->name;
623 240
        alias->priv = TRUST_ME(orig);
624 240
        return (alias->func(vsb, alias, arg));
625
}
626
627
/*--------------------------------------------------------------------
628
 * Tweak bits
629
 */
630
631
enum bit_do {BSET, BCLR, BTST};
632
633
static int
634 6775200
bit(uint8_t *p, unsigned no, enum bit_do act)
635
{
636
        uint8_t b;
637
638 6775200
        p += (no >> 3);
639 6775200
        b = (0x80 >> (no & 7));
640 6775200
        if (act == BSET)
641 796680
                *p |= b;
642 5978520
        else if (act == BCLR)
643 115200
                *p &= ~b;
644 6775200
        return (*p & b);
645
}
646
647
static inline void
648 207720
bit_clear(uint8_t *p, unsigned l)
649
{
650
651 207720
        memset(p, 0, ((size_t)l + 7) >> 3);
652 207720
}
653
654
static inline void
655 80
bit_set(uint8_t *p, unsigned l)
656
{
657
658 80
        memset(p, 255, ((size_t)l + 7) >> 3);
659 80
}
660
661
/*--------------------------------------------------------------------
662
 */
663
664
static int
665 295680
bit_tweak(struct vsb *vsb, uint8_t *p, unsigned l, const char *arg,
666
    const char * const *tags, const char *desc, char sign)
667
{
668
        int i, n;
669
        unsigned j;
670
        char **av;
671
        const char *s;
672
673 295680
        av = VAV_Parse(arg, &n, ARGV_COMMA);
674 295680
        if (av[0] != NULL) {
675 40
                VSB_printf(vsb, "Cannot parse: %s\n", av[0]);
676 40
                VAV_Free(av);
677 40
                return (-1);
678
        }
679 1415320
        for (i = 1; av[i] != NULL; i++) {
680 1119760
                s = av[i];
681 1119760
                if (sign == '+' && !strcmp(s, "none")) {
682 166120
                        bit_clear(p, l);
683 166120
                        continue;
684
                }
685 953640
                if (sign == '+' && !strcmp(s, "all")) {
686 40
                        bit_set(p, l);
687 40
                        continue;
688
                }
689 953600
                if (sign == '-' && !strcmp(s, "all")) {
690 41600
                        bit_clear(p, l);
691 41600
                        continue;
692
                }
693 912000
                if (sign == '-' && !strcmp(s, "none")) {
694 40
                        bit_set(p, l);
695 40
                        continue;
696
                }
697 911960
                if (*s != '-' && *s != '+') {
698 40
                        VSB_printf(vsb, "Missing '+' or '-' (%s)\n", s);
699 40
                        VAV_Free(av);
700 40
                        return (-1);
701
                }
702 46812200
                for (j = 0; j < l; j++) {
703 46812160
                        if (tags[j] != NULL && !strcasecmp(s + 1, tags[j]))
704 911880
                                break;
705 45900280
                }
706 911920
                if (tags[j] == NULL) {
707 40
                        VSB_printf(vsb, "Unknown %s (%s)\n", desc, s);
708 40
                        VAV_Free(av);
709 40
                        return (-1);
710
                }
711 911880
                assert(j < l);
712 911880
                if (s[0] == sign)
713 796680
                        (void)bit(p, j, BSET);
714
                else
715 115200
                        (void)bit(p, j, BCLR);
716 911880
        }
717 295560
        VAV_Free(av);
718 295560
        return (0);
719 295680
}
720
721
722
/*--------------------------------------------------------------------
723
 */
724
725
static int
726 507440
tweak_generic_bits(struct vsb *vsb, const struct parspec *par, const char *arg,
727
    uint8_t *p, unsigned l, const char * const *tags, const char *desc,
728
    char sign)
729
{
730
        unsigned j, all;
731
732 507440
        if (arg != NULL && !strcmp(arg, "default")) {
733
                /* XXX: deprecated in favor of param.reset */
734 0
                return (tweak_generic_bits(vsb, par, par->def, p, l, tags,
735 0
                    desc, sign));
736
        }
737
738 507440
        if (arg != NULL && arg != JSON_FMT)
739 295680
                return (bit_tweak(vsb, p, l, arg, tags, desc, sign));
740
741 211760
        all = 1;
742 572360
        for (j = 0; all && j < l; j++) {
743 360600
                if (tags[j] == NULL)
744 55360
                        continue;
745 305240
                if (!bit(p, j, BTST))
746 211520
                        all = 0;
747 305240
        }
748
749 211760
        if (arg == JSON_FMT)
750 840
                VSB_putc(vsb, '"');
751 211760
        if (all)
752 240
                VSB_cat(vsb, sign == '+' ? "all" : "none");
753
        else
754 211520
                VSB_cat(vsb, sign == '+' ? "none" : "all");
755 12609120
        for (j = 0; !all && j < l; j++) {
756 12397360
                if (tags[j] == NULL)
757 6839280
                        continue;
758 5558080
                if (bit(p, j, BTST))
759 761400
                        VSB_printf(vsb, ",%c%s", sign, tags[j]);
760 5558080
        }
761 211760
        if (arg == JSON_FMT)
762 840
                VSB_putc(vsb, '"');
763 211760
        return (0);
764 507440
}
765
766
/*--------------------------------------------------------------------
767
 * The vsl_mask parameter
768
 */
769
770
static const char * const VSL_tags[256] = {
771
#  define SLTM(foo,flags,sdesc,ldesc) [SLT_##foo] = #foo,
772
#  include "tbl/vsl_tags.h"
773
};
774
775
int v_matchproto_(tweak_t)
776 123280
tweak_vsl_mask(struct vsb *vsb, const struct parspec *par, const char *arg)
777
{
778
779 123280
        return (tweak_generic_bits(vsb, par, arg, mgt_param.vsl_mask,
780
            SLT__Reserved, VSL_tags, "VSL tag", '-'));
781
}
782
783
/*--------------------------------------------------------------------
784
 * The debug parameter
785
 */
786
787
static const char * const debug_tags[] = {
788
#  define DEBUG_BIT(U, l, d) [DBG_##U] = #l,
789
#  include "tbl/debug_bits.h"
790
       NULL
791
};
792
793
int v_matchproto_(tweak_t)
794 126840
tweak_debug(struct vsb *vsb, const struct parspec *par, const char *arg)
795
{
796
797 126840
        return (tweak_generic_bits(vsb, par, arg, mgt_param.debug_bits,
798
            DBG_Reserved, debug_tags, "debug bit", '+'));
799
}
800
801
/*--------------------------------------------------------------------
802
 * The experimental parameter
803
 */
804
805
static const char * const experimental_tags[] = {
806
#  define EXPERIMENTAL_BIT(U, l, d) [EXPERIMENT_##U] = #l,
807
#  include "tbl/experimental_bits.h"
808
       NULL
809
};
810
811
int v_matchproto_(tweak_t)
812 83760
tweak_experimental(struct vsb *vsb, const struct parspec *par, const char *arg)
813
{
814
815 83760
        return (tweak_generic_bits(vsb, par, arg, mgt_param.experimental_bits,
816
            EXPERIMENT_Reserved, experimental_tags, "experimental bit", '+'));
817
}
818
819
/*--------------------------------------------------------------------
820
 * The feature parameter
821
 */
822
823
static const char * const feature_tags[] = {
824
#  define FEATURE_BIT(U, l, d) [FEATURE_##U] = #l,
825
#  include "tbl/feature_bits.h"
826
       NULL
827
};
828
829
int v_matchproto_(tweak_t)
830 88680
tweak_feature(struct vsb *vsb, const struct parspec *par, const char *arg)
831
{
832
833 88680
        return (tweak_generic_bits(vsb, par, arg, mgt_param.feature_bits,
834
            FEATURE_Reserved, feature_tags, "feature bit", '+'));
835
}
836
837
/*--------------------------------------------------------------------
838
 * The vcc_feature parameter
839
 */
840
841
static const char * const vcc_feature_tags[] = {
842
#  define VCC_FEATURE_BIT(U, l, d) [VCC_FEATURE_##U] = #l,
843
#  include "tbl/vcc_feature_bits.h"
844
       NULL
845
};
846
847
int v_matchproto_(tweak_t)
848 84880
tweak_vcc_feature(struct vsb *vsb, const struct parspec *par, const char *arg)
849
{
850
        const struct parspec *orig;
851
        char buf[32];
852
        int val;
853
854 84880
        if (arg != NULL && arg != JSON_FMT &&
855 42600
            strcmp(par->name, "vcc_feature")) {
856 0
                orig = TRUST_ME(par->priv);
857 0
                val = parse_boolean(vsb, arg);
858 0
                if (val < 0)
859 0
                        return (-1);
860 0
                bprintf(buf, "%c%s", val ? '+' : '-',
861
                    par->name + strlen("vcc_"));
862 0
                return (tweak_vcc_feature(vsb, orig, buf));
863
        }
864 84880
        return (tweak_generic_bits(vsb, par, arg, mgt_param.vcc_feature_bits,
865
            VCC_FEATURE_Reserved, vcc_feature_tags, "vcc_feature bit", '+'));
866 84880
}