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
/*--------------------------------------------------------------------
47
 * Generic handling of double typed parameters
48
 */
49
50
static int
51 99291
tweak_generic_double(struct vsb *vsb, volatile double *dest,
52
    const char *arg, const char *min, const char *max, const char *fmt)
53
{
54 99291
        volatile double u, minv = 0, maxv = 0;
55
56 99291
        if (arg != NULL) {
57 50603
                if (min != NULL) {
58 50603
                        minv = VNUM(min);
59 50603
                        if (isnan(minv)) {
60 0
                                VSB_printf(vsb, "Illegal Min: %s\n", min);
61 0
                                return (-1);
62
                        }
63
                }
64 50603
                if (max != NULL) {
65 16855
                        maxv = VNUM(max);
66 16855
                        if (isnan(maxv)) {
67 0
                                VSB_printf(vsb, "Illegal Max: %s\n", max);
68 0
                                return (-1);
69
                        }
70
                }
71
72 50603
                u = VNUM(arg);
73 50603
                if (isnan(u)) {
74 1
                        VSB_printf(vsb, "Not a number(%s)\n", arg);
75 1
                        return (-1);
76
                }
77 50602
                if (min != NULL && u < minv) {
78 1
                        VSB_printf(vsb,
79
                            "Must be greater or equal to %s\n", min);
80 1
                        return (-1);
81
                }
82 50601
                if (max != NULL && u > maxv) {
83 1
                        VSB_printf(vsb,
84
                            "Must be less than or equal to %s\n", max);
85 1
                        return (-1);
86
                }
87 50600
                *dest = u;
88
        } else
89 48688
                VSB_printf(vsb, fmt, *dest);
90 99288
        return (0);
91
}
92
93
/*--------------------------------------------------------------------*/
94
95
int
96 92959
tweak_timeout(struct vsb *vsb, const struct parspec *par,
97
    const char *arg)
98
{
99
        volatile double *dest;
100
101 92959
        dest = par->priv;
102 92959
        return (tweak_generic_double(vsb, dest, arg,
103
            par->min, par->max, "%.3f"));
104
}
105
106
/*--------------------------------------------------------------------*/
107
108
int
109 4220
tweak_double(struct vsb *vsb, const struct parspec *par, const char *arg)
110
{
111
        volatile double *dest;
112
113 4220
        dest = par->priv;
114 4220
        return (tweak_generic_double(vsb, dest, arg,
115
            par->min, par->max, "%g"));
116
}
117
118
/*--------------------------------------------------------------------*/
119
120
int
121 17445
tweak_bool(struct vsb *vsb, const struct parspec *par, const char *arg)
122
{
123
        volatile unsigned *dest;
124
125 17445
        dest = par->priv;
126 17445
        if (arg != NULL) {
127 9627
                if (!strcasecmp(arg, "off"))
128 2652
                        *dest = 0;
129 6975
                else if (!strcasecmp(arg, "disable"))
130 1
                        *dest = 0;
131 6974
                else if (!strcasecmp(arg, "no"))
132 1
                        *dest = 0;
133 6973
                else if (!strcasecmp(arg, "false"))
134 5
                        *dest = 0;
135 6968
                else if (!strcasecmp(arg, "on"))
136 6945
                        *dest = 1;
137 23
                else if (!strcasecmp(arg, "enable"))
138 1
                        *dest = 1;
139 22
                else if (!strcasecmp(arg, "yes"))
140 1
                        *dest = 1;
141 21
                else if (!strcasecmp(arg, "true"))
142 20
                        *dest = 1;
143
                else {
144 1
                        VSB_printf(vsb, "use \"on\" or \"off\"\n");
145 1
                        return (-1);
146
                }
147
        } else {
148 7818
                VSB_printf(vsb, "%s", *dest ? "on" : "off");
149
        }
150 17444
        return (0);
151
}
152
153
/*--------------------------------------------------------------------*/
154
155
int
156 76704
tweak_generic_uint(struct vsb *vsb, volatile unsigned *dest, const char *arg,
157
    const char *min, const char *max)
158
{
159 76704
        unsigned u, minv = 0, maxv = 0;
160
        char *p;
161
162 76704
        if (arg != NULL) {
163 40718
                if (min != NULL) {
164 32341
                        p = NULL;
165 32341
                        minv = strtoul(min, &p, 0);
166 32341
                        if (*arg == '\0' || *p != '\0') {
167 0
                                VSB_printf(vsb, "Illegal Min: %s\n", min);
168 0
                                return (-1);
169
                        }
170
                }
171 40718
                if (max != NULL) {
172 16104
                        p = NULL;
173 16104
                        maxv = strtoul(max, &p, 0);
174 16104
                        if (*arg == '\0' || *p != '\0') {
175 0
                                VSB_printf(vsb, "Illegal Max: %s\n", max);
176 0
                                return (-1);
177
                        }
178
                }
179 40718
                p = NULL;
180 40718
                if (!strcasecmp(arg, "unlimited"))
181 1
                        u = UINT_MAX;
182
                else {
183 40717
                        u = strtoul(arg, &p, 0);
184 40717
                        if (*arg == '\0' || *p != '\0') {
185 2
                                VSB_printf(vsb, "Not a number (%s)\n", arg);
186 2
                                return (-1);
187
                        }
188
                }
189 40716
                if (min != NULL && u < minv) {
190 2
                        VSB_printf(vsb, "Must be at least %s\n", min);
191 2
                        return (-1);
192
                }
193 40714
                if (max != NULL && u > maxv) {
194 4
                        VSB_printf(vsb, "Must be no more than %s\n", max);
195 4
                        return (-1);
196
                }
197 40710
                *dest = u;
198 35986
        } else if (*dest == UINT_MAX) {
199 3
                VSB_printf(vsb, "unlimited");
200
        } else {
201 35983
                VSB_printf(vsb, "%u", *dest);
202
        }
203 76696
        return (0);
204
}
205
206
/*--------------------------------------------------------------------*/
207
208
int
209 67609
tweak_uint(struct vsb *vsb, const struct parspec *par, const char *arg)
210
{
211
        volatile unsigned *dest;
212
213 67609
        dest = par->priv;
214 67609
        return (tweak_generic_uint(vsb, dest, arg, par->min, par->max));
215
}
216
217
/*--------------------------------------------------------------------*/
218
219
static void
220 33155
fmt_bytes(struct vsb *vsb, uintmax_t t)
221
{
222
        const char *p;
223
224 33155
        if (t == 0 || t & 0xff) {
225 7741
                VSB_printf(vsb, "%jub", t);
226 7741
                return;
227
        }
228 37396
        for (p = "kMGTPEZY"; *p; p++) {
229 37396
                if (t & 0x300) {
230 4228
                        VSB_printf(vsb, "%.2f%c", t / 1024.0, *p);
231 4228
                        return;
232
                }
233 33168
                t /= 1024;
234 33168
                if (t & 0x0ff) {
235 21186
                        VSB_printf(vsb, "%ju%c", t, *p);
236 21186
                        return;
237
                }
238
        }
239 0
        VSB_printf(vsb, "(bogus number)");
240
}
241
242
static int
243 66804
tweak_generic_bytes(struct vsb *vsb, volatile ssize_t *dest, const char *arg,
244
    const char *min, const char *max)
245
{
246 66804
        uintmax_t r, rmin = 0, rmax = 0;
247
        const char *p;
248
249 66804
        if (arg != NULL) {
250 33649
                if (min != NULL) {
251 33649
                        p = VNUM_2bytes(min, &rmin, 0);
252 33649
                        if (p != NULL) {
253 0
                                VSB_printf(vsb, "Invalid min-val: %s\n", min);
254 0
                                return (-1);
255
                        }
256
                }
257 33649
                if (max != NULL) {
258 15377
                        p = VNUM_2bytes(max, &rmax, 0);
259 15377
                        if (p != NULL) {
260 0
                                VSB_printf(vsb, "Invalid max-val: %s\n", max);
261 0
                                return (-1);
262
                        }
263
                }
264 33649
                p = VNUM_2bytes(arg, &r, 0);
265 33649
                if (p != NULL) {
266 2
                        VSB_printf(vsb, "Could not convert to bytes.\n");
267 2
                        VSB_printf(vsb, "%s\n", p);
268 2
                        VSB_printf(vsb,
269
                            "  Try something like '80k' or '120M'\n");
270 2
                        return (-1);
271
                }
272
                if ((uintmax_t)((ssize_t)r) != r) {
273
                        fmt_bytes(vsb, r);
274
                        VSB_printf(vsb,
275
                            " is too large for this architecture.\n");
276
                        return (-1);
277
                }
278 33647
                if (max != NULL && r > rmax) {
279 1
                        VSB_printf(vsb, "Must be no more than %s\n", max);
280 1
                        VSB_printf(vsb, "\n");
281 1
                        return (-1);
282
                }
283 33646
                if (min != NULL && r < rmin) {
284 1
                        VSB_printf(vsb, "Must be at least %s\n", min);
285 1
                        return (-1);
286
                }
287 33645
                *dest = r;
288
        } else {
289 33155
                fmt_bytes(vsb, *dest);
290
        }
291 66800
        return (0);
292
}
293
294
/*--------------------------------------------------------------------*/
295
296
int
297 17522
tweak_bytes(struct vsb *vsb, const struct parspec *par, const char *arg)
298
{
299
        volatile ssize_t *dest;
300
301 17522
        dest = par->priv;
302 17522
        return (tweak_generic_bytes(vsb, dest, arg, par->min, par->max));
303
}
304
305
/*--------------------------------------------------------------------*/
306
307
int
308 39428
tweak_bytes_u(struct vsb *vsb, const struct parspec *par, const char *arg)
309
{
310
        volatile unsigned *d1;
311
        volatile ssize_t dest;
312
313 39428
        d1 = par->priv;
314 39428
        dest = *d1;
315 39428
        if (tweak_generic_bytes(vsb, &dest, arg, par->min, par->max))
316 4
                return (-1);
317 39424
        *d1 = dest;
318 39424
        return (0);
319
}
320
321
/*--------------------------------------------------------------------
322
 * vsl_buffer and vsl_reclen have dependencies.
323
 */
324
325
int
326 2816
tweak_vsl_buffer(struct vsb *vsb, const struct parspec *par, const char *arg)
327
{
328
        volatile unsigned *d1;
329
        volatile ssize_t dest;
330
331 2816
        d1 = par->priv;
332 2816
        dest = *d1;
333 2816
        if (tweak_generic_bytes(vsb, &dest, arg, par->min, par->max))
334 0
                return (-1);
335 2816
        *d1 = dest;
336 2816
        MCF_ParamConf(MCF_MAXIMUM, "vsl_reclen", "%u", *d1 - 12);
337 2816
        MCF_ParamConf(MCF_MAXIMUM, "shm_reclen", "%u", *d1 - 12);
338 2816
        return (0);
339
}
340
341
int
342 7038
tweak_vsl_reclen(struct vsb *vsb, const struct parspec *par, const char *arg)
343
{
344
        volatile unsigned *d1;
345
        volatile ssize_t dest;
346
347 7038
        d1 = par->priv;
348 7038
        dest = *d1;
349 7038
        if (tweak_generic_bytes(vsb, &dest, arg, par->min, par->max))
350 0
                return (-1);
351 7038
        *d1 = dest;
352 7038
        MCF_ParamConf(MCF_MINIMUM, "vsl_buffer", "%u", *d1 + 12);
353 7038
        return (0);
354
}
355
356
/*--------------------------------------------------------------------*/
357
358
int
359 7688
tweak_string(struct vsb *vsb, const struct parspec *par, const char *arg)
360
{
361 7688
        char **p = TRUST_ME(par->priv);
362
363 7688
        AN(p);
364
        /* XXX should have tweak_generic_string */
365 7688
        if (arg == NULL) {
366 3550
                VSB_quote(vsb, *p, -1, 0);
367
        } else {
368 4138
                REPLACE(*p, arg);
369
        }
370 7688
        return (0);
371
}
372
373
/*--------------------------------------------------------------------*/
374
375
int
376 4246
tweak_poolparam(struct vsb *vsb, const struct parspec *par, const char *arg)
377
{
378
        volatile struct poolparam *pp, px;
379
        char **av;
380 4246
        int retval = 0;
381
382 4246
        pp = par->priv;
383 4246
        if (arg == NULL) {
384 2130
                VSB_printf(vsb, "%u,%u,%g",
385
                    pp->min_pool, pp->max_pool, pp->max_age);
386
        } else {
387 2116
                av = VAV_Parse(arg, NULL, ARGV_COMMA);
388
                do {
389 2116
                        if (av[0] != NULL) {
390 1
                                VSB_printf(vsb, "Parse error: %s", av[0]);
391 1
                                retval = -1;
392 1
                                break;
393
                        }
394 2115
                        if (av[1] == NULL || av[2] == NULL || av[3] == NULL) {
395 1
                                VSB_printf(vsb,
396
                                    "Three fields required:"
397
                                    " min_pool, max_pool and max_age\n");
398 1
                                retval = -1;
399 1
                                break;
400
                        }
401 2114
                        px = *pp;
402 2114
                        retval = tweak_generic_uint(vsb, &px.min_pool, av[1],
403
                            par->min, par->max);
404 2114
                        if (retval)
405 1
                                break;
406 2113
                        retval = tweak_generic_uint(vsb, &px.max_pool, av[2],
407
                            par->min, par->max);
408 2113
                        if (retval)
409 1
                                break;
410 2112
                        retval = tweak_generic_double(vsb,
411 2112
                            &px.max_age, av[3], "0", "1e6", "%.0f");
412 2112
                        if (retval)
413 1
                                break;
414 2111
                        if (px.min_pool > px.max_pool) {
415 1
                                VSB_printf(vsb,
416
                                    "min_pool cannot be larger"
417
                                    " than max_pool\n");
418 1
                                retval = -1;
419 1
                                break;
420
                        }
421 2110
                        *pp = px;
422
                } while (0);
423 2116
                VAV_Free(av);
424
        }
425 4246
        return (retval);
426
}