varnish-cache/bin/varnishd/mgt/mgt_param.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2011 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29
30
#include "config.h"
31
32
#include <ctype.h>
33
#include <stdarg.h>
34
#include <stdio.h>
35
#include <stdlib.h>
36
#include <string.h>
37
#include <unistd.h>
38
39
#include "mgt/mgt.h"
40
#include "common/heritage.h"
41
42
#include "mgt/mgt_param.h"
43
#include "vav.h"
44
#include "vcli_serve.h"
45
46
#if !defined(__has_feature)
47
#define __has_feature(x)        0
48
#endif
49
50
struct plist {
51
        unsigned                        magic;
52
#define PLIST_MAGIC                     0xbfc3ea16
53
        VTAILQ_ENTRY(plist)             list;
54
        struct parspec                  *spec;
55
};
56
57
static VTAILQ_HEAD(, plist)             phead = VTAILQ_HEAD_INITIALIZER(phead);
58
59
struct params mgt_param;
60
static const int margin1 = 8;
61
static int margin2 = 0;
62
static const int wrap_at = 72;
63
static const int tab0 = 3;
64
65
/*--------------------------------------------------------------------*/
66
67
static const char OBJ_STICKY_TEXT[] =
68
        "\n\n"
69
        "NB: This parameter is evaluated only when objects are created. "
70
        "To change it for all objects, restart or ban everything.";
71
72
static const char DELAYED_EFFECT_TEXT[] =
73
        "\n\n"
74
        "NB: This parameter may take quite some time to take (full) effect.";
75
76
static const char MUST_RESTART_TEXT[] =
77
        "\n\n"
78
        "NB: This parameter will not take any effect until the "
79
        "child process has been restarted.";
80
81
static const char MUST_RELOAD_TEXT[] =
82
        "\n\n"
83
        "NB: This parameter will not take any effect until the "
84
        "VCL programs have been reloaded.";
85
86
static const char EXPERIMENTAL_TEXT[] =
87
        "\n\n"
88
        "NB: We do not know yet if it is a good idea to change "
89
        "this parameter, or if the default value is even sensible. "
90
        "Caution is advised, and feedback is most welcome.";
91
92
static const char WIZARD_TEXT[] =
93
        "\n\n"
94
        "NB: Do not change this parameter, unless a developer tell "
95
        "you to do so.";
96
97
static const char PROTECTED_TEXT[] =
98
        "\n\n"
99
        "NB: This parameter is protected and can not be changed.";
100
101
static const char ONLY_ROOT_TEXT[] =
102
        "\n\n"
103
        "NB: This parameter only works if varnishd is run as root.";
104
105
static const char NOT_IMPLEMENTED_TEXT[] =
106
        "This parameter depends on a feature which is not available"
107
        " on this platform.";
108
109
static const char NOT_IMPLEMENTED_DOC[] =
110
        "NB: This parameter depends on a feature which is not available"
111
        " on all platforms.";
112
113
/*--------------------------------------------------------------------*/
114
115
static struct parspec *
116 528102
mcf_findpar(const char *name)
117
{
118
        struct plist *pl;
119
120 528102
        AN(name);
121 42980436
        VTAILQ_FOREACH(pl, &phead, list)
122 42980364
                if (!strcmp(pl->spec->name, name))
123 528030
                        return (pl->spec);
124 72
        return (NULL);
125 528102
}
126
127
static void
128 1549800
mcf_addpar(struct parspec *ps)
129
{
130
        struct plist *pl, *pl2;
131
        int i;
132
133 1549800
        ALLOC_OBJ(pl, PLIST_MAGIC);
134 1549800
        AN(pl);
135 1549800
        pl->spec = ps;
136 66670920
        VTAILQ_FOREACH(pl2, &phead, list) {
137 65977200
                i = strcmp(pl2->spec->name, pl->spec->name);
138 65977200
                if (i == 0) {
139 0
                        fprintf(stderr, "Duplicate param: %s\n", ps->name);
140 0
                        exit(4);
141 65977200
                } else if (i > 0) {
142 856080
                        VTAILQ_INSERT_BEFORE(pl2, pl, list);
143 856080
                        return;
144
                }
145 65121120
        }
146 693720
        VTAILQ_INSERT_TAIL(&phead, pl, list);
147 1549800
}
148
149
/*--------------------------------------------------------------------
150
 * Wrap the text nicely.
151
 * Lines are allowed to contain two TABS and we render that as a table
152
 * taking the width of the first column into account.
153
 */
154
155
static void
156 23382
mcf_wrap_line(struct cli *cli, const char *b, const char *e, int tabs, int m0)
157
{
158 23382
        int n, hadtabs = 0;
159
        const char *w;
160
161 23382
        n = m0;
162 23382
        VCLI_Out(cli, "%*s", n, "");
163
164 348084
        while (b < e) {
165 335880
                if (!isspace(*b)) {
166 160848
                        VCLI_Out(cli, "%c", *b);
167 160848
                        b++;
168 160848
                        n++;
169 335880
                } else if (*b == '\t') {
170 5472
                        assert(tabs);
171 5472
                        assert(hadtabs < 2);
172 5472
                        do {
173 42264
                                VCLI_Out(cli, " ");
174 42264
                                n++;
175 42264
                        } while ((n % tabs) != (m0 + tab0) % tabs);
176 5472
                        b++;
177 5472
                        hadtabs++;
178 5472
                } else {
179 169560
                        assert (*b == ' ');
180 998352
                        for (w = b + 1; w < e; w++)
181 986148
                                if (isspace(*w))
182 157356
                                        break;
183 169560
                        if (n + (w - b) < wrap_at) {
184 158382
                                VCLI_Out(cli, "%.*s", (int)(w - b), b);
185 158382
                                n += (w - b);
186 158382
                                b = w;
187 158382
                        } else {
188 11178
                                assert(hadtabs == 0 || hadtabs == 2);
189 11178
                                VCLI_Out(cli, "\n");
190 22356
                                mcf_wrap_line(cli, b + 1, e, 0,
191 11178
                                    hadtabs ? m0 + tab0 + tabs : m0);
192 11178
                                return;
193
                        }
194
                }
195
        }
196 12204
        assert(b == e);
197 23382
}
198
199
static void
200 5940
mcf_wrap(struct cli *cli, const char *text)
201
{
202
        const char *p, *q, *r;
203 5940
        int tw = 0;
204
205 5940
        if (strchr(text, '\t') != NULL) {
206 3096
                for (p = text; *p != '\0'; ) {
207 3096
                        q = strstr(p, "\n\t");
208 3096
                        if (q == NULL)
209 360
                                break;
210 2736
                        q += 2;
211 2736
                        r = strchr(q, '\t');
212 2736
                        if (r == NULL) {
213 0
                                fprintf(stderr,
214 0
                                    "LINE with just one TAB: <%s>\n", text);
215 0
                                exit(4);
216
                        }
217 2736
                        if (r - q > tw)
218 864
                                tw = r - q;
219 2736
                        p = q;
220
                }
221 360
                tw += 2;
222 360
                if (tw < 20)
223 288
                        tw = 20;
224 360
        }
225
226 30060
        for (p = text; *p != '\0'; ) {
227 24120
                if (*p == '\n') {
228 11916
                        VCLI_Out(cli, "\n");
229 11916
                        p++;
230 11916
                        continue;
231
                }
232 12204
                q = strchr(p, '\n');
233 12204
                if (q == NULL)
234 5940
                        q = strchr(p, '\0');
235 12204
                mcf_wrap_line(cli, p, q, tw, margin1);
236 12204
                p = q;
237
        }
238 5940
}
239
240
/*--------------------------------------------------------------------*/
241
242
static void v_matchproto_(cli_func_t)
243 450
mcf_param_show(struct cli *cli, const char * const *av, void *priv)
244
{
245
        int n;
246
        struct plist *pl;
247
        const struct parspec *pp;
248 450
        int lfmt = 0, chg = 0;
249
        struct vsb *vsb;
250
251 450
        vsb = VSB_new_auto();
252 450
        (void)priv;
253
254 450
        if (av[2] != NULL && !strcmp(av[2], "changed"))
255 18
                chg = 1;
256 432
        else if (av[2] != NULL)
257 342
                lfmt = 1;
258
259 450
        n = 0;
260 47700
        VTAILQ_FOREACH(pl, &phead, list) {
261 47250
                pp = pl->spec;
262 47250
                if (lfmt && strcmp(pp->name, av[2]) && strcmp("-l", av[2]))
263 31842
                        continue;
264 15408
                n++;
265
266 15408
                VSB_clear(vsb);
267 15408
                if (pp->func(vsb, pp, NULL))
268 0
                        VCLI_SetResult(cli, CLIS_PARAM);
269 15408
                AZ(VSB_finish(vsb));
270 15408
                if (chg && pp->def != NULL && !strcmp(pp->def, VSB_data(vsb)))
271 1728
                        continue;
272
273 13680
                if (pp->flags & NOT_IMPLEMENTED) {
274 126
                        if (lfmt) {
275 36
                                VCLI_Out(cli, "%s\n", pp->name);
276 36
                                VCLI_Out(cli, "%-*sNot available", margin1, " ");
277 36
                        } else {
278 90
                                VCLI_Out(cli, "%-*s-", margin2, pp->name);
279
                        }
280 126
                } else {
281 13554
                        if (lfmt) {
282 4032
                                VCLI_Out(cli, "%s\n", pp->name);
283 4032
                                VCLI_Out(cli, "%-*sValue is: ", margin1, " ");
284 4032
                        } else {
285 9522
                                VCLI_Out(cli, "%-*s", margin2, pp->name);
286
                        }
287
288 13554
                        VCLI_Out(cli, "%s", VSB_data(vsb));
289 13554
                        if (pp->units != NULL && *pp->units != '\0')
290 11088
                                VCLI_Out(cli, " [%s]", pp->units);
291 13554
                        if (pp->def != NULL && !strcmp(pp->def, VSB_data(vsb)))
292 12222
                                VCLI_Out(cli, " (default)");
293
                }
294 13680
                VCLI_Out(cli, "\n");
295
296 13680
                if (lfmt && pp->flags & NOT_IMPLEMENTED) {
297 36
                        VCLI_Out(cli, "\n");
298 36
                        mcf_wrap(cli, NOT_IMPLEMENTED_TEXT);
299 36
                        VCLI_Out(cli, "\n\n");
300 13680
                } else if (lfmt) {
301 4032
                        if (pp->def != NULL && strcmp(pp->def, VSB_data(vsb)))
302 936
                                VCLI_Out(cli, "%-*sDefault is: %s\n",
303 468
                                    margin1, "", pp->def);
304 4032
                        if (pp->min != NULL)
305 6192
                                VCLI_Out(cli, "%-*sMinimum is: %s\n",
306 3096
                                    margin1, "", pp->min);
307 4032
                        if (pp->max != NULL)
308 1800
                                VCLI_Out(cli, "%-*sMaximum is: %s\n",
309 900
                                    margin1, "", pp->max);
310 4032
                        VCLI_Out(cli, "\n");
311 4032
                        mcf_wrap(cli, pp->descr);
312 4032
                        if (pp->flags & OBJ_STICKY)
313 126
                                mcf_wrap(cli, OBJ_STICKY_TEXT);
314 4032
                        if (pp->flags & DELAYED_EFFECT)
315 468
                                mcf_wrap(cli, DELAYED_EFFECT_TEXT);
316 4032
                        if (pp->flags & EXPERIMENTAL)
317 900
                                mcf_wrap(cli, EXPERIMENTAL_TEXT);
318 4032
                        if (pp->flags & MUST_RELOAD)
319 36
                                mcf_wrap(cli, MUST_RELOAD_TEXT);
320 4032
                        if (pp->flags & MUST_RESTART)
321 180
                                mcf_wrap(cli, MUST_RESTART_TEXT);
322 4032
                        if (pp->flags & WIZARD)
323 144
                                mcf_wrap(cli, WIZARD_TEXT);
324 4032
                        if (pp->flags & PROTECTED)
325 18
                                mcf_wrap(cli, PROTECTED_TEXT);
326 4032
                        if (pp->flags & ONLY_ROOT)
327 0
                                mcf_wrap(cli, ONLY_ROOT_TEXT);
328 4032
                        VCLI_Out(cli, "\n\n");
329 4032
                }
330 13680
        }
331 450
        if (av[2] != NULL && lfmt && strcmp(av[2], "-l") && n == 0) {
332 18
                VCLI_SetResult(cli, CLIS_PARAM);
333 18
                VCLI_Out(cli, "Unknown parameter \"%s\".", av[2]);
334 18
        }
335 450
        VSB_destroy(&vsb);
336 450
}
337
338
static inline void
339 9882
mcf_json_key_valstr(struct cli *cli, const char *key, const char *val)
340
{
341 9882
        VCLI_Out(cli, "\"%s\": ", key);
342 9882
        VCLI_JSON_str(cli, val);
343 9882
        VCLI_Out(cli, ",\n");
344 9882
}
345
346
static void v_matchproto_(cli_func_t)
347 108
mcf_param_show_json(struct cli *cli, const char * const *av, void *priv)
348
{
349 108
        int n, comma = 0;
350
        struct plist *pl;
351
        const struct parspec *pp;
352 108
        int chg = 0, flags;
353
        struct vsb *vsb, *def;
354 108
        const char *show = NULL;
355
356 108
        (void)priv;
357
358 288
        for (int i = 2; av[i] != NULL; i++) {
359 198
                if (strcmp(av[i], "-l") == 0) {
360 18
                        VCLI_SetResult(cli, CLIS_PARAM);
361 18
                        VCLI_Out(cli, "-l not permitted with param.show -j");
362 18
                        return;
363
                }
364 180
                if (strcmp(av[i], "changed") == 0) {
365 18
                        chg = 1;
366 18
                        continue;
367
                }
368 162
                if (strcmp(av[i], "-j") == 0)
369 108
                        continue;
370 54
                show = av[i];
371 54
        }
372
373 90
        vsb = VSB_new_auto();
374 90
        def = VSB_new_auto();
375
376 90
        n = 0;
377 90
        VCLI_JSON_begin(cli, 2, av);
378 90
        VCLI_Out(cli, ",\n");
379 9540
        VTAILQ_FOREACH(pl, &phead, list) {
380 9450
                pp = pl->spec;
381 9450
                if (show != NULL && strcmp(pp->name, show) != 0)
382 5634
                        continue;
383 3816
                n++;
384
385 3816
                VSB_clear(vsb);
386 3816
                if (pp->func(vsb, pp, JSON_FMT))
387 0
                        VCLI_SetResult(cli, CLIS_PARAM);
388 3816
                AZ(VSB_finish(vsb));
389 3816
                VSB_clear(def);
390 3816
                if (pp->func(def, pp, NULL))
391 0
                        VCLI_SetResult(cli, CLIS_PARAM);
392 3816
                AZ(VSB_finish(def));
393 3816
                if (chg && pp->def != NULL && !strcmp(pp->def, VSB_data(def)))
394 1728
                        continue;
395
396 2088
                VCLI_Out(cli, "%s", comma ? ",\n" : "");
397 2088
                comma++;
398 2088
                VCLI_Out(cli, "{\n");
399 2088
                VSB_indent(cli->sb, 2);
400 2088
                mcf_json_key_valstr(cli, "name", pp->name);
401 2088
                if (pp->flags & NOT_IMPLEMENTED) {
402 18
                        VCLI_Out(cli, "\"implemented\": false\n");
403 18
                        VSB_indent(cli->sb, -2);
404 18
                        VCLI_Out(cli, "}");
405 18
                        continue;
406
                }
407 2070
                VCLI_Out(cli, "\"implemented\": true,\n");
408 2070
                VCLI_Out(cli, "\"value\": %s,\n", VSB_data(vsb));
409 2070
                if (pp->units != NULL && *pp->units != '\0')
410 1656
                        mcf_json_key_valstr(cli, "units", pp->units);
411
412 2070
                if (pp->def != NULL)
413 2070
                        mcf_json_key_valstr(cli, "default", pp->def);
414 2070
                if (pp->min != NULL)
415 1512
                        mcf_json_key_valstr(cli, "minimum", pp->min);
416 2070
                if (pp->max != NULL)
417 486
                        mcf_json_key_valstr(cli, "maximum", pp->max);
418 2070
                mcf_json_key_valstr(cli, "description", pp->descr);
419
420 2070
                flags = 0;
421 2070
                VCLI_Out(cli, "\"flags\": [\n");
422 2070
                VSB_indent(cli->sb, 2);
423
424
#define flag_out(flag, string) do {                                     \
425
                        if (pp->flags & flag) {                         \
426
                                if (flags)                              \
427
                                        VCLI_Out(cli, ",\n");           \
428
                                VCLI_Out(cli, "\"%s\"", #string);       \
429
                                flags++;                                \
430
                        }                                               \
431
                } while(0)
432
433 2070
                flag_out(OBJ_STICKY, obj_sticky);
434 2070
                flag_out(DELAYED_EFFECT, delayed_effect);
435 2070
                flag_out(EXPERIMENTAL, experimental);
436 2070
                flag_out(MUST_RELOAD, must_reload);
437 2070
                flag_out(MUST_RESTART, must_restart);
438 2070
                flag_out(WIZARD, wizard);
439 2070
                flag_out(PROTECTED, protected);
440 2070
                flag_out(ONLY_ROOT, only_root);
441
442
#undef flag_out
443
444 2070
                VSB_indent(cli->sb, -2);
445 2070
                VCLI_Out(cli, "\n]");
446 2070
                VSB_indent(cli->sb, -2);
447 2070
                VCLI_Out(cli, "\n}");
448 2070
        }
449 90
        VCLI_JSON_end(cli);
450 90
        if (show != NULL && n == 0) {
451 18
                VSB_clear(cli->sb);
452 18
                VCLI_SetResult(cli, CLIS_PARAM);
453 18
                VCLI_Out(cli, "Unknown parameter \"%s\".", show);
454 18
        }
455 90
        VSB_destroy(&vsb);
456 90
        VSB_destroy(&def);
457 108
}
458
459
/*--------------------------------------------------------------------
460
 * Mark parameters as protected
461
 */
462
463
void
464 18
MCF_ParamProtect(struct cli *cli, const char *args)
465
{
466
        char **av;
467
        struct parspec *pp;
468
        int i;
469
470 18
        av = VAV_Parse(args, NULL, ARGV_COMMA);
471 18
        if (av[0] != NULL) {
472 0
                VCLI_Out(cli, "Parse error: %s", av[0]);
473 0
                VCLI_SetResult(cli, CLIS_PARAM);
474 0
                VAV_Free(av);
475 0
                return;
476
        }
477 36
        for (i = 1; av[i] != NULL; i++) {
478 18
                pp = mcf_findpar(av[i]);
479 18
                if (pp == NULL) {
480 0
                        VCLI_Out(cli, "Unknown parameter %s", av[i]);
481 0
                        VCLI_SetResult(cli, CLIS_PARAM);
482 0
                        VAV_Free(av);
483 0
                        return;
484
                }
485 18
                pp->flags |= PROTECTED;
486 18
        }
487 18
        VAV_Free(av);
488 18
}
489
490
/*--------------------------------------------------------------------*/
491
492
void
493 115866
MCF_ParamSet(struct cli *cli, const char *param, const char *val)
494
{
495
        const struct parspec *pp;
496
497 115866
        pp = mcf_findpar(param);
498 115866
        if (pp == NULL) {
499 72
                VCLI_SetResult(cli, CLIS_PARAM);
500 72
                VCLI_Out(cli, "Unknown parameter \"%s\".", param);
501 72
                return;
502
        }
503 115794
        if (pp->flags & PROTECTED) {
504 18
                VCLI_SetResult(cli, CLIS_AUTH);
505 18
                VCLI_Out(cli, "parameter \"%s\" is protected.", param);
506 18
                return;
507
        }
508 115776
        if (!val)
509 108
                val = pp->def;
510 115776
        if (pp->func(cli->sb, pp, val))
511 396
                VCLI_SetResult(cli, CLIS_PARAM);
512
513 115776
        if (cli->result == CLIS_OK && heritage.param != NULL)
514 4446
                *heritage.param = mgt_param;
515
516 115776
        if (cli->result != CLIS_OK) {
517 792
                VCLI_Out(cli, "\n(attempting to set param '%s' to '%s')",
518 396
                    pp->name, val);
519 115776
        } else if (MCH_Running() && pp->flags & MUST_RESTART) {
520 0
                VCLI_Out(cli,
521
                    "\nChange will take effect when child is restarted");
522 115380
        } else if (pp->flags & MUST_RELOAD) {
523 0
                VCLI_Out(cli,
524
                    "\nChange will take effect when VCL script is reloaded");
525 0
        }
526 115866
}
527
528
529
/*--------------------------------------------------------------------*/
530
531
static void v_matchproto_(cli_func_t)
532 6210
mcf_param_set(struct cli *cli, const char * const *av, void *priv)
533
{
534
535 6210
        (void)priv;
536 6210
        MCF_ParamSet(cli, av[2], av[3]);
537 6210
}
538
539
/*--------------------------------------------------------------------*/
540
541
static void v_matchproto_(cli_func_t)
542 108
mcf_param_reset(struct cli *cli, const char * const *av, void *priv)
543
{
544
545 108
        (void)priv;
546 108
        MCF_ParamSet(cli, av[2], NULL);
547 108
}
548
549
/*--------------------------------------------------------------------
550
 * Add a group of parameters to the global set and sort by name.
551
 */
552
553
void
554 44280
MCF_AddParams(struct parspec *ps)
555
{
556
        struct parspec *pp;
557
        const char *s;
558
559 1594080
        for (pp = ps; pp->name != NULL; pp++) {
560 1549800
                AN(pp->func);
561 1549800
                s = strchr(pp->descr, '\0');
562 1549800
                if (isspace(s[-1])) {
563 0
                        fprintf(stderr,
564 0
                            "Param->descr has trailing space: %s\n", pp->name);
565 0
                        exit(4);
566
                }
567 1549800
                mcf_addpar(pp);
568 1549800
                if (strlen(pp->name) + 1 > margin2)
569 73800
                        margin2 = strlen(pp->name) + 1;
570 1549800
        }
571 44280
}
572
573
/*--------------------------------------------------------------------
574
 * Wash a min/max/default value
575
 */
576
577
static void
578 3099600
mcf_wash_param(struct cli *cli, const struct parspec *pp, const char **val,
579
    const char *name, struct vsb *vsb)
580
{
581
        int err;
582
583 3099600
        AN(*val);
584 3099600
        VSB_clear(vsb);
585 6199200
        VSB_printf(vsb, "FAILED to set %s for param %s: %s\n",
586 3099600
            name, pp->name, *val);
587 3099600
        err = pp->func(vsb, pp, *val);
588 3099600
        AZ(VSB_finish(vsb));
589 3099600
        if (err) {
590 0
                VCLI_Out(cli, "%s\n", VSB_data(vsb));
591 0
                VCLI_SetResult(cli, CLIS_CANT);
592 0
                return;
593
        }
594 3099600
        VSB_clear(vsb);
595 3099600
        err = pp->func(vsb, pp, NULL);
596 3099600
        AZ(err);
597 3099600
        AZ(VSB_finish(vsb));
598 3099600
        if (strcmp(*val, VSB_data(vsb))) {
599 575640
                *val = strdup(VSB_data(vsb));
600 575640
                AN(*val);
601 575640
        }
602 3099600
}
603
604
/*--------------------------------------------------------------------*/
605
606
static struct cli_proto cli_params[] = {
607
        { CLICMD_PARAM_SHOW,            "", mcf_param_show,
608
          mcf_param_show_json },
609
        { CLICMD_PARAM_SET,             "", mcf_param_set },
610
        { CLICMD_PARAM_RESET,           "", mcf_param_reset },
611
        { NULL }
612
};
613
614
/*--------------------------------------------------------------------
615
 * Configure the parameters
616
 */
617
618
void
619 14760
MCF_InitParams(struct cli *cli)
620
{
621
        struct plist *pl;
622
        struct parspec *pp;
623
        struct vsb *vsb;
624
        ssize_t def, low;
625
626 14760
        MCF_AddParams(mgt_parspec);
627 14760
        MCF_AddParams(WRK_parspec);
628 14760
        MCF_AddParams(VSL_parspec);
629
630 14760
        MCF_TcpParams();
631
632 14760
        def = 56 * 1024;
633
634
        if (sizeof(void *) < 8) {               /*lint !e506 !e774  */
635
                /*
636
                 * Adjust default parameters for 32 bit systems to conserve
637
                 * VM space.
638
                 *
639
                 * Reflect changes in doc/sphinx/reference/varnishd.rst !
640
                 */
641
                MCF_ParamConf(MCF_DEFAULT, "workspace_client", "24k");
642
                MCF_ParamConf(MCF_DEFAULT, "workspace_backend", "20k");
643
                MCF_ParamConf(MCF_DEFAULT, "http_resp_size", "8k");
644
                MCF_ParamConf(MCF_DEFAULT, "http_req_size", "12k");
645
                MCF_ParamConf(MCF_DEFAULT, "gzip_buffer", "4k");
646
                MCF_ParamConf(MCF_MAXIMUM, "vsl_space", "1G");
647
                def = 52 * 1024;
648
        }
649
650 14760
        low = sysconf(_SC_THREAD_STACK_MIN);
651 14760
        MCF_ParamConf(MCF_MINIMUM, "thread_pool_stack", "%jdb", (intmax_t)low);
652
653
#if defined(__SANITIZER) || __has_feature(address_sanitizer)
654
        def = 92 * 1024;
655
#endif
656
657 14760
        if (def < low)
658 0
                def = low;
659 14760
        MCF_ParamConf(MCF_DEFAULT, "thread_pool_stack", "%jdb", (intmax_t)def);
660
661
#if !defined(MAX_THREAD_POOLS)
662
#  define MAX_THREAD_POOLS 32
663
#endif
664
665 14760
        MCF_ParamConf(MCF_MAXIMUM, "thread_pools", "%d", MAX_THREAD_POOLS);
666
667
#if !defined(HAVE_ACCEPT_FILTERS) || defined(__linux)
668
        MCF_ParamConf(MCF_DEFAULT, "accept_filter", "off");
669
#endif
670
671 14760
        VCLS_AddFunc(mgt_cls, MCF_AUTH, cli_params);
672
673 14760
        vsb = VSB_new_auto();
674 14760
        AN(vsb);
675
676 1564560
        VTAILQ_FOREACH(pl, &phead, list) {
677 1549800
                pp = pl->spec;
678
679 1549800
                if (pp->flags & NOT_IMPLEMENTED)
680 14760
                        continue;
681 1535040
                if (pp->min != NULL)
682 1195560
                        mcf_wash_param(cli, pp, &pp->min, "minimum", vsb);
683 1535040
                if (pp->max != NULL)
684 369000
                        mcf_wash_param(cli, pp, &pp->max, "maximum", vsb);
685 1535040
                AN(pp->def);
686 1535040
                mcf_wash_param(cli, pp, &pp->def, "default", vsb);
687 1535040
        }
688 14760
        VSB_destroy(&vsb);
689 14760
}
690
691
/*--------------------------------------------------------------------*/
692
693
void
694 412218
MCF_ParamConf(enum mcf_which_e which, const char *param, const char *fmt, ...)
695
{
696
        struct parspec *pp;
697
        struct vsb *vsb;
698
        va_list ap;
699
700 412218
        pp = mcf_findpar(param);
701 412218
        AN(pp);
702 412218
        vsb = VSB_new_auto();
703 412218
        AN(vsb);
704 412218
        va_start(ap, fmt);
705 412218
        VSB_vprintf(vsb, fmt, ap);
706 412218
        va_end(ap);
707 412218
        AZ(VSB_finish(vsb));
708 412218
        switch (which) {
709
        case MCF_DEFAULT:
710 59040
                pp->def = strdup(VSB_data(vsb));
711 59040
                AN(pp->def);
712 59040
                break;
713
        case MCF_MINIMUM:
714 176400
                pp->min = strdup(VSB_data(vsb));
715 176400
                AN(pp->min);
716 176400
                break;
717
        case MCF_MAXIMUM:
718 176778
                pp->max = strdup(VSB_data(vsb));
719 176778
                AN(pp->max);
720 176778
                break;
721
        }
722 412218
        VSB_delete(vsb);
723 412218
}
724
725
/*--------------------------------------------------------------------*/
726
727
void
728 36
MCF_DumpRstParam(void)
729
{
730
        struct plist *pl;
731
        const struct parspec *pp;
732
        const char *p, *q, *t1, *t2;
733
        int j;
734
735 36
        printf("\n.. The following is the autogenerated "
736
            "output from varnishd -x parameter\n\n");
737 3816
        VTAILQ_FOREACH(pl, &phead, list) {
738 3780
                pp = pl->spec;
739 3780
                printf(".. _ref_param_%s:\n\n", pp->name);
740 3780
                printf("%s\n", pp->name);
741 59796
                for (j = 0; j < strlen(pp->name); j++)
742 56016
                        printf("~");
743 3780
                printf("\n");
744
745 3780
                if (pp->flags && pp->flags & NOT_IMPLEMENTED)
746 36
                        printf("\n%s\n\n", NOT_IMPLEMENTED_DOC);
747
748 3780
                if (pp->units != NULL && *pp->units != '\0')
749 3132
                        printf("\t* Units: %s\n", pp->units);
750 3780
                printf("\t* Default: %s\n", pp->def);
751 3780
                if (pp->min != NULL)
752 2952
                        printf("\t* Minimum: %s\n", pp->min);
753 3780
                if (pp->max != NULL)
754 900
                        printf("\t* Maximum: %s\n", pp->max);
755
                /*
756
                 * XXX: we should mark the params with one/two flags
757
                 * XXX: that say if ->min/->max are valid, so we
758
                 * XXX: can emit those also in help texts.
759
                 */
760 3780
                if (pp->flags) {
761 1764
                        printf("\t* Flags: ");
762 1764
                        q = "";
763
764 1764
                        if (pp->flags & DELAYED_EFFECT) {
765 468
                                printf("%sdelayed", q);
766 468
                                q = ", ";
767 468
                        }
768 1764
                        if (pp->flags & MUST_RESTART) {
769 180
                                printf("%smust_restart", q);
770 180
                                q = ", ";
771 180
                        }
772 1764
                        if (pp->flags & MUST_RELOAD) {
773 36
                                printf("%smust_reload", q);
774 36
                                q = ", ";
775 36
                        }
776 1764
                        if (pp->flags & EXPERIMENTAL) {
777 900
                                printf("%sexperimental", q);
778 900
                                q = ", ";
779 900
                        }
780 1764
                        if (pp->flags & WIZARD) {
781 144
                                printf("%swizard", q);
782 144
                                q = ", ";
783 144
                        }
784 1764
                        if (pp->flags & ONLY_ROOT) {
785 0
                                printf("%sonly_root", q);
786 0
                                q = ", ";
787 0
                        }
788 1764
                        if (pp->flags & OBJ_STICKY) {
789 108
                                printf("%sobj_sticky", q);
790 108
                                q = ", ";
791 108
                        }
792 1764
                        printf("\n");
793 1764
                }
794 3780
                printf("\n");
795 3780
                p = pp->descr;
796 14220
                while (*p != '\0') {
797 10440
                        q = strchr(p, '\n');
798 10440
                        if (q == NULL)
799 3780
                                q = strchr(p, '\0');
800 10440
                        t1 = strchr(p, '\t');
801 10440
                        if (t1 != NULL && t1 < q) {
802 1512
                                t2 = strchr(t1 + 1, '\t');
803 1512
                                AN(t2);
804 1512
                                printf("\n\t*");
805 1512
                                (void)fwrite(t1 + 1, (t2 - 1) - t1, 1, stdout);
806 1512
                                printf("*\n\t\t");
807 1512
                                p = t2 + 1;
808 1512
                        }
809 10440
                        (void)fwrite(p, q - p, 1, stdout);
810 10440
                        p = q;
811 10440
                        if (*p == '\n') {
812 6660
                                printf("\n");
813 6660
                                p++;
814 6660
                        }
815 10440
                        continue;
816
                }
817 3780
                printf("\n\n");
818 3780
        }
819 36
}