varnish-cache/bin/varnishd/mgt/mgt_param_tweak.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
 * Functions for tweaking parameters
30
 *
31
 */
32
33
#include "config.h"
34
35
#include <limits.h>
36
#include <math.h>
37
#include <stdlib.h>
38
#include <string.h>
39
40
#include "mgt/mgt.h"
41
42
#include "mgt/mgt_param.h"
43
#include "vav.h"
44
#include "vnum.h"
45
46
const char * const JSON_FMT = (const char *)&JSON_FMT;
47
48
/*--------------------------------------------------------------------
49
 * Generic handling of double typed parameters
50
 */
51
52
static int
53 127804
tweak_generic_double(struct vsb *vsb, volatile double *dest,
54
    const char *arg, const char *min, const char *max, const char *fmt)
55
{
56 127804
        volatile double u, minv = 0, maxv = 0;
57
58 127804
        if (arg != NULL && arg != JSON_FMT) {
59 64988
                if (min != NULL) {
60 64988
                        minv = VNUM(min);
61 64988
                        if (isnan(minv)) {
62 0
                                VSB_printf(vsb, "Illegal Min: %s\n", min);
63 0
                                return (-1);
64
                        }
65 64988
                }
66 64988
                if (max != NULL) {
67 19975
                        maxv = VNUM(max);
68 19975
                        if (isnan(maxv)) {
69 0
                                VSB_printf(vsb, "Illegal Max: %s\n", max);
70 0
                                return (-1);
71
                        }
72 19975
                }
73
74 64988
                u = VNUM(arg);
75 64988
                if (isnan(u)) {
76 1
                        VSB_printf(vsb, "Not a number(%s)\n", arg);
77 1
                        return (-1);
78
                }
79 64987
                if (min != NULL && u < minv) {
80 2
                        VSB_printf(vsb,
81 1
                            "Must be greater or equal to %s\n", min);
82 1
                        return (-1);
83
                }
84 64986
                if (max != NULL && u > maxv) {
85 2
                        VSB_printf(vsb,
86 1
                            "Must be less than or equal to %s\n", max);
87 1
                        return (-1);
88
                }
89 64985
                *dest = u;
90 64985
        } else
91 62816
                VSB_printf(vsb, fmt, *dest);
92 127801
        return (0);
93 127804
}
94
95
/*--------------------------------------------------------------------*/
96
97
int
98 120298
tweak_timeout(struct vsb *vsb, const struct parspec *par,
99
    const char *arg)
100
{
101
        volatile double *dest;
102
103 120298
        dest = par->priv;
104 240596
        return (tweak_generic_double(vsb, dest, arg,
105 120298
            par->min, par->max, "%.3f"));
106
}
107
108
/*--------------------------------------------------------------------*/
109
110
int
111 5004
tweak_double(struct vsb *vsb, const struct parspec *par, const char *arg)
112
{
113
        volatile double *dest;
114
115 5004
        dest = par->priv;
116 10008
        return (tweak_generic_double(vsb, dest, arg,
117 5004
            par->min, par->max, "%g"));
118
}
119
120
/*--------------------------------------------------------------------*/
121
122
int
123 20764
tweak_bool(struct vsb *vsb, const struct parspec *par, const char *arg)
124
{
125
        volatile unsigned *dest;
126
127 20764
        dest = par->priv;
128 20764
        if (arg != NULL && arg != JSON_FMT) {
129 11468
                if (!strcasecmp(arg, "off"))
130 3185
                        *dest = 0;
131 8283
                else if (!strcasecmp(arg, "disable"))
132 1
                        *dest = 0;
133 8282
                else if (!strcasecmp(arg, "no"))
134 1
                        *dest = 0;
135 8281
                else if (!strcasecmp(arg, "false"))
136 7
                        *dest = 0;
137 8274
                else if (!strcasecmp(arg, "on"))
138 8250
                        *dest = 1;
139 24
                else if (!strcasecmp(arg, "enable"))
140 1
                        *dest = 1;
141 23
                else if (!strcasecmp(arg, "yes"))
142 1
                        *dest = 1;
143 22
                else if (!strcasecmp(arg, "true"))
144 21
                        *dest = 1;
145
                else {
146 1
                        VSB_cat(vsb, "use \"on\" or \"off\"\n");
147 1
                        return (-1);
148
                }
149 20763
        } else if (arg == JSON_FMT) {
150 24
                VSB_printf(vsb, "%s", *dest ? "true" : "false");
151 24
        } else {
152 9272
                VSB_printf(vsb, "%s", *dest ? "on" : "off");
153
        }
154 20763
        return (0);
155 20764
}
156
157
/*--------------------------------------------------------------------*/
158
159
static int
160 106047
tweak_generic_uint(struct vsb *vsb, volatile unsigned *dest, const char *arg,
161
    const char *min, const char *max,
162
    const char *min_reason, const char *max_reason)
163
{
164 106047
        unsigned u, minv = 0, maxv = 0;
165
        char *p;
166
167 106047
        if (arg != NULL && arg != JSON_FMT) {
168 55803
                if (min != NULL) {
169 45851
                        p = NULL;
170 45851
                        minv = strtoul(min, &p, 0);
171 45851
                        if (*arg == '\0' || *p != '\0') {
172 0
                                VSB_printf(vsb, "Illegal Min: %s\n", min);
173 0
                                return (-1);
174
                        }
175 45851
                }
176 55803
                if (max != NULL) {
177 21629
                        p = NULL;
178 21629
                        maxv = strtoul(max, &p, 0);
179 21629
                        if (*arg == '\0' || *p != '\0') {
180 0
                                VSB_printf(vsb, "Illegal Max: %s\n", max);
181 0
                                return (-1);
182
                        }
183 21629
                }
184 55803
                p = NULL;
185 55803
                if (!strcasecmp(arg, "unlimited"))
186 1
                        u = UINT_MAX;
187
                else {
188 55802
                        u = strtoul(arg, &p, 0);
189 55802
                        if (*arg == '\0' || *p != '\0') {
190 2
                                VSB_printf(vsb, "Not a number (%s)\n", arg);
191 2
                                return (-1);
192
                        }
193
                }
194 55801
                if (min != NULL && u < minv) {
195 3
                        VSB_printf(vsb, "Must be at least %s", min);
196 3
                        if (min_reason != NULL)
197 2
                                VSB_printf(vsb, " (%s)", min_reason);
198 3
                        VSB_putc(vsb, '\n');
199 3
                        return (-1);
200
                }
201 55798
                if (max != NULL && u > maxv) {
202 6
                        VSB_printf(vsb, "Must be no more than %s", max);
203 6
                        if (max_reason != NULL)
204 5
                                VSB_printf(vsb, " (%s)", max_reason);
205 6
                        VSB_putc(vsb, '\n');
206 6
                        return (-1);
207
                }
208 55792
                *dest = u;
209 106036
        } else if (*dest == UINT_MAX && arg != JSON_FMT) {
210 5
                VSB_cat(vsb, "unlimited");
211 5
        } else {
212 50239
                VSB_printf(vsb, "%u", *dest);
213
        }
214 106036
        return (0);
215 106047
}
216
217
/*--------------------------------------------------------------------*/
218
219
int
220 101040
tweak_uint(struct vsb *vsb, const struct parspec *par, const char *arg)
221
{
222
        volatile unsigned *dest;
223
224 101040
        dest = par->priv;
225 202080
        return (tweak_generic_uint(vsb, dest, arg, par->min, par->max,
226 101040
            par->dyn_min_reason, par->dyn_max_reason));
227
}
228
229
/*--------------------------------------------------------------------*/
230
231
static void
232 45990
fmt_bytes(struct vsb *vsb, uintmax_t t)
233
{
234
        const char *p;
235
236 45990
        if (t == 0 || t & 0xff) {
237 13344
                VSB_printf(vsb, "%jub", t);
238 13344
                return;
239
        }
240 46850
        for (p = "kMGTPEZY"; *p; p++) {
241 46850
                if (t & 0x300) {
242 5012
                        VSB_printf(vsb, "%.2f%c", t / 1024.0, *p);
243 5012
                        return;
244
                }
245 41838
                t /= 1024;
246 41838
                if (t & 0x0ff) {
247 27634
                        VSB_printf(vsb, "%ju%c", t, *p);
248 27634
                        return;
249
                }
250 14204
        }
251 0
        VSB_cat(vsb, "(bogus number)");
252 45990
}
253
254
static int
255 92588
tweak_generic_bytes(struct vsb *vsb, volatile ssize_t *dest, const char *arg,
256
    const char *min, const char *max)
257
{
258 92588
        uintmax_t r, rmin = 0, rmax = 0;
259
        const char *p;
260
261 92588
        if (arg != NULL && arg != JSON_FMT) {
262 46552
                if (min != NULL) {
263 46552
                        p = VNUM_2bytes(min, &rmin, 0);
264 46552
                        if (p != NULL) {
265 0
                                VSB_printf(vsb, "Invalid min-val: %s\n", min);
266 0
                                return (-1);
267
                        }
268 46552
                }
269 46552
                if (max != NULL) {
270 23233
                        p = VNUM_2bytes(max, &rmax, 0);
271 23233
                        if (p != NULL) {
272 0
                                VSB_printf(vsb, "Invalid max-val: %s\n", max);
273 0
                                return (-1);
274
                        }
275 23233
                }
276 46552
                p = VNUM_2bytes(arg, &r, 0);
277 46552
                if (p != NULL) {
278 2
                        VSB_cat(vsb, "Could not convert to bytes.\n");
279 2
                        VSB_printf(vsb, "%s\n", p);
280 2
                        VSB_cat(vsb, "  Try something like '80k' or '120M'\n");
281 2
                        return (-1);
282
                }
283 46550
                if ((uintmax_t)((ssize_t)r) != r) {
284 0
                        fmt_bytes(vsb, r);
285 0
                        VSB_cat(vsb, " is too large for this architecture.\n");
286 0
                        return (-1);
287
                }
288 46550
                if (max != NULL && r > rmax) {
289 1
                        VSB_printf(vsb, "Must be no more than %s\n", max);
290 1
                        VSB_cat(vsb, "\n");
291 1
                        return (-1);
292
                }
293 46549
                if (min != NULL && r < rmin) {
294 1
                        VSB_printf(vsb, "Must be at least %s\n", min);
295 1
                        return (-1);
296
                }
297 46548
                *dest = r;
298 92584
        } else if (arg == JSON_FMT) {
299 46
                VSB_printf(vsb, "%zd", *dest);
300 46
        } else {
301 45990
                fmt_bytes(vsb, *dest);
302
        }
303 92584
        return (0);
304 92588
}
305
306
/*--------------------------------------------------------------------*/
307
308
int
309 20796
tweak_bytes(struct vsb *vsb, const struct parspec *par, const char *arg)
310
{
311
        volatile ssize_t *dest;
312
313 20796
        dest = par->priv;
314 20796
        return (tweak_generic_bytes(vsb, dest, arg, par->min, par->max));
315
}
316
317
/*--------------------------------------------------------------------*/
318
319
int
320 63448
tweak_bytes_u(struct vsb *vsb, const struct parspec *par, const char *arg)
321
{
322
        volatile unsigned *d1;
323
        volatile ssize_t dest;
324
325 63448
        d1 = par->priv;
326 63448
        dest = *d1;
327 63448
        if (tweak_generic_bytes(vsb, &dest, arg, par->min, par->max))
328 4
                return (-1);
329 63444
        *d1 = dest;
330 63444
        return (0);
331 63448
}
332
333
/*--------------------------------------------------------------------
334
 * vsl_buffer and vsl_reclen have dependencies.
335
 */
336
337
int
338 3340
tweak_vsl_buffer(struct vsb *vsb, const struct parspec *par, const char *arg)
339
{
340
        volatile unsigned *d1;
341
        volatile ssize_t dest;
342
343 3340
        d1 = par->priv;
344 3340
        dest = *d1;
345 3340
        if (tweak_generic_bytes(vsb, &dest, arg, par->min, par->max))
346 0
                return (-1);
347 3340
        *d1 = dest;
348 3340
        MCF_ParamConf(MCF_MAXIMUM, "vsl_reclen", "%u", *d1 - 12);
349 3340
        return (0);
350 3340
}
351
352
int
353 5004
tweak_vsl_reclen(struct vsb *vsb, const struct parspec *par, const char *arg)
354
{
355
        volatile unsigned *d1;
356
        volatile ssize_t dest;
357
358 5004
        d1 = par->priv;
359 5004
        dest = *d1;
360 5004
        if (tweak_generic_bytes(vsb, &dest, arg, par->min, par->max))
361 0
                return (-1);
362 5004
        *d1 = dest;
363 5004
        MCF_ParamConf(MCF_MINIMUM, "vsl_buffer", "%u", *d1 + 12);
364 5004
        return (0);
365 5004
}
366
367
/*--------------------------------------------------------------------*/
368
369
int
370 5791
tweak_string(struct vsb *vsb, const struct parspec *par, const char *arg)
371
{
372 5791
        char **p = TRUST_ME(par->priv);
373
374 5791
        AN(p);
375
        /* XXX should have tweak_generic_string */
376 5791
        if (arg == NULL) {
377 2526
                VSB_quote(vsb, *p, -1, 0);
378 5791
        } else if (arg == JSON_FMT) {
379 6
                VSB_quote(vsb, *p, -1, VSB_QUOTE_JSON|VSB_QUOTE_CSTR);
380 6
        } else {
381 3259
                REPLACE(*p, arg);
382
        }
383 5791
        return (0);
384
}
385
386
/*--------------------------------------------------------------------*/
387
388
int
389 5042
tweak_poolparam(struct vsb *vsb, const struct parspec *par, const char *arg)
390
{
391
        volatile struct poolparam *pp, px;
392
        char **av;
393 5042
        int retval = 0;
394
395 5042
        pp = par->priv;
396 5042
        if (arg == JSON_FMT) {
397 8
                VSB_cat(vsb, "{\n");
398 8
                VSB_indent(vsb, 8);
399 8
                VSB_printf(vsb, "\"min_pool\": %u,\n", pp->min_pool);
400 8
                VSB_printf(vsb, "\"max_pool\": %u,\n", pp->max_pool);
401 8
                VSB_printf(vsb, "\"max_age\": %g\n", pp->max_age);
402 8
                VSB_indent(vsb, -4);
403 8
                VSB_cat(vsb, "}");
404 5042
        } else if (arg == NULL) {
405 5056
                VSB_printf(vsb, "%u,%u,%g",
406 2528
                    pp->min_pool, pp->max_pool, pp->max_age);
407 2528
        } else {
408 2506
                av = VAV_Parse(arg, NULL, ARGV_COMMA);
409 2506
                do {
410 2506
                        if (av[0] != NULL) {
411 1
                                VSB_printf(vsb, "Parse error: %s", av[0]);
412 1
                                retval = -1;
413 1
                                break;
414
                        }
415 2505
                        if (av[1] == NULL || av[2] == NULL || av[3] == NULL) {
416 1
                                VSB_cat(vsb,
417
                                    "Three fields required:"
418
                                    " min_pool, max_pool and max_age\n");
419 1
                                retval = -1;
420 1
                                break;
421
                        }
422 2504
                        px = *pp;
423 5008
                        retval = tweak_generic_uint(vsb, &px.min_pool, av[1],
424 2504
                            par->min, par->max, par->dyn_min_reason,
425 2504
                            par->dyn_max_reason);
426 2504
                        if (retval)
427 1
                                break;
428 5006
                        retval = tweak_generic_uint(vsb, &px.max_pool, av[2],
429 2503
                            par->min, par->max, par->dyn_min_reason,
430 2503
                            par->dyn_max_reason);
431 2503
                        if (retval)
432 1
                                break;
433 5004
                        retval = tweak_generic_double(vsb,
434 2502
                            &px.max_age, av[3], "0", "1e6", "%.0f");
435 2502
                        if (retval)
436 1
                                break;
437 2501
                        if (px.min_pool > px.max_pool) {
438 1
                                VSB_cat(vsb,
439
                                    "min_pool cannot be larger"
440
                                    " than max_pool\n");
441 1
                                retval = -1;
442 1
                                break;
443
                        }
444 2500
                        *pp = px;
445 2500
                } while (0);
446 2506
                VAV_Free(av);
447
        }
448 5042
        return (retval);
449
}