source: bin/varnishd/mgt/mgt_main.c @ b40bdeb

Revision b40bdeb, 15.5 KB checked in by Poul-Henning Kamp <phk@…>, 2 years ago (diff)

Convert the -l argument into two params. For now setting them any
other way than -l does you no good.

  • Property mode set to 100644
Line 
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 * The management process and CLI handling
30 */
31
32#include "config.h"
33
34#include <sys/stat.h>
35#include <sys/utsname.h>
36
37#include <ctype.h>
38#include <fcntl.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <syslog.h>
43#include <time.h>
44#include <unistd.h>
45
46#include "mgt/mgt.h"
47#include "common/heritage.h"
48#include "common/params.h"
49
50#include "hash/hash_slinger.h"
51#include "vav.h"
52#include "vcli.h"
53#include "vcli_common.h"
54#include "vev.h"
55#include "vfil.h"
56#include "vin.h"
57#include "vpf.h"
58#include "vsha256.h"
59#include "vtim.h"
60
61#include "compat/daemon.h"
62
63#ifndef HAVE_SRANDOMDEV
64#include "compat/srandomdev.h"
65#endif
66
67struct heritage         heritage;
68unsigned                d_flag = 0;
69pid_t                   mgt_pid;
70struct vev_base         *mgt_evb;
71int                     exit_status = 0;
72struct vsb              *vident;
73
74static void
75build_vident(void)
76{
77        struct utsname uts;
78
79        vident = VSB_new_auto();
80        AN(vident);
81        if (!uname(&uts)) {
82                VSB_printf(vident, ",%s", uts.sysname);
83                VSB_printf(vident, ",%s", uts.release);
84                VSB_printf(vident, ",%s", uts.machine);
85        }
86}
87
88/*--------------------------------------------------------------------*/
89
90const void *
91pick(const struct choice *cp, const char *which, const char *kind)
92{
93
94        for(; cp->name != NULL; cp++) {
95                if (!strcmp(cp->name, which))
96                        return (cp->ptr);
97        }
98        ARGV_ERR("Unknown %s method \"%s\"\n", kind, which);
99}
100
101/*--------------------------------------------------------------------*/
102
103static unsigned long
104arg_ul(const char *p)
105{
106        char *q;
107        unsigned long ul;
108
109        ul = strtoul(p, &q, 0);
110        if (*q != '\0')
111                ARGV_ERR("Invalid number: \"%s\"\n", p);
112        return (ul);
113}
114
115/*--------------------------------------------------------------------*/
116
117static void
118usage(void)
119{
120#define FMT "    %-28s # %s\n"
121
122        fprintf(stderr, "usage: varnishd [options]\n");
123        fprintf(stderr, FMT, "-a address:port", "HTTP listen address and port");
124        fprintf(stderr, FMT, "-b address:port", "backend address and port");
125        fprintf(stderr, FMT, "", "   -b <hostname_or_IP>");
126        fprintf(stderr, FMT, "", "   -b '<hostname_or_IP>:<port_or_service>'");
127        fprintf(stderr, FMT, "-C", "print VCL code compiled to C language");
128        fprintf(stderr, FMT, "-d", "debug");
129        fprintf(stderr, FMT, "-f file", "VCL script");
130        fprintf(stderr, FMT, "-F", "Run in foreground");
131        fprintf(stderr, FMT, "-h kind[,hashoptions]", "Hash specification");
132        fprintf(stderr, FMT, "", "  -h critbit [default]");
133        fprintf(stderr, FMT, "", "  -h simple_list");
134        fprintf(stderr, FMT, "", "  -h classic");
135        fprintf(stderr, FMT, "", "  -h classic,<buckets>");
136        fprintf(stderr, FMT, "-i identity", "Identity of varnish instance");
137        fprintf(stderr, FMT, "-l shl,free,fill", "Size of shared memory file");
138        fprintf(stderr, FMT, "", "  shl: space for SHL records [80m]");
139        fprintf(stderr, FMT, "", "  free: space for other allocations [1m]");
140        fprintf(stderr, FMT, "", "  fill: prefill new file [+]");
141        fprintf(stderr, FMT, "-M address:port", "Reverse CLI destination.");
142        fprintf(stderr, FMT, "-n dir", "varnishd working directory");
143        fprintf(stderr, FMT, "-P file", "PID file");
144        fprintf(stderr, FMT, "-p param=value", "set parameter");
145        fprintf(stderr, FMT,
146            "-s kind[,storageoptions]", "Backend storage specification");
147        fprintf(stderr, FMT, "", "  -s malloc");
148#ifdef HAVE_LIBUMEM
149        fprintf(stderr, FMT, "", "  -s umem");
150#endif
151        fprintf(stderr, FMT, "", "  -s file  [default: use /tmp]");
152        fprintf(stderr, FMT, "", "  -s file,<dir_or_file>");
153        fprintf(stderr, FMT, "", "  -s file,<dir_or_file>,<size>");
154        fprintf(stderr, FMT, "", "  -s persist{experimenta}");
155        fprintf(stderr, FMT, "",
156            "  -s file,<dir_or_file>,<size>,<granularity>");
157        fprintf(stderr, FMT, "-t", "Default TTL");
158        fprintf(stderr, FMT, "-S secret-file",
159            "Secret file for CLI authentication");
160        fprintf(stderr, FMT, "-T address:port",
161            "Telnet listen address and port");
162        fprintf(stderr, FMT, "-V", "version");
163        fprintf(stderr, FMT, "-w int[,int[,int]]", "Number of worker threads");
164        fprintf(stderr, FMT, "", "  -w <fixed_count>");
165        fprintf(stderr, FMT, "", "  -w min,max");
166        fprintf(stderr, FMT, "", "  -w min,max,timeout [default: -w2,500,300]");
167        fprintf(stderr, FMT, "-u user", "Priviledge separation user id");
168#undef FMT
169        exit(1);
170}
171
172
173/*--------------------------------------------------------------------*/
174
175static void
176tackle_warg(const char *argv)
177{
178        char **av;
179        unsigned int u;
180
181        av = VAV_Parse(argv, NULL, ARGV_COMMA);
182        AN(av);
183
184        if (av[0] != NULL)
185                ARGV_ERR("%s\n", av[0]);
186
187        if (av[1] == NULL)
188                usage();
189
190        u = arg_ul(av[1]);
191        if (u < 1)
192                usage();
193        mgt_param.wthread_max = mgt_param.wthread_min = u;
194
195        if (av[2] != NULL) {
196                u = arg_ul(av[2]);
197                if (u < mgt_param.wthread_min)
198                        usage();
199                mgt_param.wthread_max = u;
200
201                if (av[3] != NULL) {
202                        u = arg_ul(av[3]);
203                        mgt_param.wthread_timeout = u;
204                }
205        }
206        VAV_Free(av);
207}
208
209/*--------------------------------------------------------------------*/
210
211static void
212cli_check(const struct cli *cli)
213{
214        if (cli->result == CLIS_OK) {
215                VSB_clear(cli->sb);
216                return;
217        }
218        AZ(VSB_finish(cli->sb));
219        fprintf(stderr, "Error:\n%s\n", VSB_data(cli->sb));
220        exit (2);
221}
222
223/*--------------------------------------------------------------------
224 * All praise POSIX!  Thanks to our glorious standards there are no
225 * standard way to get a back-trace of the stack, and even if we hack
226 * that together from spit and pieces of string, there is no way no
227 * standard way to translate a pointer to a symbol, which returns anything
228 * usable.  (See for instance FreeBSD PR-134391).
229 *
230 * Attempt to run nm(1) on our binary during startup, hoping it will
231 * give us a usable list of symbols.
232 */
233
234struct symbols {
235        uintptr_t               a;
236        char                    *n;
237        VTAILQ_ENTRY(symbols)   list;
238};
239
240static VTAILQ_HEAD(,symbols) symbols = VTAILQ_HEAD_INITIALIZER(symbols);
241
242int
243Symbol_Lookup(struct vsb *vsb, void *ptr)
244{
245        struct symbols *s, *s0;
246        uintptr_t pp;
247
248        pp = (uintptr_t)ptr;
249        s0 = NULL;
250        VTAILQ_FOREACH(s, &symbols, list) {
251                if (s->a > pp)
252                        continue;
253                if (s0 == NULL || s->a > s0->a)
254                        s0 = s;
255        }
256        if (s0 == NULL)
257                return (-1);
258        VSB_printf(vsb, "%p: %s+%jx", ptr, s0->n, (uintmax_t)pp - s0->a);
259        return (0);
260}
261
262static void
263Symbol_hack(const char *a0)
264{
265        char buf[BUFSIZ], *p, *e;
266        FILE *fi;
267        uintptr_t a;
268        struct symbols *s;
269
270        bprintf(buf, "nm -an %s 2>/dev/null", a0);
271        fi = popen(buf, "r");
272        if (fi == NULL)
273                return;
274        while (fgets(buf, sizeof buf, fi)) {
275                if (buf[0] == ' ')
276                        continue;
277                p = NULL;
278                a = strtoul(buf, &p, 16);
279                if (p == NULL)
280                        continue;
281                if (a == 0)
282                        continue;
283                if (*p++ != ' ')
284                        continue;
285                p++;
286                if (*p++ != ' ')
287                        continue;
288                if (*p <= ' ')
289                        continue;
290                e = strchr(p, '\0');
291                AN(e);
292                while (e > p && isspace(e[-1]))
293                        e--;
294                *e = '\0';
295                s = malloc(sizeof *s + strlen(p) + 1);
296                AN(s);
297                s->a = a;
298                s->n = (void*)(s + 1);
299                strcpy(s->n, p);
300                VTAILQ_INSERT_TAIL(&symbols, s, list);
301        }
302        (void)pclose(fi);
303}
304
305/*--------------------------------------------------------------------
306 * This function is called when the CLI on stdin is closed.
307 */
308
309static void
310cli_stdin_close(void *priv)
311{
312
313        (void)priv;
314        (void)close(0);
315        (void)close(1);
316        (void)close(2);
317        assert(open("/dev/null", O_RDONLY) == 0);
318        assert(open("/dev/null", O_WRONLY) == 1);
319        assert(open("/dev/null", O_WRONLY) == 2);
320
321        if (d_flag) {
322                mgt_stop_child();
323                mgt_cli_close_all();
324                exit(0);
325        }
326}
327
328/*--------------------------------------------------------------------*/
329
330int
331main(int argc, char * const *argv)
332{
333        int o;
334        unsigned C_flag = 0;
335        unsigned F_flag = 0;
336        const char *b_arg = NULL;
337        const char *f_arg = NULL;
338        const char *i_arg = NULL;
339        const char *h_arg = "critbit";
340        const char *M_arg = NULL;
341        const char *n_arg = NULL;
342        const char *P_arg = NULL;
343        const char *S_arg = NULL;
344        const char *s_arg = "file";
345        int s_arg_given = 0;
346        const char *T_arg = NULL;
347        char *p, *vcl = NULL;
348        struct cli cli[1];
349        struct vpf_fh *pfh = NULL;
350        char *dirname;
351        char **av;
352        unsigned clilim;
353
354        /*
355         * Start out by closing all unwanted file descriptors we might
356         * have inherited from sloppy process control daemons.
357         */
358        for (o = getdtablesize(); o > STDERR_FILENO; o--)
359                (void)close(o);
360
361        srandomdev();
362
363        mgt_got_fd(STDERR_FILENO);
364
365        setbuf(stdout, NULL);
366        setbuf(stderr, NULL);
367
368        build_vident();
369
370        Symbol_hack(argv[0]);
371
372        /* for ASSERT_MGT() */
373        mgt_pid = getpid();
374
375        /*
376         * Run in UTC timezone, on the off-chance that this operating
377         * system does not have a timegm() function, and translates
378         * timestamps on the local timescale.
379         * See lib/libvarnish/time.c
380         */
381        AZ(setenv("TZ", "UTC", 1));
382        tzset();
383        assert(VTIM_parse("Sun, 06 Nov 1994 08:49:37 GMT") == 784111777);
384        assert(VTIM_parse("Sunday, 06-Nov-94 08:49:37 GMT") == 784111777);
385        assert(VTIM_parse("Sun Nov  6 08:49:37 1994") == 784111777);
386
387        /*
388         * Check that our SHA256 works
389         */
390        SHA256_Test();
391
392        memset(cli, 0, sizeof cli);
393        cli[0].magic = CLI_MAGIC;
394        cli[0].sb = VSB_new_auto();
395        XXXAN(cli[0].sb);
396        cli[0].result = CLIS_OK;
397        clilim = 32768;
398        cli[0].limit = &clilim;
399
400        VTAILQ_INIT(&heritage.socks);
401
402        MCF_ParamInit(cli);
403
404        if (sizeof(void *) < 8) {
405                /*
406                 * Adjust default parameters for 32 bit systems to conserve
407                 * VM space.
408                 */
409                MCF_ParamSet(cli, "sess_workspace", "16384");
410                cli_check(cli);
411
412                MCF_ParamSet(cli, "thread_pool_workspace", "16384");
413                cli_check(cli);
414
415                MCF_ParamSet(cli, "http_resp_size", "8192");
416                cli_check(cli);
417
418                MCF_ParamSet(cli, "http_req_size", "12288");
419                cli_check(cli);
420
421                MCF_ParamSet(cli, "thread_pool_stack", "32bit");
422                cli_check(cli);
423
424                MCF_ParamSet(cli, "gzip_stack_buffer", "4096");
425                cli_check(cli);
426        }
427
428        cli_check(cli);
429
430        while ((o = getopt(argc, argv,
431            "a:b:Cdf:Fg:h:i:l:L:M:n:P:p:S:s:T:t:u:Vx:w:")) != -1)
432                switch (o) {
433                case 'a':
434                        MCF_ParamSet(cli, "listen_address", optarg);
435                        cli_check(cli);
436                        break;
437                case 'b':
438                        b_arg = optarg;
439                        break;
440                case 'C':
441                        C_flag = 1 - C_flag;
442                        break;
443                case 'd':
444                        d_flag++;
445                        break;
446                case 'f':
447                        f_arg = optarg;
448                        break;
449                case 'F':
450                        F_flag = 1 - F_flag;
451                        break;
452                case 'g':
453                        MCF_ParamSet(cli, "group", optarg);
454                        break;
455                case 'h':
456                        h_arg = optarg;
457                        break;
458                case 'i':
459                        i_arg = optarg;
460                        break;
461                case 'l':
462                        av = VAV_Parse(optarg, NULL, ARGV_COMMA);
463                        AN(av);
464                        if (av[0] != NULL)
465                                ARGV_ERR("\t-l ...: %s", av[0]);
466                        if (av[1] != NULL) {
467                                MCF_ParamSet(cli, "vsl_space", av[1]);
468                                cli_check(cli);
469                        }
470                        if (av[1] != NULL && av[2] != NULL) {
471                                MCF_ParamSet(cli, "vsm_space", av[2]);
472                                cli_check(cli);
473                        }
474                        VAV_Free(av);
475                        break;
476                case 'M':
477                        M_arg = optarg;
478                        break;
479                case 'n':
480                        n_arg = optarg;
481                        break;
482                case 'P':
483                        P_arg = optarg;
484                        break;
485                case 'p':
486                        p = strchr(optarg, '=');
487                        if (p == NULL)
488                                usage();
489                        AN(p);
490                        *p++ = '\0';
491                        MCF_ParamSet(cli, optarg, p);
492                        cli_check(cli);
493                        break;
494                case 's':
495                        s_arg_given = 1;
496                        STV_Config(optarg);
497                        break;
498                case 't':
499                        MCF_ParamSet(cli, "default_ttl", optarg);
500                        break;
501                case 'S':
502                        S_arg = optarg;
503                        break;
504                case 'T':
505                        T_arg = optarg;
506                        break;
507                case 'u':
508                        MCF_ParamSet(cli, "user", optarg);
509                        break;
510                case 'V':
511                        /* XXX: we should print the ident here */
512                        VCS_Message("varnishd");
513                        exit(0);
514                case 'x':
515                        if (!strcmp(optarg, "dumprst")) {
516                                MCF_DumpRst();
517                                exit (0);
518                        }
519                        usage();
520                        break;
521                case 'w':
522                        tackle_warg(optarg);
523                        break;
524                default:
525                        usage();
526                }
527
528        argc -= optind;
529        argv += optind;
530
531        mgt_vcc_init();
532
533        if (argc != 0) {
534                fprintf(stderr, "Too many arguments (%s...)\n", argv[0]);
535                usage();
536        }
537
538        /* XXX: we can have multiple CLI actions above, is this enough ? */
539        if (cli[0].result != CLIS_OK) {
540                fprintf(stderr, "Parameter errors:\n");
541                AZ(VSB_finish(cli[0].sb));
542                fprintf(stderr, "%s\n", VSB_data(cli[0].sb));
543                exit(1);
544        }
545
546        if (d_flag && F_flag) {
547                fprintf(stderr, "Only one of -d or -F can be specified\n");
548                usage();
549        }
550
551        if (b_arg != NULL && f_arg != NULL) {
552                fprintf(stderr, "Only one of -b or -f can be specified\n");
553                usage();
554        }
555        if (S_arg == NULL && T_arg == NULL && d_flag == 0 && b_arg == NULL &&
556            f_arg == NULL && M_arg == NULL) {
557                fprintf(stderr,
558                    "At least one of -d, -b, -f, -M, -S or -T "
559                    "must be specified\n");
560                usage();
561        }
562
563        if (f_arg != NULL) {
564                vcl = VFIL_readfile(NULL, f_arg, NULL);
565                if (vcl == NULL) {
566                        fprintf(stderr, "Cannot read '%s': %s\n",
567                            f_arg, strerror(errno));
568                        exit(1);
569                }
570        }
571
572        if (VIN_N_Arg(n_arg, &heritage.name, &dirname, NULL) != 0) {
573                fprintf(stderr, "Invalid instance name: %s\n",
574                    strerror(errno));
575                exit(1);
576        }
577
578        if (i_arg != NULL) {
579                if (snprintf(heritage.identity, sizeof heritage.identity,
580                    "%s", i_arg) > sizeof heritage.identity) {
581                        fprintf(stderr, "Invalid identity name: %s\n",
582                            strerror(ENAMETOOLONG));
583                        exit(1);
584                }
585        }
586
587        if (n_arg != NULL)
588                openlog(n_arg, LOG_PID, LOG_LOCAL0);
589        else
590                openlog("varnishd", LOG_PID, LOG_LOCAL0);
591
592        if (mkdir(dirname, 0755) < 0 && errno != EEXIST) {
593                fprintf(stderr, "Cannot create working directory '%s': %s\n",
594                    dirname, strerror(errno));
595                exit(1);
596        }
597
598        if (chdir(dirname) < 0) {
599                fprintf(stderr, "Cannot change to working directory '%s': %s\n",
600                    dirname, strerror(errno));
601                exit(1);
602        }
603
604        /* XXX: should this be relative to the -n arg ? */
605        if (P_arg && (pfh = VPF_Open(P_arg, 0644, NULL)) == NULL) {
606                perror(P_arg);
607                exit(1);
608        }
609
610        if (b_arg != NULL || f_arg != NULL)
611                if (mgt_vcc_default(b_arg, f_arg, vcl, C_flag))
612                        exit (2);
613
614        if (C_flag)
615                exit (0);
616
617        /* If no -s argument specified, process default -s argument */
618        if (!s_arg_given)
619                STV_Config(s_arg);
620
621        /* Configure Transient storage, if user did not */
622        STV_Config_Transient();
623
624        HSH_config(h_arg);
625
626        mgt_SHM_Init();
627
628        AZ(VSB_finish(vident));
629
630        if (!d_flag && !F_flag)
631                AZ(varnish_daemon(1, 0));
632
633        mgt_SHM_Pid();
634
635        if (pfh != NULL && VPF_Write(pfh))
636                fprintf(stderr, "NOTE: Could not write PID file\n");
637
638        if (d_flag)
639                fprintf(stderr, "Platform: %s\n", VSB_data(vident) + 1);
640        syslog(LOG_NOTICE, "Platform: %s\n", VSB_data(vident) + 1);
641
642        /* Do this again after debugstunt and daemon has run */
643        mgt_pid = getpid();
644
645        mgt_evb = vev_new_base();
646        XXXAN(mgt_evb);
647
648        if (d_flag)
649                mgt_cli_setup(0, 1, 1, "debug", cli_stdin_close, NULL);
650        if (S_arg != NULL)
651                mgt_cli_secret(S_arg);
652        if (M_arg != NULL)
653                mgt_cli_master(M_arg);
654        if (T_arg != NULL)
655                mgt_cli_telnet(T_arg);
656
657        AN(VSM_Alloc(0, VSM_CLASS_MARK, "", ""));
658
659        MGT_Run();
660
661        if (pfh != NULL)
662                (void)VPF_Remove(pfh);
663        exit(exit_status);
664}
665
666#if defined(PTHREAD_CANCELED) || defined(PTHREAD_MUTEX_DEFAULT)
667#error "Keep pthreads out of in manager process"
668#endif
Note: See TracBrowser for help on using the repository browser.