varnish-cache/bin/varnishd/mgt/mgt_param.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
31
#include "config.h"
32
33
#include <ctype.h>
34
#include <stdarg.h>
35
#include <stdio.h>
36
#include <stdlib.h>
37
#include <string.h>
38
#include <unistd.h>
39
40
#include "mgt/mgt.h"
41
#include "common/heritage.h"
42
43
#include "mgt/mgt_param.h"
44
#include "vav.h"
45
#include "vcli_serve.h"
46
47
struct plist {
48
        unsigned                        magic;
49
#define PLIST_MAGIC                     0xbfc3ea16
50
        VTAILQ_ENTRY(plist)             list;
51
        struct parspec                  *spec;
52
};
53
54
static VTAILQ_HEAD(, plist)             phead = VTAILQ_HEAD_INITIALIZER(phead);
55
56
struct params mgt_param;
57
static const int margin1 = 8;
58
static int margin2 = 0;
59
static const int wrap_at = 72;
60
static const int tab0 = 3;
61
62
/*--------------------------------------------------------------------*/
63
64
static const char OBJ_STICKY_TEXT[] =
65
        "\n\n"
66
        "NB: This parameter is evaluated only when objects are created. "
67
        "To change it for all objects, restart or ban everything.";
68
69
static const char DELAYED_EFFECT_TEXT[] =
70
        "\n\n"
71
        "NB: This parameter may take quite some time to take (full) effect.";
72
73
static const char MUST_RESTART_TEXT[] =
74
        "\n\n"
75
        "NB: This parameter will not take any effect until the "
76
        "child process has been restarted.";
77
78
static const char MUST_RELOAD_TEXT[] =
79
        "\n\n"
80
        "NB: This parameter will not take any effect until the "
81
        "VCL programs have been reloaded.";
82
83
static const char EXPERIMENTAL_TEXT[] =
84
        "\n\n"
85
        "NB: We do not know yet if it is a good idea to change "
86
        "this parameter, or if the default value is even sensible. "
87
        "Caution is advised, and feedback is most welcome.";
88
89
static const char WIZARD_TEXT[] =
90
        "\n\n"
91
        "NB: Do not change this parameter, unless a developer tell "
92
        "you to do so.";
93
94
static const char PROTECTED_TEXT[] =
95
        "\n\n"
96
        "NB: This parameter is protected and can not be changed.";
97
98
static const char ONLY_ROOT_TEXT[] =
99
        "\n\n"
100
        "NB: This parameter only works if varnishd is run as root.";
101
102
static const char NOT_IMPLEMENTED_TEXT[] =
103
        "\n\n"
104
        "NB: This parameter depends on a feature which is not available"
105
        " on this platform.";
106
107
static const char PLATFORM_DEPENDENT_TEXT[] =
108
        "\n\n"
109
        "NB: This parameter depends on a feature which is not available"
110
        " on all platforms.";
111
112
static const char BUILD_OPTIONS_TEXT[] =
113
        "\n\n"
114
        "NB: The actual default value for this parameter depends on the"
115
        " Varnish build environment and options.";
116
117
/*--------------------------------------------------------------------*/
118
119
static struct parspec *
120 1113100
mcf_findpar(const char *name)
121
{
122
        struct plist *pl;
123
124 1113100
        AN(name);
125 99251350
        VTAILQ_FOREACH(pl, &phead, list)
126 99251250
                if (!strcmp(pl->spec->name, name))
127 1113000
                        return (pl->spec);
128 100
        return (NULL);
129 1113100
}
130
131
static void
132 2901600
mcf_addpar(struct parspec *ps)
133
{
134
        struct plist *pl, *pl2;
135
        int i;
136
137 2901600
        ALLOC_OBJ(pl, PLIST_MAGIC);
138 2901600
        AN(pl);
139 2901600
        pl->spec = ps;
140 131539200
        VTAILQ_FOREACH(pl2, &phead, list) {
141 130894400
                i = strcmp(pl2->spec->name, pl->spec->name);
142 130894400
                if (i == 0) {
143 0
                        fprintf(stderr, "Duplicate param: %s\n", ps->name);
144 0
                        exit(4);
145 130894400
                } else if (i > 0) {
146 2256800
                        VTAILQ_INSERT_BEFORE(pl2, pl, list);
147 2256800
                        return;
148
                }
149 128637600
        }
150 644800
        VTAILQ_INSERT_TAIL(&phead, pl, list);
151 2901600
}
152
153
/*--------------------------------------------------------------------
154
 * Wrap the text nicely.
155
 * Lines are allowed to contain two TABS and we render that as a table
156
 * taking the width of the first column into account.
157
 */
158
159
static void
160 57200
mcf_wrap_line(struct cli *cli, const char *b, const char *e, int tabs, int m0)
161
{
162 57200
        int n, hadtabs = 0;
163
        const char *w;
164
165 57200
        n = m0;
166 57200
        VCLI_Out(cli, "%*s", n, "");
167
168 847625
        while (b < e) {
169 818725
                if (!isspace(*b)) {
170 400725
                        VCLI_Out(cli, "%c", *b);
171 400725
                        b++;
172 400725
                        n++;
173 818725
                } else if (*b == '\t') {
174 12350
                        assert(tabs);
175 12350
                        assert(hadtabs < 2);
176 12350
                        do {
177 97550
                                VCLI_Out(cli, " ");
178 97550
                                n++;
179 97550
                        } while ((n % tabs) != (m0 + tab0) % tabs);
180 12350
                        b++;
181 12350
                        hadtabs++;
182 12350
                } else {
183 405650
                        assert (*b == ' ');
184 2420850
                        for (w = b + 1; w < e; w++)
185 2391950
                                if (isspace(*w))
186 376750
                                        break;
187 405650
                        if (n + (w - b) < wrap_at) {
188 377350
                                VCLI_Out(cli, "%.*s", (int)(w - b), b);
189 377350
                                n += (w - b);
190 377350
                                b = w;
191 377350
                        } else {
192 28300
                                assert(hadtabs == 0 || hadtabs == 2);
193 28300
                                VCLI_Out(cli, "\n");
194 56600
                                mcf_wrap_line(cli, b + 1, e, 0,
195 28300
                                    hadtabs ? m0 + tab0 + tabs : m0);
196 28300
                                return;
197
                        }
198
                }
199
        }
200 28900
        assert(b == e);
201 57200
}
202
203
static void
204 13975
mcf_wrap(struct cli *cli, const char *text)
205
{
206
        const char *p, *q, *r;
207 13975
        int tw = 0;
208
209 13975
        if (strchr(text, '\t') != NULL) {
210 6975
                for (p = text; *p != '\0'; ) {
211 6975
                        q = strstr(p, "\n\t");
212 6975
                        if (q == NULL)
213 800
                                break;
214 6175
                        q += 2;
215 6175
                        r = strchr(q, '\t');
216 6175
                        if (r == NULL) {
217 0
                                fprintf(stderr,
218 0
                                    "LINE with just one TAB: <%s>\n", text);
219 0
                                exit(4);
220
                        }
221 6175
                        if (r - q > tw)
222 2200
                                tw = r - q;
223 6175
                        p = q;
224
                }
225 800
                tw += 2;
226 800
                if (tw < 20)
227 675
                        tw = 20;
228 800
        }
229
230 72150
        for (p = text; *p != '\0'; ) {
231 58175
                if (*p == '\n') {
232 29275
                        VCLI_Out(cli, "\n");
233 29275
                        p++;
234 29275
                        continue;
235
                }
236 28900
                q = strchr(p, '\n');
237 28900
                if (q == NULL)
238 13975
                        q = strchr(p, '\0');
239 28900
                mcf_wrap_line(cli, p, q, tw, margin1);
240 28900
                p = q;
241
        }
242 13975
}
243
244
/*--------------------------------------------------------------------*/
245
246
static void v_matchproto_(cli_func_t)
247 825
mcf_param_show(struct cli *cli, const char * const *av, void *priv)
248
{
249
        struct plist *pl;
250
        const struct parspec *pp, *pa;
251 825
        int n, lfmt = 0, chg = 0;
252
        struct vsb *vsb;
253 825
        const char *show = NULL;
254
255 825
        (void)priv;
256
257 1500
        for (n = 2; av[n] != NULL; n++) {
258 700
                if (strcmp(av[n], "-l") == 0) {
259 75
                        lfmt = 1;
260 75
                        continue;
261
                }
262 625
                if (strcmp(av[n], "changed") == 0) {
263 25
                        chg = 1;
264 25
                        continue;
265
                }
266 600
                if (show != NULL) {
267 25
                        VCLI_SetResult(cli, CLIS_TOOMANY);
268 25
                        VCLI_Out(cli, "Too many parameters");
269 25
                        return;
270
                }
271 575
                show = av[n];
272 575
                lfmt = 1;
273 575
        }
274
275 800
        vsb = VSB_new_auto();
276 800
        AN(vsb);
277
278 800
        n = 0;
279 94400
        VTAILQ_FOREACH(pl, &phead, list) {
280 93600
                pp = pl->spec;
281 93600
                if (lfmt && show != NULL && strcmp(pp->name, show))
282 63825
                        continue;
283 29875
                if (pp->func == tweak_alias &&
284 1100
                    (show == NULL || strcmp(pp->name, show)))
285 1000
                        continue;
286 28775
                n++;
287
288 28775
                VSB_clear(vsb);
289 28775
                if (pp->func(vsb, pp, NULL))
290 0
                        VCLI_SetResult(cli, CLIS_PARAM);
291 28775
                AZ(VSB_finish(vsb));
292 28775
                if (chg && pp->def != NULL && !strcmp(pp->def, VSB_data(vsb)))
293 2525
                        continue;
294
295 26250
                if (pp->flags & NOT_IMPLEMENTED) {
296 0
                        if (lfmt) {
297 0
                                VCLI_Out(cli, "%s\n", pp->name);
298 0
                                VCLI_Out(cli, "%-*sNot available", margin1, " ");
299 0
                        } else {
300 0
                                VCLI_Out(cli, "%-*s-", margin2, pp->name);
301
                        }
302 0
                } else {
303 26250
                        if (lfmt) {
304 9000
                                VCLI_Out(cli, "%s\n", pp->name);
305 9000
                                VCLI_Out(cli, "%-*sValue is: ", margin1, " ");
306 9000
                        } else {
307 17250
                                VCLI_Out(cli, "%-*s", margin2, pp->name);
308
                        }
309
310 26250
                        VCLI_Out(cli, "%s", VSB_data(vsb));
311 26250
                        if (pp->units != NULL && *pp->units != '\0')
312 20900
                                VCLI_Out(cli, " [%s]", pp->units);
313 26250
                        if (pp->def != NULL && !strcmp(pp->def, VSB_data(vsb)))
314 23325
                                VCLI_Out(cli, " (default)");
315
                }
316 26250
                VCLI_Out(cli, "\n");
317
318 26250
                if (lfmt && pp->func == tweak_alias) {
319 100
                        pa = TRUST_ME(pp->priv);
320 200
                        VCLI_Out(cli, "%-*sAlias of: %s\n",
321 100
                            margin1, " ", pa->name);
322 100
                }
323 26250
                if (lfmt && pp->flags & NOT_IMPLEMENTED) {
324 0
                        VCLI_Out(cli, "\n");
325 0
                        mcf_wrap(cli, NOT_IMPLEMENTED_TEXT);
326 0
                        VCLI_Out(cli, "\n\n");
327 26250
                } else if (lfmt) {
328 9000
                        if (pp->def != NULL && strcmp(pp->def, VSB_data(vsb)))
329 2100
                                VCLI_Out(cli, "%-*sDefault is: %s\n",
330 1050
                                    margin1, "", pp->def);
331 9000
                        if (pp->min != NULL)
332 13750
                                VCLI_Out(cli, "%-*sMinimum is: %s\n",
333 6875
                                    margin1, "", pp->min);
334 9000
                        if (pp->max != NULL)
335 3600
                                VCLI_Out(cli, "%-*sMaximum is: %s\n",
336 1800
                                    margin1, "", pp->max);
337 9000
                        VCLI_Out(cli, "\n");
338 9000
                        mcf_wrap(cli, pp->descr);
339 9000
                        if (pp->flags & OBJ_STICKY)
340 250
                                mcf_wrap(cli, OBJ_STICKY_TEXT);
341 9000
                        if (pp->flags & DELAYED_EFFECT)
342 1200
                                mcf_wrap(cli, DELAYED_EFFECT_TEXT);
343 9000
                        if (pp->flags & EXPERIMENTAL)
344 2100
                                mcf_wrap(cli, EXPERIMENTAL_TEXT);
345 9000
                        if (pp->flags & MUST_RELOAD)
346 175
                                mcf_wrap(cli, MUST_RELOAD_TEXT);
347 9000
                        if (pp->flags & MUST_RESTART)
348 525
                                mcf_wrap(cli, MUST_RESTART_TEXT);
349 9000
                        if (pp->flags & WIZARD)
350 375
                                mcf_wrap(cli, WIZARD_TEXT);
351 9000
                        if (pp->flags & PROTECTED)
352 25
                                mcf_wrap(cli, PROTECTED_TEXT);
353 9000
                        if (pp->flags & ONLY_ROOT)
354 0
                                mcf_wrap(cli, ONLY_ROOT_TEXT);
355 9000
                        if (pp->flags & BUILD_OPTIONS)
356 325
                                mcf_wrap(cli, BUILD_OPTIONS_TEXT);
357 9000
                        VCLI_Out(cli, "\n\n");
358 9000
                }
359 26250
        }
360 800
        if (show != NULL && n == 0) {
361 25
                VCLI_SetResult(cli, CLIS_PARAM);
362 25
                VCLI_Out(cli, "Unknown parameter \"%s\".", show);
363 25
        }
364 800
        VSB_destroy(&vsb);
365 825
}
366
367
static inline void
368 29100
mcf_json_key_valstr(struct cli *cli, const char *key, const char *val)
369
{
370 29100
        VCLI_Out(cli, "\"%s\": ", key);
371 29100
        VCLI_JSON_str(cli, val);
372 29100
        VCLI_Out(cli, ",\n");
373 29100
}
374
375
static void v_matchproto_(cli_func_t)
376 325
mcf_param_show_json(struct cli *cli, const char * const *av, void *priv)
377
{
378 325
        int n, comma = 0, chg = 0;
379
        struct plist *pl;
380
        const struct parspec *pp, *pa;
381
        struct vsb *vsb, *def;
382 325
        const char *show = NULL, *sep;
383
384 325
        (void)priv;
385
386 900
        for (int i = 2; av[i] != NULL; i++) {
387 625
                if (strcmp(av[i], "-l") == 0) {
388 25
                        VCLI_SetResult(cli, CLIS_PARAM);
389 25
                        VCLI_Out(cli, "-l not permitted with param.show -j");
390 25
                        return;
391
                }
392 600
                if (strcmp(av[i], "changed") == 0) {
393 25
                        chg = 1;
394 25
                        continue;
395
                }
396 575
                if (strcmp(av[i], "-j") == 0)
397 325
                        continue;
398 250
                if (show != NULL) {
399 25
                        VCLI_SetResult(cli, CLIS_TOOMANY);
400 25
                        VCLI_Out(cli, "Too many parameters");
401 25
                        return;
402
                }
403 225
                show = av[i];
404 225
        }
405
406 275
        vsb = VSB_new_auto();
407 275
        AN(vsb);
408 275
        def = VSB_new_auto();
409 275
        AN(def);
410
411 275
        n = 0;
412 275
        VCLI_JSON_begin(cli, 2, av);
413 275
        VCLI_Out(cli, ",\n");
414 32450
        VTAILQ_FOREACH(pl, &phead, list) {
415 32175
                pp = pl->spec;
416 32175
                if (show != NULL && strcmp(pp->name, show) != 0)
417 23225
                        continue;
418 8975
                if (pp->func == tweak_alias &&
419 325
                    (show == NULL || strcmp(pp->name, show)))
420 300
                        continue;
421 8650
                n++;
422
423 8650
                VSB_clear(vsb);
424 8650
                if (pp->func(vsb, pp, JSON_FMT))
425 0
                        VCLI_SetResult(cli, CLIS_PARAM);
426 8650
                AZ(VSB_finish(vsb));
427 8650
                VSB_clear(def);
428 8650
                if (pp->func(def, pp, NULL))
429 0
                        VCLI_SetResult(cli, CLIS_PARAM);
430 8650
                AZ(VSB_finish(def));
431 8650
                if (chg && pp->def != NULL && !strcmp(pp->def, VSB_data(def)))
432 2525
                        continue;
433
434 6125
                VCLI_Out(cli, "%s", comma ? ",\n" : "");
435 6125
                comma++;
436 6125
                VCLI_Out(cli, "{\n");
437 6125
                VSB_indent(cli->sb, 2);
438 6125
                mcf_json_key_valstr(cli, "name", pp->name);
439 6125
                if (pp->func == tweak_alias) {
440 25
                        pa = TRUST_ME(pp->priv);
441 25
                        mcf_json_key_valstr(cli, "alias", pa->name);
442 25
                }
443 6125
                if (pp->flags & NOT_IMPLEMENTED) {
444 0
                        VCLI_Out(cli, "\"implemented\": false\n");
445 0
                        VSB_indent(cli->sb, -2);
446 0
                        VCLI_Out(cli, "}");
447 0
                        continue;
448
                }
449 6125
                VCLI_Out(cli, "\"implemented\": true,\n");
450 6125
                VCLI_Out(cli, "\"value\": %s,\n", VSB_data(vsb));
451 6125
                if (pp->units != NULL && *pp->units != '\0')
452 4800
                        mcf_json_key_valstr(cli, "units", pp->units);
453
454 6125
                if (pp->def != NULL)
455 6100
                        mcf_json_key_valstr(cli, "default", pp->def);
456 6125
                if (pp->min != NULL)
457 4625
                        mcf_json_key_valstr(cli, "minimum", pp->min);
458 6125
                if (pp->max != NULL)
459 1300
                        mcf_json_key_valstr(cli, "maximum", pp->max);
460 6125
                mcf_json_key_valstr(cli, "description", pp->descr);
461
462 6125
                VCLI_Out(cli, "\"flags\": [");
463 6125
                VSB_indent(cli->sb, 2);
464 6125
                sep = "";
465
466
#define flag_out(flag, string) do {                                     \
467
                        if (pp->flags & flag) {                         \
468
                                VCLI_Out(cli, "%s\n", sep);             \
469
                                VCLI_Out(cli, "\"%s\"", #string);       \
470
                                sep = ",";                              \
471
                        }                                               \
472
                } while(0)
473
474 6125
                flag_out(OBJ_STICKY, obj_sticky);
475 6125
                flag_out(DELAYED_EFFECT, delayed_effect);
476 6125
                flag_out(EXPERIMENTAL, experimental);
477 6125
                flag_out(MUST_RELOAD, must_reload);
478 6125
                flag_out(MUST_RESTART, must_restart);
479 6125
                flag_out(WIZARD, wizard);
480 6125
                flag_out(PROTECTED, protected);
481 6125
                flag_out(ONLY_ROOT, only_root);
482 6125
                flag_out(BUILD_OPTIONS, build_options);
483
484
#undef flag_out
485
486 6125
                if (pp->flags)
487 2975
                        VCLI_Out(cli, "\n");
488 6125
                VSB_indent(cli->sb, -2);
489 6125
                VCLI_Out(cli, "]\n");
490 6125
                VSB_indent(cli->sb, -2);
491 6125
                VCLI_Out(cli, "}");
492 6125
        }
493 275
        VCLI_JSON_end(cli);
494 275
        if (show != NULL && n == 0) {
495 25
                VSB_clear(cli->sb);
496 25
                VCLI_SetResult(cli, CLIS_PARAM);
497 25
                VCLI_Out(cli, "Unknown parameter \"%s\".", show);
498 25
        }
499 275
        VSB_destroy(&vsb);
500 275
        VSB_destroy(&def);
501 325
}
502
503
/*--------------------------------------------------------------------
504
 * Mark parameters as protected
505
 */
506
507
void
508 25
MCF_ParamProtect(struct cli *cli, const char *args)
509
{
510
        char **av;
511
        struct parspec *pp;
512
        int i;
513
514 25
        av = VAV_Parse(args, NULL, ARGV_COMMA);
515 25
        if (av[0] != NULL) {
516 0
                VCLI_Out(cli, "Parse error: %s", av[0]);
517 0
                VCLI_SetResult(cli, CLIS_PARAM);
518 0
                VAV_Free(av);
519 0
                return;
520
        }
521 50
        for (i = 1; av[i] != NULL; i++) {
522 25
                pp = mcf_findpar(av[i]);
523 25
                if (pp == NULL) {
524 0
                        VCLI_Out(cli, "Unknown parameter %s", av[i]);
525 0
                        VCLI_SetResult(cli, CLIS_PARAM);
526 0
                        VAV_Free(av);
527 0
                        return;
528
                }
529 25
                pp->flags |= PROTECTED;
530 25
        }
531 25
        VAV_Free(av);
532 25
}
533
534
/*--------------------------------------------------------------------*/
535
536
void
537 221125
MCF_ParamSet(struct cli *cli, const char *param, const char *val)
538
{
539
        const struct parspec *pp;
540
541 221125
        pp = mcf_findpar(param);
542 221125
        if (pp == NULL) {
543 100
                VCLI_SetResult(cli, CLIS_PARAM);
544 100
                VCLI_Out(cli, "Unknown parameter \"%s\".", param);
545 100
                return;
546
        }
547 221025
        if (pp->flags & NOT_IMPLEMENTED) {
548 0
                VCLI_SetResult(cli, CLIS_CANT);
549 0
                VCLI_Out(cli,
550
                    "parameter \"%s\" is not available on this platform.",
551 0
                    param
552
                );
553 0
                return;
554
        }
555 221025
        if (pp->flags & PROTECTED) {
556 25
                VCLI_SetResult(cli, CLIS_AUTH);
557 25
                VCLI_Out(cli, "parameter \"%s\" is protected.", param);
558 25
                return;
559
        }
560 221000
        if (!val)
561 675
                val = pp->def;
562 221000
        if (pp->func(cli->sb, pp, val))
563 700
                VCLI_SetResult(cli, CLIS_PARAM);
564
565 221000
        if (cli->result == CLIS_OK && heritage.param != NULL)
566 7950
                *heritage.param = mgt_param;
567
568 221000
        if (cli->result != CLIS_OK) {
569 1400
                VCLI_Out(cli, "\n(attempting to set param '%s' to '%s')",
570 700
                    pp->name, val);
571 221000
        } else if (MCH_Running() && pp->flags & MUST_RESTART) {
572 0
                VCLI_Out(cli,
573
                    "\nChange will take effect when child is restarted");
574 220300
        } else if (pp->flags & MUST_RELOAD) {
575 50
                VCLI_Out(cli,
576
                    "\nChange will take effect when VCL script is reloaded");
577 50
        }
578 221125
}
579
580
581
/*--------------------------------------------------------------------*/
582
583
static void v_matchproto_(cli_func_t)
584 12025
mcf_param_set(struct cli *cli, const char * const *av, void *priv)
585
{
586
587 12025
        (void)priv;
588 12025
        MCF_ParamSet(cli, av[2], av[3]);
589 12025
}
590
591
static void v_matchproto_(cli_func_t)
592 100
mcf_param_set_json(struct cli *cli, const char * const *av, void *priv)
593
{
594 100
        const char *const avs[] = { av[0], av[1], av[2], av[3], NULL };
595
596 100
        MCF_ParamSet(cli, av[3], av[4]);
597 100
        if (cli->result == CLIS_OK)
598 100
                mcf_param_show_json(cli, avs, priv);
599 100
}
600
601
/*--------------------------------------------------------------------*/
602
603
static void v_matchproto_(cli_func_t)
604 650
mcf_param_reset(struct cli *cli, const char * const *av, void *priv)
605
{
606
607 650
        (void)priv;
608 650
        MCF_ParamSet(cli, av[2], NULL);
609 650
}
610
611
/*--------------------------------------------------------------------
612
 * Initialize parameters and sort by name.
613
 */
614
615
static struct parspec mgt_parspec[] = {
616
#define PARAM_ALL
617
#define PARAM_PRE {
618
#define PARAM(typ, fld, nm, ...) #nm, __VA_ARGS__
619
#define PARAM_POST },
620
#include "tbl/params.h"
621
        { NULL, NULL, NULL }
622
};
623
624
static void
625 24800
mcf_init_params(void)
626
{
627
        struct parspec *pp;
628
        const char *s;
629
630 2926400
        for (pp = mgt_parspec; pp->name != NULL; pp++) {
631 2901600
                AN(pp->func);
632 2901600
                s = strchr(pp->descr, '\0');
633 2901600
                if (isspace(s[-1])) {
634 0
                        fprintf(stderr,
635 0
                            "Param->descr has trailing space: %s\n", pp->name);
636 0
                        exit(4);
637
                }
638 2901600
                mcf_addpar(pp);
639 2901600
                margin2 = vmax_t(int, margin2, strlen(pp->name) + 1);
640 2901600
        }
641 24800
}
642
643
/*--------------------------------------------------------------------
644
 * Wash a min/max/default value
645
 */
646
647
static void
648 1883950
mcf_dyn_vsb(enum mcf_which_e which, struct parspec *pp, struct vsb *vsb)
649
{
650
651 1883950
        switch (which) {
652
        case MCF_DEFAULT:
653 595200
                REPLACE(pp->dyn_def, VSB_data(vsb));
654 595200
                pp->def = pp->dyn_def;
655 595200
                break;
656
        case MCF_MINIMUM:
657 817525
                REPLACE(pp->dyn_min, VSB_data(vsb));
658 817525
                pp->min = pp->dyn_min;
659 817525
                break;
660
        case MCF_MAXIMUM:
661 471225
                REPLACE(pp->dyn_max, VSB_data(vsb));
662 471225
                pp->max = pp->dyn_max;
663 471225
                break;
664
        default:
665 0
                WRONG("bad 'which'");
666 0
        }
667 1883950
}
668
669
static void
670 5679200
mcf_wash_param(struct cli *cli, struct parspec *pp, enum mcf_which_e which,
671
    const char *name, struct vsb *vsb)
672
{
673
        const char *val;
674
        int err;
675
676 5679200
        switch (which) {
677 2901600
        case MCF_DEFAULT: val = pp->def; break;
678 2182400
        case MCF_MINIMUM: val = pp->min; break;
679 595200
        case MCF_MAXIMUM: val = pp->max; break;
680
        default:
681 0
                WRONG("bad 'which'");
682 0
        }
683 5679200
        AN(val);
684
685 5679200
        if (pp->func == tweak_alias) {
686 99200
                assert(which == MCF_DEFAULT);
687 99200
                pp->priv = mcf_findpar(pp->def);
688 99200
                pp->def = NULL;
689 99200
                return;
690
        }
691
692 5580000
        VSB_clear(vsb);
693 11160000
        VSB_printf(vsb, "FAILED to set %s for param %s: %s\n",
694 5580000
            name, pp->name, val);
695 5580000
        err = pp->func(vsb, pp, val);
696 5580000
        AZ(VSB_finish(vsb));
697 5580000
        if (err) {
698 0
                VCLI_Out(cli, "%s\n", VSB_data(vsb));
699 0
                VCLI_SetResult(cli, CLIS_CANT);
700 0
                return;
701
        }
702 5580000
        VSB_clear(vsb);
703 5580000
        err = pp->func(vsb, pp, NULL);
704 5580000
        AZ(err);
705 5580000
        AZ(VSB_finish(vsb));
706 5580000
        if (strcmp(val, VSB_data(vsb)))
707 1091200
                mcf_dyn_vsb(which, pp, vsb);
708 5679200
}
709
710
/*--------------------------------------------------------------------*/
711
712
static struct cli_proto cli_params[] = {
713
        { CLICMD_PARAM_SHOW,    "", mcf_param_show, mcf_param_show_json },
714
        { CLICMD_PARAM_SET,     "", mcf_param_set, mcf_param_set_json },
715
        { CLICMD_PARAM_RESET,   "", mcf_param_reset, mcf_param_set_json },
716
        { NULL }
717
};
718
719
/*--------------------------------------------------------------------
720
 * Configure the parameters
721
 */
722
723
void
724 24800
MCF_InitParams(struct cli *cli)
725
{
726
        struct plist *pl;
727
        struct parspec *pp;
728
        struct vsb *vsb;
729
        ssize_t def, low;
730
731 24800
        mcf_init_params();
732 24800
        MCF_TcpParams();
733
734 24800
        def = 80 * 1024;
735
736
        if (sizeof(void *) < 8) {               /*lint !e506 !e774  */
737
                /*
738
                 * Adjust default parameters for 32 bit systems to conserve
739
                 * VM space.
740
                 *
741
                 * Reflect changes in doc/sphinx/reference/varnishd.rst !
742
                 */
743
                MCF_ParamConf(MCF_DEFAULT, "workspace_client", "24k");
744
                MCF_ParamConf(MCF_DEFAULT, "workspace_backend", "20k");
745
                MCF_ParamConf(MCF_DEFAULT, "http_resp_size", "8k");
746
                MCF_ParamConf(MCF_DEFAULT, "http_req_size", "12k");
747
                MCF_ParamConf(MCF_DEFAULT, "gzip_buffer", "4k");
748
                MCF_ParamConf(MCF_DEFAULT, "vsl_buffer", "4k");
749
                MCF_ParamConf(MCF_MAXIMUM, "vsl_space", "1G");
750
                def = 64 * 1024;
751
        }
752
753 24800
        low = sysconf(_SC_THREAD_STACK_MIN);
754 24800
        MCF_ParamConf(MCF_MINIMUM, "thread_pool_stack", "%jdb", (intmax_t)low);
755
756
#if defined(ENABLE_SANITIZER) || defined(ENABLE_COVERAGE)
757 24800
        def = 192 * 1024;
758
#endif
759
760 24800
        if (def < low)
761 0
                def = low;
762 24800
        MCF_ParamConf(MCF_DEFAULT, "thread_pool_stack", "%jdb", (intmax_t)def);
763
764
#if !defined(MAX_THREAD_POOLS)
765
#  define MAX_THREAD_POOLS 32
766
#endif
767
768 24800
        MCF_ParamConf(MCF_MAXIMUM, "thread_pools", "%d", MAX_THREAD_POOLS);
769
770
#if !defined(HAVE_ACCEPT_FILTERS) || defined(__linux)
771
        MCF_ParamConf(MCF_DEFAULT, "accept_filter", "off");
772
#endif
773
774 24800
        VCLS_AddFunc(mgt_cls, MCF_AUTH, cli_params);
775
776 24800
        vsb = VSB_new_auto();
777 24800
        AN(vsb);
778
779 2926400
        VTAILQ_FOREACH(pl, &phead, list) {
780 2901600
                pp = pl->spec;
781
782 2901600
                if (pp->flags & NOT_IMPLEMENTED)
783 0
                        continue;
784 2901600
                if (pp->min != NULL)
785 2182400
                        mcf_wash_param(cli, pp, MCF_MINIMUM, "minimum", vsb);
786 2901600
                if (pp->max != NULL)
787 595200
                        mcf_wash_param(cli, pp, MCF_MAXIMUM, "maximum", vsb);
788 2901600
                AN(pp->def);
789 2901600
                mcf_wash_param(cli, pp, MCF_DEFAULT, "default", vsb);
790 2901600
        }
791 24800
        VSB_destroy(&vsb);
792
793 24800
        AN(mgt_cc_cmd);
794 24800
        REPLACE(mgt_cc_cmd_def, mgt_cc_cmd);
795 24800
}
796
797
/*--------------------------------------------------------------------*/
798
799
void
800 792750
MCF_ParamConf(enum mcf_which_e which, const char * const param,
801
    const char *fmt, ...)
802
{
803
        struct parspec *pp;
804
        struct vsb *vsb;
805
        va_list ap;
806
807 792750
        pp = mcf_findpar(param);
808 792750
        AN(pp);
809 792750
        vsb = VSB_new_auto();
810 792750
        AN(vsb);
811 792750
        va_start(ap, fmt);
812 792750
        VSB_vprintf(vsb, fmt, ap);
813 792750
        va_end(ap);
814 792750
        AZ(VSB_finish(vsb));
815 792750
        mcf_dyn_vsb(which, pp, vsb);
816 792750
        VSB_destroy(&vsb);
817 792750
}
818
819
/*--------------------------------------------------------------------*/
820
821
void
822 50
MCF_DumpRstParam(void)
823
{
824
        struct plist *pl;
825
        const struct parspec *pp;
826
        const char *p, *q, *t1, *t2;
827
        size_t z;
828
829 50
        printf("\n.. The following is the autogenerated "
830
            "output from varnishd -x parameter\n\n");
831 5900
        VTAILQ_FOREACH(pl, &phead, list) {
832 5850
                pp = pl->spec;
833 5850
                if (!strcmp("deprecated_dummy", pp->name))
834 50
                    continue;
835 5800
                printf(".. _ref_param_%s:\n\n", pp->name);
836 5800
                printf("%s\n", pp->name);
837 91950
                for (z = 0; z < strlen(pp->name); z++)
838 86150
                        printf("~");
839 5800
                printf("\n");
840
841 5800
                if (pp->flags && pp->flags & PLATFORM_DEPENDENT)
842 250
                        printf("\n%s\n\n", PLATFORM_DEPENDENT_TEXT);
843
844 5800
                if (pp->flags && pp->flags & BUILD_OPTIONS)
845 200
                        printf("\n%s\n\n", BUILD_OPTIONS_TEXT);
846
847 5800
                if (pp->units != NULL && *pp->units != '\0')
848 4550
                        printf("\t* Units: %s\n", pp->units);
849
#define MCF_DYN_REASON(lbl, nm)                                 \
850
                if (pp->dyn_ ## nm ## _reason != NULL)          \
851
                        printf("\t* " #lbl ": %s\n",            \
852
                            pp->dyn_ ## nm ## _reason);         \
853
                else if (pp->nm != NULL)                        \
854
                        printf("\t* " #lbl ": %s\n", pp->nm);
855 5800
                MCF_DYN_REASON(Default, def);
856 5800
                MCF_DYN_REASON(Minimum, min);
857 5800
                MCF_DYN_REASON(Maximum, max);
858
#undef MCF_DYN_REASON
859 5800
                if (pp->flags & ~DOCS_FLAGS) {
860 2700
                        printf("\t* Flags: ");
861 2700
                        q = "";
862
863 2700
                        if (pp->flags & DELAYED_EFFECT) {
864 800
                                printf("%sdelayed", q);
865 800
                                q = ", ";
866 800
                        }
867 2700
                        if (pp->flags & MUST_RESTART) {
868 350
                                printf("%smust_restart", q);
869 350
                                q = ", ";
870 350
                        }
871 2700
                        if (pp->flags & MUST_RELOAD) {
872 100
                                printf("%smust_reload", q);
873 100
                                q = ", ";
874 100
                        }
875 2700
                        if (pp->flags & EXPERIMENTAL) {
876 1400
                                printf("%sexperimental", q);
877 1400
                                q = ", ";
878 1400
                        }
879 2700
                        if (pp->flags & WIZARD) {
880 250
                                printf("%swizard", q);
881 250
                                q = ", ";
882 250
                        }
883 2700
                        if (pp->flags & ONLY_ROOT) {
884 0
                                printf("%sonly_root", q);
885 0
                                q = ", ";
886 0
                        }
887 2700
                        if (pp->flags & OBJ_STICKY) {
888 150
                                printf("%sobj_sticky", q);
889 150
                                q = ", ";
890 150
                        }
891 2700
                        printf("\n");
892 2700
                }
893 5800
                printf("\n");
894 5800
                p = pp->descr;
895 22650
                while (*p != '\0') {
896 16850
                        q = strchr(p, '\n');
897 16850
                        if (q == NULL)
898 5800
                                q = strchr(p, '\0');
899 16850
                        t1 = strchr(p, '\t');
900 16850
                        if (t1 != NULL && t1 < q) {
901 2750
                                t2 = strchr(t1 + 1, '\t');
902 2750
                                AN(t2);
903 2750
                                printf("\n\t*");
904 2750
                                (void)fwrite(t1 + 1, (t2 - 1) - t1, 1, stdout);
905 2750
                                printf("*\n\t\t");
906 2750
                                p = t2 + 1;
907 2750
                        }
908 16850
                        (void)fwrite(p, q - p, 1, stdout);
909 16850
                        p = q;
910 16850
                        if (*p == '\n') {
911 11050
                                printf("\n");
912 11050
                                p++;
913 11050
                        }
914 16850
                        continue;
915
                }
916 5800
                printf("\n\n");
917 5800
        }
918 50
}