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 447150
parse_decimal(const char *p, const char **err)
60
{
61
        double v;
62
63 447150
        v = SF_Parse_Decimal(&p, 0, err);
64 447150
        if (errno == 0 && *p != '\0') {
65 25
                errno = EINVAL;
66 25
                *err = "Invalid number";
67 25
        }
68 447150
        return (v);
69
}
70
71
static int
72 4209825
tweak_generic_double(struct vsb *vsb, const char *arg, const struct parspec *pp,
73
    parse_double_f parse, const char *fmt)
74
{
75 4209825
        volatile double u, minv = VRT_DECIMAL_MIN, maxv = VRT_DECIMAL_MAX;
76 4209825
        volatile double *dest = pp->priv;
77
        const char *err;
78
79 4209825
        if (arg != NULL && arg != JSON_FMT) {
80 2135975
                if (pp->min != NULL) {
81 2135975
                        minv = parse(pp->min, &err);
82 2135975
                        if (errno) {
83 0
                                VSB_printf(vsb, "Min: %s (%s)\n", err, pp->min);
84 0
                                return (-1);
85
                        }
86 2135975
                }
87 2135975
                if (pp->max != NULL) {
88 595475
                        maxv = parse(pp->max, &err);
89 595475
                        if (errno) {
90 0
                                VSB_printf(vsb, "Max: %s (%s)\n", err, pp->max);
91 0
                                return (-1);
92
                        }
93 595475
                }
94
95 2135975
                u = parse(arg, &err);
96 2135975
                if (errno) {
97 100
                        VSB_printf(vsb, "%s (%s)\n", err, arg);
98 100
                        return (-1);
99
                }
100 2135875
                if (u < minv) {
101 50
                        VSB_printf(vsb,
102 25
                            "Must be greater or equal to %s\n", pp->min);
103 25
                        return (-1);
104
                }
105 2135850
                if (u > maxv) {
106 50
                        VSB_printf(vsb,
107 25
                            "Must be less than or equal to %s\n", pp->max);
108 25
                        return (-1);
109
                }
110 2135825
                *dest = u;
111 2135825
        } else {
112 2073850
                VSB_printf(vsb, fmt, *dest);
113
        }
114 4209675
        return (0);
115 4209825
}
116
117
/*--------------------------------------------------------------------*/
118
119
static double
120 4420275
parse_duration(const char *p, const char **err)
121
{
122
        double v, r;
123
124 4420275
        v = SF_Parse_Decimal(&p, 0, err);
125 4420275
        if (*p == '\0')
126 4320525
                return (v);
127
128 99750
        r = VNUM_duration_unit(v, p, NULL);
129 99750
        if (isnan(r)) {
130 50
                errno = EINVAL;
131 50
                *err = "Invalid duration unit";
132 50
        }
133
134 99750
        return (r);
135 4420275
}
136
137
int v_matchproto_(tweak_t)
138 3985975
tweak_timeout(struct vsb *vsb, const struct parspec *par, const char *arg)
139
{
140
141 3985975
        return (tweak_generic_double(vsb, arg, par, parse_duration, "%.3f"));
142
}
143
144
/*--------------------------------------------------------------------*/
145
146
int v_matchproto_(tweak_t)
147 149225
tweak_double(struct vsb *vsb, const struct parspec *par, const char *arg)
148
{
149
150 149225
        return (tweak_generic_double(vsb, arg, par, parse_decimal, "%g"));
151
}
152
153
/*--------------------------------------------------------------------*/
154
155
static int
156 294125
parse_boolean(struct vsb *vsb, const char *arg)
157
{
158
159 294125
        if (!strcasecmp(arg, "off"))
160 95100
                return (0);
161 199025
        if (!strcasecmp(arg, "disable"))
162 25
                return (0);
163 199000
        if (!strcasecmp(arg, "no"))
164 25
                return (0);
165 198975
        if (!strcasecmp(arg, "false"))
166 100
                return (0);
167 198875
        if (!strcasecmp(arg, "on"))
168 198525
                return (1);
169 350
        if (!strcasecmp(arg, "enable"))
170 25
                return (1);
171 325
        if (!strcasecmp(arg, "yes"))
172 25
                return (1);
173 300
        if (!strcasecmp(arg, "true"))
174 275
                return (1);
175
176 25
        VSB_cat(vsb, "use \"on\" or \"off\"\n");
177 25
        return (-1);
178 294125
}
179
180
int v_matchproto_(tweak_t)
181 546125
tweak_boolean(struct vsb *vsb, const struct parspec *par, const char *arg)
182
{
183
        volatile unsigned *dest;
184
        int val;
185
186 546125
        dest = par->priv;
187 546125
        if (arg != NULL && arg != JSON_FMT) {
188 294125
                val = parse_boolean(vsb, arg);
189 294125
                if (val < 0)
190 25
                        return (-1);
191 294100
                *dest = val;
192 546100
        } else if (arg == JSON_FMT) {
193 750
                VSB_printf(vsb, "%s", *dest ? "true" : "false");
194 750
        } else {
195 251250
                VSB_printf(vsb, "%s", *dest ? "on" : "off");
196
        }
197 546100
        return (0);
198 546125
}
199
200
/*--------------------------------------------------------------------*/
201
202
static int
203 3411150
tweak_generic_uint(struct vsb *vsb, volatile unsigned *dest, const char *arg,
204
    const char *min, const char *max,
205
    const char *min_reason, const char *max_reason)
206
{
207 3411150
        unsigned u, minv = 0, maxv = 0;
208
        char *p;
209
210 3411150
        if (arg != NULL && arg != JSON_FMT) {
211 1787550
                if (min != NULL) {
212 1563600
                        p = NULL;
213 1563600
                        minv = strtoul(min, &p, 0);
214 1563600
                        if (*arg == '\0' || *p != '\0') {
215 0
                                VSB_printf(vsb, "Illegal Min: %s\n", min);
216 0
                                return (-1);
217
                        }
218 1563600
                }
219 1787550
                if (max != NULL) {
220 669575
                        p = NULL;
221 669575
                        maxv = strtoul(max, &p, 0);
222 669575
                        if (*arg == '\0' || *p != '\0') {
223 0
                                VSB_printf(vsb, "Illegal Max: %s\n", max);
224 0
                                return (-1);
225
                        }
226 669575
                }
227 1787550
                p = NULL;
228 1787550
                if (!strcasecmp(arg, "unlimited"))
229 25
                        u = UINT_MAX;
230
                else {
231 1787525
                        u = strtoul(arg, &p, 0);
232 1787525
                        if (*arg == '\0' || *p != '\0') {
233 50
                                VSB_printf(vsb, "Not a number (%s)\n", arg);
234 50
                                return (-1);
235
                        }
236
                }
237 1787500
                if (min != NULL && u < minv) {
238 75
                        VSB_printf(vsb, "Must be at least %s", min);
239 75
                        if (min_reason != NULL)
240 50
                                VSB_printf(vsb, " (%s)", min_reason);
241 75
                        VSB_putc(vsb, '\n');
242 75
                        return (-1);
243
                }
244 1787425
                if (max != NULL && u > maxv) {
245 150
                        VSB_printf(vsb, "Must be no more than %s", max);
246 150
                        if (max_reason != NULL)
247 125
                                VSB_printf(vsb, " (%s)", max_reason);
248 150
                        VSB_putc(vsb, '\n');
249 150
                        return (-1);
250
                }
251 1787275
                *dest = u;
252 3410875
        } else if (*dest == UINT_MAX && arg != JSON_FMT) {
253 125
                VSB_cat(vsb, "unlimited");
254 125
        } else {
255 1623475
                VSB_printf(vsb, "%u", *dest);
256
        }
257 3410875
        return (0);
258 3411150
}
259
260
/*--------------------------------------------------------------------*/
261
262
int v_matchproto_(tweak_t)
263 3261825
tweak_uint(struct vsb *vsb, const struct parspec *par, const char *arg)
264
{
265
        volatile unsigned *dest;
266
267 3261825
        dest = par->priv;
268 6523650
        return (tweak_generic_uint(vsb, dest, arg, par->min, par->max,
269 3261825
            par->dyn_min_reason, par->dyn_max_reason));
270
}
271
272
/*--------------------------------------------------------------------*/
273
274
static void
275 1346675
fmt_bytes(struct vsb *vsb, uintmax_t t)
276
{
277
        const char *p;
278
279 1346675
        if (t == 0 || t & 0xff) {
280 472225
                VSB_printf(vsb, "%jub", t);
281 472225
                return;
282
        }
283 1198475
        for (p = "kMGTPEZY"; *p; p++) {
284 1198475
                if (t & 0x300) {
285 124650
                        VSB_printf(vsb, "%.2f%c", t / 1024.0, *p);
286 124650
                        return;
287
                }
288 1073825
                t /= 1024;
289 1073825
                if (t & 0x0ff) {
290 749800
                        VSB_printf(vsb, "%ju%c", t, *p);
291 749800
                        return;
292
                }
293 324025
        }
294 0
        VSB_cat(vsb, "(bogus number)");
295 1346675
}
296
297
static int
298 2757300
tweak_generic_bytes(struct vsb *vsb, volatile ssize_t *dest, const char *arg,
299
    const char *min, const char *max)
300
{
301 2757300
        uintmax_t r, rmin = 0, rmax = 0;
302
        const char *p;
303
304 2757300
        if (arg != NULL && arg != JSON_FMT) {
305 1408900
                if (min != NULL) {
306 1408900
                        p = VNUM_2bytes(min, &rmin, 0);
307 1408900
                        if (p != NULL) {
308 0
                                VSB_printf(vsb, "Invalid min-val: %s\n", min);
309 0
                                return (-1);
310
                        }
311 1408900
                }
312 1408900
                if (max != NULL) {
313 663800
                        p = VNUM_2bytes(max, &rmax, 0);
314 663800
                        if (p != NULL) {
315 0
                                VSB_printf(vsb, "Invalid max-val: %s\n", max);
316 0
                                return (-1);
317
                        }
318 663800
                }
319 1408900
                p = VNUM_2bytes(arg, &r, 0);
320 1408900
                if (p != NULL) {
321 50
                        VSB_cat(vsb, "Could not convert to bytes.\n");
322 50
                        VSB_printf(vsb, "%s\n", p);
323 50
                        VSB_cat(vsb, "  Try something like '80k' or '120M'\n");
324 50
                        return (-1);
325
                }
326 1408850
                if ((uintmax_t)((ssize_t)r) != r) {
327 0
                        fmt_bytes(vsb, r);
328 0
                        VSB_cat(vsb, " is too large for this architecture.\n");
329 0
                        return (-1);
330
                }
331 1408850
                if (max != NULL && r > rmax) {
332 25
                        VSB_printf(vsb, "Must be no more than %s\n", max);
333 25
                        VSB_cat(vsb, "\n");
334 25
                        return (-1);
335
                }
336 1408825
                if (min != NULL && r < rmin) {
337 25
                        VSB_printf(vsb, "Must be at least %s\n", min);
338 25
                        return (-1);
339
                }
340 1408800
                *dest = r;
341 2757200
        } else if (arg == JSON_FMT) {
342 1725
                VSB_printf(vsb, "%zd", *dest);
343 1725
        } else {
344 1346675
                fmt_bytes(vsb, *dest);
345
        }
346 2757200
        return (0);
347 2757300
}
348
349
/*--------------------------------------------------------------------*/
350
351
int v_matchproto_(tweak_t)
352 570725
tweak_bytes(struct vsb *vsb, const struct parspec *par, const char *arg)
353
{
354
        volatile ssize_t *dest;
355
356 570725
        dest = par->priv;
357 570725
        return (tweak_generic_bytes(vsb, dest, arg, par->min, par->max));
358
}
359
360
/*--------------------------------------------------------------------*/
361
362
int v_matchproto_(tweak_t)
363 1937650
tweak_bytes_u(struct vsb *vsb, const struct parspec *par, const char *arg)
364
{
365
        volatile unsigned *d1;
366
        volatile ssize_t dest;
367
368 1937650
        d1 = par->priv;
369 1937650
        dest = *d1;
370 1937650
        if (tweak_generic_bytes(vsb, &dest, arg, par->min, par->max))
371 100
                return (-1);
372 1937550
        *d1 = dest;
373 1937550
        return (0);
374 1937650
}
375
376
/*--------------------------------------------------------------------
377
 * vsl_buffer and vsl_reclen have dependencies.
378
 */
379
380
int v_matchproto_(tweak_t)
381 99725
tweak_vsl_buffer(struct vsb *vsb, const struct parspec *par, const char *arg)
382
{
383
        volatile unsigned *d1;
384
        volatile ssize_t dest;
385
386 99725
        d1 = par->priv;
387 99725
        dest = *d1;
388 99725
        if (tweak_generic_bytes(vsb, &dest, arg, par->min, par->max))
389 0
                return (-1);
390 99725
        *d1 = dest;
391 99725
        MCF_ParamConf(MCF_MAXIMUM, "vsl_reclen", "%u", *d1 - 12);
392 99725
        return (0);
393 99725
}
394
395
int v_matchproto_(tweak_t)
396 149200
tweak_vsl_reclen(struct vsb *vsb, const struct parspec *par, const char *arg)
397
{
398
        volatile unsigned *d1;
399
        volatile ssize_t dest;
400
401 149200
        d1 = par->priv;
402 149200
        dest = *d1;
403 149200
        if (tweak_generic_bytes(vsb, &dest, arg, par->min, par->max))
404 0
                return (-1);
405 149200
        *d1 = dest;
406 149200
        MCF_ParamConf(MCF_MINIMUM, "vsl_buffer", "%u", *d1 + 12);
407 149200
        return (0);
408 149200
}
409
410
/*--------------------------------------------------------------------*/
411
412
int v_matchproto_(tweak_t)
413 273075
tweak_string(struct vsb *vsb, const struct parspec *par, const char *arg)
414
{
415 273075
        char **p = TRUST_ME(par->priv);
416
417 273075
        AN(p);
418 273075
        if (arg == NULL) {
419 125650
                VSB_quote(vsb, *p, -1, 0);
420 273075
        } else if (arg == JSON_FMT) {
421 375
                VSB_putc(vsb, '"');
422 375
                VSB_quote(vsb, *p, -1, VSB_QUOTE_JSON);
423 375
                VSB_putc(vsb, '"');
424 375
        } else {
425 147050
                REPLACE(*p, arg);
426
        }
427 273075
        return (0);
428
}
429
430
/*--------------------------------------------------------------------*/
431
432
int v_matchproto_(tweak_t)
433 150425
tweak_poolparam(struct vsb *vsb, const struct parspec *par, const char *arg)
434
{
435
        volatile struct poolparam *pp, px;
436
        struct parspec pt;
437
        char **av;
438 150425
        int retval = 0;
439
440 150425
        pp = par->priv;
441 150425
        if (arg == JSON_FMT) {
442 275
                VSB_cat(vsb, "{\n");
443 275
                VSB_indent(vsb, 8);
444 275
                VSB_printf(vsb, "\"min_pool\": %u,\n", pp->min_pool);
445 275
                VSB_printf(vsb, "\"max_pool\": %u,\n", pp->max_pool);
446 275
                VSB_printf(vsb, "\"max_age\": %g\n", pp->max_age);
447 275
                VSB_indent(vsb, -4);
448 275
                VSB_cat(vsb, "}");
449 150425
        } else if (arg == NULL) {
450 150850
                VSB_printf(vsb, "%u,%u,%g",
451 75425
                    pp->min_pool, pp->max_pool, pp->max_age);
452 75425
        } else {
453 74725
                av = VAV_Parse(arg, NULL, ARGV_COMMA);
454 74725
                do {
455 74725
                        if (av[0] != NULL) {
456 25
                                VSB_printf(vsb, "Parse error: %s", av[0]);
457 25
                                retval = -1;
458 25
                                break;
459
                        }
460 74700
                        if (av[1] == NULL || av[2] == NULL || av[3] == NULL) {
461 25
                                VSB_cat(vsb,
462
                                    "Three fields required:"
463
                                    " min_pool, max_pool and max_age\n");
464 25
                                retval = -1;
465 25
                                break;
466
                        }
467 74675
                        px = *pp;
468 149350
                        retval = tweak_generic_uint(vsb, &px.min_pool, av[1],
469 74675
                            par->min, par->max, par->dyn_min_reason,
470 74675
                            par->dyn_max_reason);
471 74675
                        if (retval)
472 25
                                break;
473 149300
                        retval = tweak_generic_uint(vsb, &px.max_pool, av[2],
474 74650
                            par->min, par->max, par->dyn_min_reason,
475 74650
                            par->dyn_max_reason);
476 74650
                        if (retval)
477 25
                                break;
478 74625
                        pt.priv = &px.max_age;
479 74625
                        pt.min = "0";
480 74625
                        pt.max = "1000000";
481 74625
                        retval = tweak_generic_double(vsb, av[3], &pt,
482
                            parse_decimal, "%.0f");
483 74625
                        if (retval)
484 25
                                break;
485 74600
                        if (px.min_pool > px.max_pool) {
486 25
                                VSB_cat(vsb,
487
                                    "min_pool cannot be larger"
488
                                    " than max_pool\n");
489 25
                                retval = -1;
490 25
                                break;
491
                        }
492 74575
                        *pp = px;
493 74575
                } while (0);
494 74725
                VAV_Free(av);
495
        }
496 150425
        return (retval);
497
}
498
499
/*--------------------------------------------------------------------
500
 * Thread pool tweaks.
501
 *
502
 * The min/max values automatically update the opposites appropriate
503
 * limit, so they don't end up crossing.
504
 */
505
506
int v_matchproto_(tweak_t)
507 172375
tweak_thread_pool_min(struct vsb *vsb, const struct parspec *par,
508
    const char *arg)
509
{
510 172375
        if (tweak_uint(vsb, par, arg))
511 50
                return (-1);
512
513 172325
        MCF_ParamConf(MCF_MINIMUM, "thread_pool_max",
514 172325
            "%u", mgt_param.wthread_min);
515 172325
        MCF_ParamConf(MCF_MAXIMUM, "thread_pool_reserve",
516 172325
            "%u", mgt_param.wthread_min * 950 / 1000);
517 172325
        return (0);
518 172375
}
519
520
int v_matchproto_(tweak_t)
521 50425
tweak_thread_pool_max(struct vsb *vsb, const struct parspec *par,
522
    const char *arg)
523
{
524
525 50425
        if (tweak_uint(vsb, par, arg))
526 50
                return (-1);
527
528 50375
        MCF_ParamConf(MCF_MAXIMUM, "thread_pool_min",
529 50375
            "%u", mgt_param.wthread_max);
530 50375
        return (0);
531 50425
}
532
533
/*--------------------------------------------------------------------
534
 * Tweak storage
535
 */
536
537
int v_matchproto_(tweak_t)
538 50025
tweak_storage(struct vsb *vsb, const struct parspec *par, const char *arg)
539
{
540
        struct stevedore *stv;
541
542
        /* XXX: If we want to remove the MUST_RESTART flag from the
543
         * h2_rxbuf_storage parameter, we could have a mechanism here
544
         * that when the child is running calls out through CLI to change
545
         * the stevedore being used. */
546
547 50025
        if (arg == NULL || arg == JSON_FMT)
548 25200
                return (tweak_string(vsb, par, arg));
549
550 24825
        if (!strcmp(arg, "Transient")) {
551
                /* Always allow setting to the special name
552
                 * "Transient". There will always be a stevedore with this
553
                 * name, but it may not have been configured at the time
554
                 * this is called. */
555 24800
        } else {
556
                /* Only allow setting the value to a known configured
557
                 * stevedore */
558 25
                STV_Foreach(stv) {
559 25
                        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
560 25
                        if (!strcmp(stv->ident, arg))
561 25
                                break;
562
                }
563 25
                if (stv == NULL) {
564 0
                        VSB_printf(vsb, "unknown storage backend '%s'", arg);
565 0
                        return (-1);
566
                }
567
        }
568 24825
        return (tweak_string(vsb, par, arg));
569 50025
}
570
571
/*--------------------------------------------------------------------
572
 * Tweak alias
573
 */
574
575
int v_matchproto_(tweak_t)
576 150
tweak_alias(struct vsb *vsb, const struct parspec *par, const char *arg)
577
{
578
        const struct parspec *orig;
579
        struct parspec alias[1];
580
581 150
        orig = TRUST_ME(par->priv);
582 150
        AN(orig);
583 150
        memcpy(alias, orig, sizeof *orig);
584 150
        alias->name = par->name;
585 150
        alias->priv = TRUST_ME(orig);
586 150
        return (alias->func(vsb, alias, arg));
587
}
588
589
/*--------------------------------------------------------------------
590
 * Tweak bits
591
 */
592
593
enum bit_do {BSET, BCLR, BTST};
594
595
static int
596 7958125
bit(uint8_t *p, unsigned no, enum bit_do act)
597
{
598
        uint8_t b;
599
600 7958125
        p += (no >> 3);
601 7958125
        b = (0x80 >> (no & 7));
602 7958125
        if (act == BSET)
603 475900
                *p |= b;
604 7482225
        else if (act == BCLR)
605 68925
                *p &= ~b;
606 7958125
        return (*p & b);
607
}
608
609
static inline void
610 124075
bit_clear(uint8_t *p, unsigned l)
611
{
612
613 124075
        memset(p, 0, ((size_t)l + 7) >> 3);
614 124075
}
615
616
/*--------------------------------------------------------------------
617
 */
618
619
static int
620 176625
bit_tweak(struct vsb *vsb, uint8_t *p, unsigned l, const char *arg,
621
    const char * const *tags, const char *desc, char sign)
622
{
623
        int i, n;
624
        unsigned j;
625
        char **av;
626
        const char *s;
627
628 176625
        av = VAV_Parse(arg, &n, ARGV_COMMA);
629 176625
        if (av[0] != NULL) {
630 25
                VSB_printf(vsb, "Cannot parse: %s\n", av[0]);
631 25
                VAV_Free(av);
632 25
                return (-1);
633
        }
634 845500
        for (i = 1; av[i] != NULL; i++) {
635 668950
                s = av[i];
636 668950
                if (sign == '+' && !strcmp(s, "none")) {
637 99225
                        bit_clear(p, l);
638 99225
                        continue;
639
                }
640 569725
                if (sign == '-' && !strcmp(s, "all")) {
641 24850
                        bit_clear(p, l);
642 24850
                        continue;
643
                }
644 544875
                if (*s != '-' && *s != '+') {
645 25
                        VSB_printf(vsb, "Missing '+' or '-' (%s)\n", s);
646 25
                        VAV_Free(av);
647 25
                        return (-1);
648
                }
649 27966275
                for (j = 0; j < l; j++) {
650 27966250
                        if (tags[j] != NULL && !strcasecmp(s + 1, tags[j]))
651 544825
                                break;
652 27421425
                }
653 544850
                if (tags[j] == NULL) {
654 25
                        VSB_printf(vsb, "Unknown %s (%s)\n", desc, s);
655 25
                        VAV_Free(av);
656 25
                        return (-1);
657
                }
658 544825
                assert(j < l);
659 544825
                if (s[0] == sign)
660 475900
                        (void)bit(p, j, BSET);
661
                else
662 68925
                        (void)bit(p, j, BCLR);
663 544825
        }
664 176550
        VAV_Free(av);
665 176550
        return (0);
666 176625
}
667
668
669
/*--------------------------------------------------------------------
670
 */
671
672
static int
673 303125
tweak_generic_bits(struct vsb *vsb, const struct parspec *par, const char *arg,
674
    uint8_t *p, unsigned l, const char * const *tags, const char *desc,
675
    char sign)
676
{
677
        unsigned j;
678
679 303125
        if (arg != NULL && !strcmp(arg, "default")) {
680
                /* XXX: deprecated in favor of param.reset */
681 0
                return (tweak_generic_bits(vsb, par, par->def, p, l, tags,
682 0
                    desc, sign));
683
        }
684
685 303125
        if (arg != NULL && arg != JSON_FMT)
686 176625
                return (bit_tweak(vsb, p, l, arg, tags, desc, sign));
687
688 126500
        if (arg == JSON_FMT)
689 475
                VSB_putc(vsb, '"');
690 126500
        VSB_cat(vsb, sign == '+' ? "none" : "all");
691 7539800
        for (j = 0; j < l; j++) {
692 7413300
                if (bit(p, j, BTST))
693 455200
                        VSB_printf(vsb, ",%c%s", sign, tags[j]);
694 7413300
        }
695 126500
        if (arg == JSON_FMT)
696 475
                VSB_putc(vsb, '"');
697 126500
        return (0);
698 303125
}
699
700
/*--------------------------------------------------------------------
701
 * The vsl_mask parameter
702
 */
703
704
static const char * const VSL_tags[256] = {
705
#  define SLTM(foo,flags,sdesc,ldesc) [SLT_##foo] = #foo,
706
#  include "tbl/vsl_tags.h"
707
};
708
709
int v_matchproto_(tweak_t)
710 73600
tweak_vsl_mask(struct vsb *vsb, const struct parspec *par, const char *arg)
711
{
712
713 73600
        return (tweak_generic_bits(vsb, par, arg, mgt_param.vsl_mask,
714
            SLT__Reserved, VSL_tags, "VSL tag", '-'));
715
}
716
717
/*--------------------------------------------------------------------
718
 * The debug parameter
719
 */
720
721
static const char * const debug_tags[] = {
722
#  define DEBUG_BIT(U, l, d) [DBG_##U] = #l,
723
#  include "tbl/debug_bits.h"
724
       NULL
725
};
726
727
int v_matchproto_(tweak_t)
728 75900
tweak_debug(struct vsb *vsb, const struct parspec *par, const char *arg)
729
{
730
731 75900
        return (tweak_generic_bits(vsb, par, arg, mgt_param.debug_bits,
732
            DBG_Reserved, debug_tags, "debug bit", '+'));
733
}
734
735
/*--------------------------------------------------------------------
736
 * The experimental parameter
737
 */
738
739
static const char * const experimental_tags[] = {
740
#  define EXPERIMENTAL_BIT(U, l, d) [EXPERIMENT_##U] = #l,
741
#  include "tbl/experimental_bits.h"
742
       NULL
743
};
744
745
int v_matchproto_(tweak_t)
746 50050
tweak_experimental(struct vsb *vsb, const struct parspec *par, const char *arg)
747
{
748
749 50050
        return (tweak_generic_bits(vsb, par, arg, mgt_param.experimental_bits,
750
            EXPERIMENT_Reserved, experimental_tags, "experimental bit", '+'));
751
}
752
753
/*--------------------------------------------------------------------
754
 * The feature parameter
755
 */
756
757
static const char * const feature_tags[] = {
758
#  define FEATURE_BIT(U, l, d) [FEATURE_##U] = #l,
759
#  include "tbl/feature_bits.h"
760
       NULL
761
};
762
763
int v_matchproto_(tweak_t)
764 52825
tweak_feature(struct vsb *vsb, const struct parspec *par, const char *arg)
765
{
766
767 52825
        return (tweak_generic_bits(vsb, par, arg, mgt_param.feature_bits,
768
            FEATURE_Reserved, feature_tags, "feature bit", '+'));
769
}
770
771
/*--------------------------------------------------------------------
772
 * The vcc_feature parameter
773
 */
774
775
static const char * const vcc_feature_tags[] = {
776
#  define VCC_FEATURE_BIT(U, l, d) [VCC_FEATURE_##U] = #l,
777
#  include "tbl/vcc_feature_bits.h"
778
       NULL
779
};
780
781
int v_matchproto_(tweak_t)
782 50750
tweak_vcc_feature(struct vsb *vsb, const struct parspec *par, const char *arg)
783
{
784
        const struct parspec *orig;
785
        char buf[32];
786
        int val;
787
788 50750
        if (arg != NULL && arg != JSON_FMT &&
789 25475
            strcmp(par->name, "vcc_feature")) {
790 0
                orig = TRUST_ME(par->priv);
791 0
                val = parse_boolean(vsb, arg);
792 0
                if (val < 0)
793 0
                        return (-1);
794 0
                bprintf(buf, "%c%s", val ? '+' : '-',
795
                    par->name + strlen("vcc_"));
796 0
                return (tweak_vcc_feature(vsb, orig, buf));
797
        }
798 50750
        return (tweak_generic_bits(vsb, par, arg, mgt_param.vcc_feature_bits,
799
            VCC_FEATURE_Reserved, vcc_feature_tags, "vcc_feature bit", '+'));
800 50750
}