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 2267406
tweak_generic_double(struct vsb *vsb, volatile double *dest,
54
    const char *arg, const char *min, const char *max, const char *fmt)
55
{
56 2267406
        volatile double u, minv = 0, maxv = 0;
57
58 2267406
        if (arg != NULL && arg != JSON_FMT) {
59 1152918
                if (min != NULL) {
60 1152918
                        minv = VNUM(min);
61 1152918
                        if (isnan(minv)) {
62 0
                                VSB_printf(vsb, "Illegal Min: %s\n", min);
63 0
                                return (-1);
64
                        }
65 1152918
                }
66 1152918
                if (max != NULL) {
67 354366
                        maxv = VNUM(max);
68 354366
                        if (isnan(maxv)) {
69 0
                                VSB_printf(vsb, "Illegal Max: %s\n", max);
70 0
                                return (-1);
71
                        }
72 354366
                }
73
74 1152918
                u = VNUM(arg);
75 1152918
                if (isnan(u)) {
76 18
                        VSB_printf(vsb, "Not a number(%s)\n", arg);
77 18
                        return (-1);
78
                }
79 1152900
                if (min != NULL && u < minv) {
80 36
                        VSB_printf(vsb,
81 18
                            "Must be greater or equal to %s\n", min);
82 18
                        return (-1);
83
                }
84 1152882
                if (max != NULL && u > maxv) {
85 36
                        VSB_printf(vsb,
86 18
                            "Must be less than or equal to %s\n", max);
87 18
                        return (-1);
88
                }
89 1152864
                *dest = u;
90 1152864
        } else
91 1114488
                VSB_printf(vsb, fmt, *dest);
92 2267352
        return (0);
93 2267406
}
94
95
/*--------------------------------------------------------------------*/
96
97
int
98 2134242
tweak_timeout(struct vsb *vsb, const struct parspec *par,
99
    const char *arg)
100
{
101
        volatile double *dest;
102
103 2134242
        dest = par->priv;
104 4268484
        return (tweak_generic_double(vsb, dest, arg,
105 2134242
            par->min, par->max, "%.3f"));
106
}
107
108
/*--------------------------------------------------------------------*/
109
110
int
111 88776
tweak_double(struct vsb *vsb, const struct parspec *par, const char *arg)
112
{
113
        volatile double *dest;
114
115 88776
        dest = par->priv;
116 177552
        return (tweak_generic_double(vsb, dest, arg,
117 88776
            par->min, par->max, "%g"));
118
}
119
120
/*--------------------------------------------------------------------*/
121
122
int
123 368298
tweak_bool(struct vsb *vsb, const struct parspec *par, const char *arg)
124
{
125
        volatile unsigned *dest;
126
127 368298
        dest = par->priv;
128 368298
        if (arg != NULL && arg != JSON_FMT) {
129 203346
                if (!strcasecmp(arg, "off"))
130 56430
                        *dest = 0;
131 146916
                else if (!strcasecmp(arg, "disable"))
132 18
                        *dest = 0;
133 146898
                else if (!strcasecmp(arg, "no"))
134 18
                        *dest = 0;
135 146880
                else if (!strcasecmp(arg, "false"))
136 126
                        *dest = 0;
137 146754
                else if (!strcasecmp(arg, "on"))
138 146322
                        *dest = 1;
139 432
                else if (!strcasecmp(arg, "enable"))
140 18
                        *dest = 1;
141 414
                else if (!strcasecmp(arg, "yes"))
142 18
                        *dest = 1;
143 396
                else if (!strcasecmp(arg, "true"))
144 378
                        *dest = 1;
145
                else {
146 18
                        VSB_printf(vsb, "use \"on\" or \"off\"\n");
147 18
                        return (-1);
148
                }
149 368280
        } else if (arg == JSON_FMT) {
150 432
                VSB_printf(vsb, "%s", *dest ? "true" : "false");
151 432
        } else {
152 164520
                VSB_printf(vsb, "%s", *dest ? "on" : "off");
153
        }
154 368280
        return (0);
155 368298
}
156
157
/*--------------------------------------------------------------------*/
158
159
int
160 1881216
tweak_generic_uint(struct vsb *vsb, volatile unsigned *dest, const char *arg,
161
    const char *min, const char *max)
162
{
163 1881216
        unsigned u, minv = 0, maxv = 0;
164
        char *p;
165
166 1881216
        if (arg != NULL && arg != JSON_FMT) {
167 989784
                if (min != NULL) {
168 813348
                        p = NULL;
169 813348
                        minv = strtoul(min, &p, 0);
170 813348
                        if (*arg == '\0' || *p != '\0') {
171 0
                                VSB_printf(vsb, "Illegal Min: %s\n", min);
172 0
                                return (-1);
173
                        }
174 813348
                }
175 989784
                if (max != NULL) {
176 383580
                        p = NULL;
177 383580
                        maxv = strtoul(max, &p, 0);
178 383580
                        if (*arg == '\0' || *p != '\0') {
179 0
                                VSB_printf(vsb, "Illegal Max: %s\n", max);
180 0
                                return (-1);
181
                        }
182 383580
                }
183 989784
                p = NULL;
184 989784
                if (!strcasecmp(arg, "unlimited"))
185 18
                        u = UINT_MAX;
186
                else {
187 989766
                        u = strtoul(arg, &p, 0);
188 989766
                        if (*arg == '\0' || *p != '\0') {
189 36
                                VSB_printf(vsb, "Not a number (%s)\n", arg);
190 36
                                return (-1);
191
                        }
192
                }
193 989748
                if (min != NULL && u < minv) {
194 36
                        VSB_printf(vsb, "Must be at least %s\n", min);
195 36
                        return (-1);
196
                }
197 989712
                if (max != NULL && u > maxv) {
198 72
                        VSB_printf(vsb, "Must be no more than %s\n", max);
199 72
                        return (-1);
200
                }
201 989640
                *dest = u;
202 1881072
        } else if (*dest == UINT_MAX && arg != JSON_FMT) {
203 90
                VSB_printf(vsb, "unlimited");
204 90
        } else {
205 891342
                VSB_printf(vsb, "%u", *dest);
206
        }
207 1881072
        return (0);
208 1881216
}
209
210
/*--------------------------------------------------------------------*/
211
212
int
213 1689588
tweak_uint(struct vsb *vsb, const struct parspec *par, const char *arg)
214
{
215
        volatile unsigned *dest;
216
217 1689588
        dest = par->priv;
218 1689588
        return (tweak_generic_uint(vsb, dest, arg, par->min, par->max));
219
}
220
221
/*--------------------------------------------------------------------*/
222
223
static void
224 815940
fmt_bytes(struct vsb *vsb, uintmax_t t)
225
{
226
        const char *p;
227
228 815940
        if (t == 0 || t & 0xff) {
229 236736
                VSB_printf(vsb, "%jub", t);
230 236736
                return;
231
        }
232 831204
        for (p = "kMGTPEZY"; *p; p++) {
233 831204
                if (t & 0x300) {
234 88920
                        VSB_printf(vsb, "%.2f%c", t / 1024.0, *p);
235 88920
                        return;
236
                }
237 742284
                t /= 1024;
238 742284
                if (t & 0x0ff) {
239 490284
                        VSB_printf(vsb, "%ju%c", t, *p);
240 490284
                        return;
241
                }
242 252000
        }
243 0
        VSB_printf(vsb, "(bogus number)");
244 815940
}
245
246
static int
247 1642572
tweak_generic_bytes(struct vsb *vsb, volatile ssize_t *dest, const char *arg,
248
    const char *min, const char *max)
249
{
250 1642572
        uintmax_t r, rmin = 0, rmax = 0;
251
        const char *p;
252
253 1642572
        if (arg != NULL && arg != JSON_FMT) {
254 825804
                if (min != NULL) {
255 825804
                        p = VNUM_2bytes(min, &rmin, 0);
256 825804
                        if (p != NULL) {
257 0
                                VSB_printf(vsb, "Invalid min-val: %s\n", min);
258 0
                                return (-1);
259
                        }
260 825804
                }
261 825804
                if (max != NULL) {
262 412146
                        p = VNUM_2bytes(max, &rmax, 0);
263 412146
                        if (p != NULL) {
264 0
                                VSB_printf(vsb, "Invalid max-val: %s\n", max);
265 0
                                return (-1);
266
                        }
267 412146
                }
268 825804
                p = VNUM_2bytes(arg, &r, 0);
269 825804
                if (p != NULL) {
270 36
                        VSB_printf(vsb, "Could not convert to bytes.\n");
271 36
                        VSB_printf(vsb, "%s\n", p);
272 36
                        VSB_printf(vsb,
273
                            "  Try something like '80k' or '120M'\n");
274 36
                        return (-1);
275
                }
276 825768
                if ((uintmax_t)((ssize_t)r) != r) {
277 0
                        fmt_bytes(vsb, r);
278 0
                        VSB_printf(vsb,
279
                            " is too large for this architecture.\n");
280 0
                        return (-1);
281
                }
282 825768
                if (max != NULL && r > rmax) {
283 18
                        VSB_printf(vsb, "Must be no more than %s\n", max);
284 18
                        VSB_printf(vsb, "\n");
285 18
                        return (-1);
286
                }
287 825750
                if (min != NULL && r < rmin) {
288 18
                        VSB_printf(vsb, "Must be at least %s\n", min);
289 18
                        return (-1);
290
                }
291 825732
                *dest = r;
292 1642500
        } else if (arg == JSON_FMT) {
293 828
                VSB_printf(vsb, "%zd", *dest);
294 828
        } else {
295 815940
                fmt_bytes(vsb, *dest);
296
        }
297 1642500
        return (0);
298 1642572
}
299
300
/*--------------------------------------------------------------------*/
301
302
int
303 368928
tweak_bytes(struct vsb *vsb, const struct parspec *par, const char *arg)
304
{
305
        volatile ssize_t *dest;
306
307 368928
        dest = par->priv;
308 368928
        return (tweak_generic_bytes(vsb, dest, arg, par->min, par->max));
309
}
310
311
/*--------------------------------------------------------------------*/
312
313
int
314 1125612
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 1125612
        d1 = par->priv;
320 1125612
        dest = *d1;
321 1125612
        if (tweak_generic_bytes(vsb, &dest, arg, par->min, par->max))
322 72
                return (-1);
323 1125540
        *d1 = dest;
324 1125540
        return (0);
325 1125612
}
326
327
/*--------------------------------------------------------------------
328
 * vsl_buffer and vsl_reclen have dependencies.
329
 */
330
331
int
332 59256
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 59256
        d1 = par->priv;
338 59256
        dest = *d1;
339 59256
        if (tweak_generic_bytes(vsb, &dest, arg, par->min, par->max))
340 0
                return (-1);
341 59256
        *d1 = dest;
342 59256
        MCF_ParamConf(MCF_MAXIMUM, "vsl_reclen", "%u", *d1 - 12);
343 59256
        return (0);
344 59256
}
345
346
int
347 88776
tweak_vsl_reclen(struct vsb *vsb, const struct parspec *par, const char *arg)
348
{
349
        volatile unsigned *d1;
350
        volatile ssize_t dest;
351
352 88776
        d1 = par->priv;
353 88776
        dest = *d1;
354 88776
        if (tweak_generic_bytes(vsb, &dest, arg, par->min, par->max))
355 0
                return (-1);
356 88776
        *d1 = dest;
357 88776
        MCF_ParamConf(MCF_MINIMUM, "vsl_buffer", "%u", *d1 + 12);
358 88776
        return (0);
359 88776
}
360
361
/*--------------------------------------------------------------------*/
362
363
int
364 102726
tweak_string(struct vsb *vsb, const struct parspec *par, const char *arg)
365
{
366 102726
        char **p = TRUST_ME(par->priv);
367
368 102726
        AN(p);
369
        /* XXX should have tweak_generic_string */
370 102726
        if (arg == NULL) {
371 44820
                VSB_quote(vsb, *p, -1, 0);
372 102726
        } else if (arg == JSON_FMT) {
373 108
                VSB_quote(vsb, *p, -1, VSB_QUOTE_JSON|VSB_QUOTE_CSTR);
374 108
        } else {
375 57798
                REPLACE(*p, arg);
376
        }
377 102726
        return (0);
378
}
379
380
/*--------------------------------------------------------------------*/
381
382
int
383 89460
tweak_poolparam(struct vsb *vsb, const struct parspec *par, const char *arg)
384
{
385
        volatile struct poolparam *pp, px;
386
        char **av;
387 89460
        int retval = 0;
388
389 89460
        pp = par->priv;
390 89460
        if (arg == JSON_FMT) {
391 144
                VSB_printf(vsb, "{\n");
392 144
                VSB_indent(vsb, 8);
393 144
                VSB_printf(vsb, "\"min_pool\": %u,\n", pp->min_pool);
394 144
                VSB_printf(vsb, "\"max_pool\": %u,\n", pp->max_pool);
395 144
                VSB_printf(vsb, "\"max_age\": %g\n", pp->max_age);
396 144
                VSB_indent(vsb, -4);
397 144
                VSB_printf(vsb, "}");
398 89460
        } else if (arg == NULL) {
399 89712
                VSB_printf(vsb, "%u,%u,%g",
400 44856
                    pp->min_pool, pp->max_pool, pp->max_age);
401 44856
        } else {
402 44460
                av = VAV_Parse(arg, NULL, ARGV_COMMA);
403 44460
                do {
404 44460
                        if (av[0] != NULL) {
405 18
                                VSB_printf(vsb, "Parse error: %s", av[0]);
406 18
                                retval = -1;
407 18
                                break;
408
                        }
409 44442
                        if (av[1] == NULL || av[2] == NULL || av[3] == NULL) {
410 18
                                VSB_printf(vsb,
411
                                    "Three fields required:"
412
                                    " min_pool, max_pool and max_age\n");
413 18
                                retval = -1;
414 18
                                break;
415
                        }
416 44424
                        px = *pp;
417 88848
                        retval = tweak_generic_uint(vsb, &px.min_pool, av[1],
418 44424
                            par->min, par->max);
419 44424
                        if (retval)
420 18
                                break;
421 88812
                        retval = tweak_generic_uint(vsb, &px.max_pool, av[2],
422 44406
                            par->min, par->max);
423 44406
                        if (retval)
424 18
                                break;
425 88776
                        retval = tweak_generic_double(vsb,
426 44388
                            &px.max_age, av[3], "0", "1e6", "%.0f");
427 44388
                        if (retval)
428 18
                                break;
429 44370
                        if (px.min_pool > px.max_pool) {
430 18
                                VSB_printf(vsb,
431
                                    "min_pool cannot be larger"
432
                                    " than max_pool\n");
433 18
                                retval = -1;
434 18
                                break;
435
                        }
436 44352
                        *pp = px;
437 44352
                } while (0);
438 44460
                VAV_Free(av);
439
        }
440 89460
        return (retval);
441
}