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 242382
tweak_generic_double(struct vsb *vsb, volatile double *dest,
54
    const char *arg, const char *min, const char *max, const char *fmt)
55
{
56 242382
        volatile double u, minv = 0, maxv = 0;
57
58 242382
        if (arg != NULL && arg != JSON_FMT) {
59 123212
                if (min != NULL) {
60 123212
                        minv = VNUM(min);
61 123212
                        if (isnan(minv)) {
62 0
                                VSB_printf(vsb, "Illegal Min: %s\n", min);
63 0
                                return (-1);
64
                        }
65
                }
66 123212
                if (max != NULL) {
67 37886
                        maxv = VNUM(max);
68 37886
                        if (isnan(maxv)) {
69 0
                                VSB_printf(vsb, "Illegal Max: %s\n", max);
70 0
                                return (-1);
71
                        }
72
                }
73
74 123212
                u = VNUM(arg);
75 123212
                if (isnan(u)) {
76 2
                        VSB_printf(vsb, "Not a number(%s)\n", arg);
77 2
                        return (-1);
78
                }
79 123210
                if (min != NULL && u < minv) {
80 2
                        VSB_printf(vsb,
81
                            "Must be greater or equal to %s\n", min);
82 2
                        return (-1);
83
                }
84 123208
                if (max != NULL && u > maxv) {
85 2
                        VSB_printf(vsb,
86
                            "Must be less than or equal to %s\n", max);
87 2
                        return (-1);
88
                }
89 123206
                *dest = u;
90
        } else
91 119170
                VSB_printf(vsb, fmt, *dest);
92 242376
        return (0);
93
}
94
95
/*--------------------------------------------------------------------*/
96
97
int
98 228144
tweak_timeout(struct vsb *vsb, const struct parspec *par,
99
    const char *arg)
100
{
101
        volatile double *dest;
102
103 228144
        dest = par->priv;
104 228144
        return (tweak_generic_double(vsb, dest, arg,
105
            par->min, par->max, "%.3f"));
106
}
107
108
/*--------------------------------------------------------------------*/
109
110
int
111 9492
tweak_double(struct vsb *vsb, const struct parspec *par, const char *arg)
112
{
113
        volatile double *dest;
114
115 9492
        dest = par->priv;
116 9492
        return (tweak_generic_double(vsb, dest, arg,
117
            par->min, par->max, "%g"));
118
}
119
120
/*--------------------------------------------------------------------*/
121
122
int
123 39370
tweak_bool(struct vsb *vsb, const struct parspec *par, const char *arg)
124
{
125
        volatile unsigned *dest;
126
127 39370
        dest = par->priv;
128 39370
        if (arg != NULL && arg != JSON_FMT) {
129 43446
                if (!strcasecmp(arg, "off"))
130 6020
                        *dest = 0;
131 15704
                else if (!strcasecmp(arg, "disable"))
132 2
                        *dest = 0;
133 15702
                else if (!strcasecmp(arg, "no"))
134 2
                        *dest = 0;
135 15700
                else if (!strcasecmp(arg, "false"))
136 14
                        *dest = 0;
137 15686
                else if (!strcasecmp(arg, "on"))
138 15638
                        *dest = 1;
139 48
                else if (!strcasecmp(arg, "enable"))
140 2
                        *dest = 1;
141 46
                else if (!strcasecmp(arg, "yes"))
142 2
                        *dest = 1;
143 44
                else if (!strcasecmp(arg, "true"))
144 42
                        *dest = 1;
145
                else {
146 2
                        VSB_printf(vsb, "use \"on\" or \"off\"\n");
147 2
                        return (-1);
148
                }
149 17646
        } else if (arg == JSON_FMT) {
150 48
                VSB_printf(vsb, "%s", *dest ? "true" : "false");
151
        } else {
152 17598
                VSB_printf(vsb, "%s", *dest ? "on" : "off");
153
        }
154 39368
        return (0);
155
}
156
157
/*--------------------------------------------------------------------*/
158
159
int
160 194790
tweak_generic_uint(struct vsb *vsb, volatile unsigned *dest, const char *arg,
161
    const char *min, const char *max)
162
{
163 194790
        unsigned u, minv = 0, maxv = 0;
164
        char *p;
165
166 194790
        if (arg != NULL && arg != JSON_FMT) {
167 102642
                if (min != NULL) {
168 83788
                        p = NULL;
169 83788
                        minv = strtoul(min, &p, 0);
170 83788
                        if (*arg == '\0' || *p != '\0') {
171 0
                                VSB_printf(vsb, "Illegal Min: %s\n", min);
172 0
                                return (-1);
173
                        }
174
                }
175 102642
                if (max != NULL) {
176 40996
                        p = NULL;
177 40996
                        maxv = strtoul(max, &p, 0);
178 40996
                        if (*arg == '\0' || *p != '\0') {
179 0
                                VSB_printf(vsb, "Illegal Max: %s\n", max);
180 0
                                return (-1);
181
                        }
182
                }
183 102642
                p = NULL;
184 102642
                if (!strcasecmp(arg, "unlimited"))
185 2
                        u = UINT_MAX;
186
                else {
187 102640
                        u = strtoul(arg, &p, 0);
188 102640
                        if (*arg == '\0' || *p != '\0') {
189 4
                                VSB_printf(vsb, "Not a number (%s)\n", arg);
190 4
                                return (-1);
191
                        }
192
                }
193 102638
                if (min != NULL && u < minv) {
194 4
                        VSB_printf(vsb, "Must be at least %s\n", min);
195 4
                        return (-1);
196
                }
197 102634
                if (max != NULL && u > maxv) {
198 8
                        VSB_printf(vsb, "Must be no more than %s\n", max);
199 8
                        return (-1);
200
                }
201 102626
                *dest = u;
202 92148
        } else if (*dest == UINT_MAX && arg != JSON_FMT) {
203 10
                VSB_printf(vsb, "unlimited");
204
        } else {
205 92138
                VSB_printf(vsb, "%u", *dest);
206
        }
207 194774
        return (0);
208
}
209
210
/*--------------------------------------------------------------------*/
211
212
int
213 174310
tweak_uint(struct vsb *vsb, const struct parspec *par, const char *arg)
214
{
215
        volatile unsigned *dest;
216
217 174310
        dest = par->priv;
218 174310
        return (tweak_generic_uint(vsb, dest, arg, par->min, par->max));
219
}
220
221
/*--------------------------------------------------------------------*/
222
223
static void
224 90428
fmt_bytes(struct vsb *vsb, uintmax_t t)
225
{
226
        const char *p;
227
228 90428
        if (t == 0 || t & 0xff) {
229 28490
                VSB_printf(vsb, "%jub", t);
230 28490
                return;
231
        }
232 88884
        for (p = "kMGTPEZY"; *p; p++) {
233 88884
                if (t & 0x300) {
234 9508
                        VSB_printf(vsb, "%.2f%c", t / 1024.0, *p);
235 9508
                        return;
236
                }
237 79376
                t /= 1024;
238 79376
                if (t & 0x0ff) {
239 52430
                        VSB_printf(vsb, "%ju%c", t, *p);
240 52430
                        return;
241
                }
242
        }
243 0
        VSB_printf(vsb, "(bogus number)");
244
}
245
246
static int
247 181964
tweak_generic_bytes(struct vsb *vsb, volatile ssize_t *dest, const char *arg,
248
    const char *min, const char *max)
249
{
250 181964
        uintmax_t r, rmin = 0, rmax = 0;
251
        const char *p;
252
253 181964
        if (arg != NULL && arg != JSON_FMT) {
254 91440
                if (min != NULL) {
255 91440
                        p = VNUM_2bytes(min, &rmin, 0);
256 91440
                        if (p != NULL) {
257 0
                                VSB_printf(vsb, "Invalid min-val: %s\n", min);
258 0
                                return (-1);
259
                        }
260
                }
261 91440
                if (max != NULL) {
262 44060
                        p = VNUM_2bytes(max, &rmax, 0);
263 44060
                        if (p != NULL) {
264 0
                                VSB_printf(vsb, "Invalid max-val: %s\n", max);
265 0
                                return (-1);
266
                        }
267
                }
268 91440
                p = VNUM_2bytes(arg, &r, 0);
269 91440
                if (p != NULL) {
270 4
                        VSB_printf(vsb, "Could not convert to bytes.\n");
271 4
                        VSB_printf(vsb, "%s\n", p);
272 4
                        VSB_printf(vsb,
273
                            "  Try something like '80k' or '120M'\n");
274 4
                        return (-1);
275
                }
276
                if ((uintmax_t)((ssize_t)r) != r) {
277
                        fmt_bytes(vsb, r);
278
                        VSB_printf(vsb,
279
                            " is too large for this architecture.\n");
280
                        return (-1);
281
                }
282 91436
                if (max != NULL && r > rmax) {
283 2
                        VSB_printf(vsb, "Must be no more than %s\n", max);
284 2
                        VSB_printf(vsb, "\n");
285 2
                        return (-1);
286
                }
287 91434
                if (min != NULL && r < rmin) {
288 2
                        VSB_printf(vsb, "Must be at least %s\n", min);
289 2
                        return (-1);
290
                }
291 91432
                *dest = r;
292 90524
        } else if (arg == JSON_FMT) {
293 96
                VSB_printf(vsb, "%zd", *dest);
294
        } else {
295 90428
                fmt_bytes(vsb, *dest);
296
        }
297 181956
        return (0);
298
}
299
300
/*--------------------------------------------------------------------*/
301
302
int
303 39442
tweak_bytes(struct vsb *vsb, const struct parspec *par, const char *arg)
304
{
305
        volatile ssize_t *dest;
306
307 39442
        dest = par->priv;
308 39442
        return (tweak_generic_bytes(vsb, dest, arg, par->min, par->max));
309
}
310
311
/*--------------------------------------------------------------------*/
312
313
int
314 120354
tweak_bytes_u(struct vsb *vsb, const struct parspec *par, const char *arg)
315
{
316
        volatile unsigned *d1;
317
        volatile ssize_t dest;
318
319 120354
        d1 = par->priv;
320 120354
        dest = *d1;
321 120354
        if (tweak_generic_bytes(vsb, &dest, arg, par->min, par->max))
322 8
                return (-1);
323 120346
        *d1 = dest;
324 120346
        return (0);
325
}
326
327
/*--------------------------------------------------------------------
328
 * vsl_buffer and vsl_reclen have dependencies.
329
 */
330
331
int
332 6336
tweak_vsl_buffer(struct vsb *vsb, const struct parspec *par, const char *arg)
333
{
334
        volatile unsigned *d1;
335
        volatile ssize_t dest;
336
337 6336
        d1 = par->priv;
338 6336
        dest = *d1;
339 6336
        if (tweak_generic_bytes(vsb, &dest, arg, par->min, par->max))
340 0
                return (-1);
341 6336
        *d1 = dest;
342 6336
        MCF_ParamConf(MCF_MAXIMUM, "vsl_reclen", "%u", *d1 - 12);
343 6336
        MCF_ParamConf(MCF_MAXIMUM, "shm_reclen", "%u", *d1 - 12);
344 6336
        return (0);
345
}
346
347
int
348 15832
tweak_vsl_reclen(struct vsb *vsb, const struct parspec *par, const char *arg)
349
{
350
        volatile unsigned *d1;
351
        volatile ssize_t dest;
352
353 15832
        d1 = par->priv;
354 15832
        dest = *d1;
355 15832
        if (tweak_generic_bytes(vsb, &dest, arg, par->min, par->max))
356 0
                return (-1);
357 15832
        *d1 = dest;
358 15832
        MCF_ParamConf(MCF_MINIMUM, "vsl_buffer", "%u", *d1 + 12);
359 15832
        return (0);
360
}
361
362
/*--------------------------------------------------------------------*/
363
364
int
365 17338
tweak_string(struct vsb *vsb, const struct parspec *par, const char *arg)
366
{
367 17338
        char **p = TRUST_ME(par->priv);
368
369 17338
        AN(p);
370
        /* XXX should have tweak_generic_string */
371 17338
        if (arg == NULL) {
372 7990
                VSB_quote(vsb, *p, -1, 0);
373 9348
        } else if (arg == JSON_FMT) {
374 20
                VSB_quote(vsb, *p, -1, VSB_QUOTE_JSON|VSB_QUOTE_CSTR);
375
        } else {
376 9328
                REPLACE(*p, arg);
377
        }
378 17338
        return (0);
379
}
380
381
/*--------------------------------------------------------------------*/
382
383
int
384 9568
tweak_poolparam(struct vsb *vsb, const struct parspec *par, const char *arg)
385
{
386
        volatile struct poolparam *pp, px;
387
        char **av;
388 9568
        int retval = 0;
389
390 9568
        pp = par->priv;
391 9568
        if (arg == JSON_FMT) {
392 16
                VSB_printf(vsb, "{\n");
393 16
                VSB_indent(vsb, 8);
394 16
                VSB_printf(vsb, "\"min_pool\": %u,\n", pp->min_pool);
395 16
                VSB_printf(vsb, "\"max_pool\": %u,\n", pp->max_pool);
396 16
                VSB_printf(vsb, "\"max_age\": %g\n", pp->max_age);
397 16
                VSB_indent(vsb, -4);
398 16
                VSB_printf(vsb, "}");
399 9552
        } else if (arg == NULL) {
400 4798
                VSB_printf(vsb, "%u,%u,%g",
401
                    pp->min_pool, pp->max_pool, pp->max_age);
402
        } else {
403 4754
                av = VAV_Parse(arg, NULL, ARGV_COMMA);
404
                do {
405 4754
                        if (av[0] != NULL) {
406 2
                                VSB_printf(vsb, "Parse error: %s", av[0]);
407 2
                                retval = -1;
408 2
                                break;
409
                        }
410 4752
                        if (av[1] == NULL || av[2] == NULL || av[3] == NULL) {
411 2
                                VSB_printf(vsb,
412
                                    "Three fields required:"
413
                                    " min_pool, max_pool and max_age\n");
414 2
                                retval = -1;
415 2
                                break;
416
                        }
417 4750
                        px = *pp;
418 4750
                        retval = tweak_generic_uint(vsb, &px.min_pool, av[1],
419
                            par->min, par->max);
420 4750
                        if (retval)
421 2
                                break;
422 4748
                        retval = tweak_generic_uint(vsb, &px.max_pool, av[2],
423
                            par->min, par->max);
424 4748
                        if (retval)
425 2
                                break;
426 4746
                        retval = tweak_generic_double(vsb,
427 4746
                            &px.max_age, av[3], "0", "1e6", "%.0f");
428 4746
                        if (retval)
429 2
                                break;
430 4744
                        if (px.min_pool > px.max_pool) {
431 2
                                VSB_printf(vsb,
432
                                    "min_pool cannot be larger"
433
                                    " than max_pool\n");
434 2
                                retval = -1;
435 2
                                break;
436
                        }
437 4742
                        *pp = px;
438
                } while (0);
439 4754
                VAV_Free(av);
440
        }
441 9568
        return (retval);
442
}