vinyl-cache/bin/vinyltest/vtest2/src/vtc_haproxy.c
0
/*-
1
 * Copyright (c) 2008-2018 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Frédéric Lécaille <flecaille@haproxy.com>
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
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
30
#include "config.h"
31
32
#include <inttypes.h>
33
#include <poll.h>
34
#include <stdio.h>
35
#include <stdlib.h>
36
#include <string.h>
37
#include <sys/stat.h> /* for MUSL (mode_t) */
38
#include <sys/socket.h>
39
#include <sys/un.h>
40
#include <unistd.h>
41
42
#include "vtc.h"
43
44
#include "vfil.h"
45
#include "vpf.h"
46
#include "vre.h"
47
#include "vtcp.h"
48
#include "vsa.h"
49
#include "vtim.h"
50
#include "vudp.h"
51
52
#define HAPROXY_PROGRAM_ENV_VAR "HAPROXY_PROGRAM"
53
#define HAPROXY_ARGS_ENV_VAR    "HAPROXY_ARGS"
54
#define HAPROXY_OPT_WORKER      "-W"
55
#define HAPROXY_OPT_SD_WORKER   "-Ws"
56
#define HAPROXY_OPT_MCLI        "-S"
57
#define HAPROXY_OPT_DAEMON      "-D"
58
#define HAPROXY_SIGNAL          SIGINT
59
#define HAPROXY_EXPECT_EXIT     (128 + HAPROXY_SIGNAL)
60
61
struct envar {
62
        VTAILQ_ENTRY(envar) list;
63
        char *name;
64
        char *value;
65
};
66
67
struct haproxy {
68
        unsigned                magic;
69
#define HAPROXY_MAGIC           0x8a45cf75
70
        char                    *name;
71
        struct vtclog           *vl;
72
        VTAILQ_ENTRY(haproxy)   list;
73
74
        const char              *filename;
75
        struct vsb              *args;
76
        int                     opt_worker;
77
        int                     opt_mcli;
78
        int                     opt_daemon;
79
        int                     opt_check_mode;
80
        char                    *pid_fn;
81
        pid_t                   pid;
82
        pid_t                   ppid;
83
        int                     fds[4];
84
        char                    *cfg_fn;
85
        struct vsb              *cfg_vsb;
86
87
        pthread_t               tp;
88
        int                     expect_exit;
89
        int                     expect_signal;
90
        int                     its_dead_jim;
91
92
        /* sd_notify unix socket */
93
        struct sockaddr_un      sd_uds;
94
        int                     sd_sock;
95
96
        /* UNIX socket CLI. */
97
        char                    *cli_fn;
98
        /* TCP socket CLI. */
99
        struct haproxy_cli *cli;
100
101
        /* master CLI */
102
        struct haproxy_cli *mcli;
103
104
        char                    *workdir;
105
        struct vsb              *msgs;
106
        char                    closed_sock[256]; /* Closed TCP socket */
107
        VTAILQ_HEAD(,envar) envars;
108
};
109
110
static VTAILQ_HEAD(, haproxy)   haproxies =
111
    VTAILQ_HEAD_INITIALIZER(haproxies);
112
113
struct haproxy_cli {
114
        unsigned                magic;
115
#define HAPROXY_CLI_MAGIC       0xb09a4ed8
116
        struct vtclog           *vl;
117
        char                    running;
118
119
        char                    *spec;
120
121
        int                     sock;
122
        char                    connect[256];
123
124
        pthread_t               tp;
125
        size_t                  txbuf_sz;
126
        char                    *txbuf;
127
        size_t                  rxbuf_sz;
128
        char                    *rxbuf;
129
130
        vtim_dur                timeout;
131
};
132
133
static void haproxy_write_conf(struct haproxy *h);
134
135
static void
136 105
haproxy_add_envar(struct haproxy *h,
137
                  const char *name, const char *value)
138
{
139
        struct envar *e;
140
141 105
        e = malloc(sizeof *e);
142 105
        AN(e);
143 105
        e->name = strdup(name);
144 105
        e->value = strdup(value);
145 105
        AN(e->name);
146 105
        AN(e->value);
147 105
        VTAILQ_INSERT_TAIL(&h->envars, e, list);
148 105
}
149
150
static void
151 60
haproxy_delete_envars(struct haproxy *h)
152
{
153
        struct envar *e, *e2;
154 165
        VTAILQ_FOREACH_SAFE(e, &h->envars, list, e2) {
155 105
                VTAILQ_REMOVE(&h->envars, e, list);
156 105
                free(e->name);
157 105
                free(e->value);
158 105
                free(e);
159 105
        }
160 60
}
161
162
static void
163 60
haproxy_build_env(const struct haproxy *h)
164
{
165
        struct envar *e;
166
167 165
        VTAILQ_FOREACH(e, &h->envars, list) {
168 105
                if (setenv(e->name, e->value, 0) == -1)
169 0
                        vtc_fatal(h->vl, "setenv() failed: %s (%d)",
170 0
                                  strerror(errno), errno);
171 105
        }
172 60
}
173
174
/**********************************************************************
175
 * Socket connect (same as client_tcp_connect()).
176
 */
177
178
static int
179 15
haproxy_cli_tcp_connect(struct vtclog *vl, const char *addr, vtim_dur tmo,
180
    const char **errp)
181
{
182
        int fd;
183
        char mabuf[VTCP_ADDRBUFSIZE], mpbuf[VTCP_PORTBUFSIZE];
184
185 15
        AN(addr);
186 15
        AN(errp);
187 15
        fd = VTCP_open(addr, NULL, tmo, errp);
188 15
        if (fd < 0)
189 0
                return (fd);
190 15
        VTCP_myname(fd, mabuf, sizeof mabuf, mpbuf, sizeof mpbuf);
191 30
        vtc_log(vl, 3,
192 15
            "CLI connected fd %d from %s %s to %s", fd, mabuf, mpbuf, addr);
193 15
        return (fd);
194 15
}
195
196
/*
197
 * SECTION: haproxy.cli haproxy CLI Specification
198
 * SECTION: haproxy.cli.send
199
 * send STRING
200
 *         Push STRING on the CLI connection. STRING will be terminated by an
201
 *         end of line character (\n).
202
 */
203
static void v_matchproto_(cmd_f)
204 15
cmd_haproxy_cli_send(CMD_ARGS)
205
{
206
        struct vsb *vsb;
207
        struct haproxy_cli *hc;
208
        int j;
209
210 15
        (void)vl;
211 15
        CAST_OBJ_NOTNULL(hc, priv, HAPROXY_CLI_MAGIC);
212 15
        AZ(strcmp(av[0], "send"));
213 15
        AN(av[1]);
214 15
        AZ(av[2]);
215
216 15
        vsb = VSB_new_auto();
217 15
        AN(vsb);
218 15
        AZ(VSB_cat(vsb, av[1]));
219 15
        AZ(VSB_cat(vsb, "\n"));
220 15
        AZ(VSB_finish(vsb));
221 15
        if (hc->sock == -1) {
222
                int fd;
223
                const char *err;
224
                struct vsb *vsb_connect;
225
226 0
                vsb_connect = macro_expand(hc->vl, hc->connect);
227 0
                AN(vsb_connect);
228 0
                fd = haproxy_cli_tcp_connect(hc->vl,
229 0
                    VSB_data(vsb_connect), 10., &err);
230 0
                if (fd < 0)
231 0
                        vtc_fatal(hc->vl,
232 0
                            "CLI failed to open %s: %s", VSB_data(vsb), err);
233 0
                VSB_destroy(&vsb_connect);
234 0
                hc->sock = fd;
235 0
        }
236 15
        vtc_dump(hc->vl, 4, "CLI send", VSB_data(vsb), -1);
237
238 15
        if (VSB_tofile(vsb, hc->sock))
239 0
                vtc_fatal(hc->vl,
240 0
                    "CLI fd %d send error %s", hc->sock, strerror(errno));
241
242
        /* a CLI command must be followed by a SHUT_WR if we want HAProxy to
243
         * close after the response */
244 15
        j = shutdown(hc->sock, SHUT_WR);
245 15
        vtc_log(hc->vl, 3, "CLI shutting fd %d", hc->sock);
246 15
        if (!VTCP_Check(j))
247 0
                vtc_fatal(hc->vl, "Shutdown failed: %s", strerror(errno));
248
249 15
        VSB_destroy(&vsb);
250 15
}
251
252
#define HAPROXY_CLI_RECV_LEN (1 << 14)
253
static void
254 15
haproxy_cli_recv(struct haproxy_cli *hc)
255
{
256
        ssize_t ret;
257
        size_t rdz, left, off;
258
259 15
        rdz = ret = off = 0;
260
        /* We want to null terminate this buffer. */
261 15
        left = hc->rxbuf_sz - 1;
262 30
        while (!vtc_error && left > 0) {
263 30
                VTCP_set_read_timeout(hc->sock, hc->timeout);
264
265 30
                ret = recv(hc->sock, hc->rxbuf + off, HAPROXY_CLI_RECV_LEN, 0);
266 30
                if (ret < 0) {
267 0
                        if (errno == EINTR || errno == EAGAIN)
268 0
                                continue;
269
270 0
                        vtc_fatal(hc->vl,
271
                            "CLI fd %d recv() failed (%s)",
272 0
                            hc->sock, strerror(errno));
273
                }
274
                /* Connection closed. */
275 30
                if (ret == 0) {
276 15
                        if (rdz > 0 && hc->rxbuf[rdz - 1] != '\n')
277 0
                                vtc_fatal(hc->vl,
278
                                    "CLI rx timeout (fd: %d %.3fs ret: %zd)",
279 0
                                    hc->sock, hc->timeout, ret);
280
281 15
                        vtc_log(hc->vl, 4, "CLI connection normally closed");
282 15
                        vtc_log(hc->vl, 3, "CLI closing fd %d", hc->sock);
283 15
                        VTCP_close(&hc->sock);
284 15
                        break;
285
                }
286
287 15
                rdz += ret;
288 15
                left -= ret;
289 15
                off  += ret;
290
        }
291 15
        hc->rxbuf[rdz] = '\0';
292 15
        vtc_dump(hc->vl, 4, "CLI recv", hc->rxbuf, rdz);
293 15
}
294
295
/*
296
 * SECTION: haproxy.cli.expect
297
 * expect OP STRING
298
 *         Regex match the CLI reception buffer with STRING
299
 *         if OP is ~ or, on the contrary, if OP is !~ check that there is
300
 *         no regex match.
301
 */
302
static void v_matchproto_(cmd_f)
303 15
cmd_haproxy_cli_expect(CMD_ARGS)
304
{
305
        struct haproxy_cli *hc;
306
        struct vsb vsb[1];
307
        vre_t *vre;
308
        int error, erroroffset, i, ret;
309
        char *cmp, *spec, errbuf[VRE_ERROR_LEN];
310
311 15
        (void)vl;
312 15
        CAST_OBJ_NOTNULL(hc, priv, HAPROXY_CLI_MAGIC);
313 15
        AZ(strcmp(av[0], "expect"));
314 15
        av++;
315
316 15
        cmp = av[0];
317 15
        spec = av[1];
318 15
        AN(cmp);
319 15
        AN(spec);
320 15
        AZ(av[2]);
321
322 15
        assert(!strcmp(cmp, "~") || !strcmp(cmp, "!~"));
323
324 15
        haproxy_cli_recv(hc);
325
326 15
        vre = VRE_compile(spec, 0, &error, &erroroffset, 1);
327 15
        if (vre == NULL) {
328 0
                AN(VSB_init(vsb, errbuf, sizeof errbuf));
329 0
                AZ(VRE_error(vsb, error));
330 0
                AZ(VSB_finish(vsb));
331 0
                VSB_fini(vsb);
332 0
                vtc_fatal(hc->vl, "CLI regexp error: '%s' (@%d) (%s)",
333 0
                    errbuf, erroroffset, spec);
334
        }
335
336 15
        i = VRE_match(vre, hc->rxbuf, 0, 0, NULL);
337
338 15
        VRE_free(&vre);
339
340 15
        ret = (i >= 0 && *cmp == '~') || (i < 0 && *cmp == '!');
341 15
        if (!ret)
342 0
                vtc_fatal(hc->vl, "CLI expect failed %s \"%s\"", cmp, spec);
343
        else
344 15
                vtc_log(hc->vl, 4, "CLI expect match %s \"%s\"", cmp, spec);
345 15
}
346
347
static const struct cmds haproxy_cli_cmds[] = {
348
#define CMD_HAPROXY_CLI(n) { CMDS_MAGIC, #n, cmd_haproxy_cli_##n },
349
        CMD_HAPROXY_CLI(send)
350
        CMD_HAPROXY_CLI(expect)
351
#undef CMD_HAPROXY_CLI
352
        { CMDS_MAGIC, NULL, NULL }
353
};
354
355
/**********************************************************************
356
 * HAProxy CLI client thread
357
 */
358
359
static void *
360 15
haproxy_cli_thread(void *priv)
361
{
362
        struct haproxy_cli *hc;
363
        struct vsb *vsb;
364
        int fd;
365
        const char *err;
366
367 15
        CAST_OBJ_NOTNULL(hc, priv, HAPROXY_CLI_MAGIC);
368 15
        AN(*hc->connect);
369
370 15
        vsb = macro_expand(hc->vl, hc->connect);
371 15
        AN(vsb);
372
373 15
        fd = haproxy_cli_tcp_connect(hc->vl, VSB_data(vsb), 10., &err);
374 15
        if (fd < 0)
375 0
                vtc_fatal(hc->vl,
376 0
                    "CLI failed to open %s: %s", VSB_data(vsb), err);
377 15
        VTCP_blocking(fd);
378 15
        hc->sock = fd;
379 15
        parse_string(hc->vl, hc, hc->spec);
380 15
        vtc_log(hc->vl, 2, "CLI ending");
381 15
        VSB_destroy(&vsb);
382 15
        return (NULL);
383
}
384
385
/**********************************************************************
386
 * Wait for the CLI client thread to stop
387
 */
388
389
static void
390 15
haproxy_cli_wait(struct haproxy_cli *hc)
391
{
392
        void *res;
393
394 15
        CHECK_OBJ_NOTNULL(hc, HAPROXY_CLI_MAGIC);
395 15
        vtc_log(hc->vl, 2, "CLI waiting");
396 15
        PTOK(pthread_join(hc->tp, &res));
397 15
        if (res != NULL)
398 0
                vtc_fatal(hc->vl, "CLI returned \"%s\"", (char *)res);
399 15
        REPLACE(hc->spec, NULL);
400 15
        hc->tp = 0;
401 15
        hc->running = 0;
402 15
}
403
404
/**********************************************************************
405
 * Start the CLI client thread
406
 */
407
408
static void
409 15
haproxy_cli_start(struct haproxy_cli *hc)
410
{
411 15
        CHECK_OBJ_NOTNULL(hc, HAPROXY_CLI_MAGIC);
412 15
        vtc_log(hc->vl, 2, "CLI starting");
413 15
        PTOK(pthread_create(&hc->tp, NULL, haproxy_cli_thread, hc));
414 15
        hc->running = 1;
415
416 15
}
417
418
/**********************************************************************
419
 * Run the CLI client thread
420
 */
421
422
static void
423 15
haproxy_cli_run(struct haproxy_cli *hc)
424
{
425 15
        haproxy_cli_start(hc);
426 15
        haproxy_cli_wait(hc);
427 15
}
428
429
/**********************************************************************
430
 * Wait for the pidfile
431
 */
432
433
static void
434 25
haproxy_wait_pidfile(struct haproxy *h)
435
{
436 25
        char buf_err[1024] = {0};
437 25
        int usleep_time = 1000;
438
        double t0;
439
        pid_t pid;
440
441 25
        vtc_log(h->vl, 3, "wait-pid-file");
442 1305
        for (t0 = VTIM_mono(); VTIM_mono() - t0 < 3;) {
443 1305
                if (vtc_error)
444 0
                        return;
445
446 1305
                if (VPF_Read(h->pid_fn, &pid) != 0) {
447 1280
                        bprintf(buf_err,
448
                            "Could not read PID file '%s'", h->pid_fn);
449 1280
                        usleep(usleep_time);
450 1280
                        continue;
451
                }
452
453 25
                if (!h->opt_daemon && pid != h->pid) {
454 0
                        bprintf(buf_err,
455
                            "PID file has different PID (%ld != %lld)",
456
                            (long)pid, (long long)h->pid);
457 0
                        usleep(usleep_time);
458 0
                        continue;
459
                }
460
461 25
                if (kill(pid, 0) < 0) {
462 0
                        bprintf(buf_err,
463
                            "Could not find PID %ld process", (long)pid);
464 0
                        usleep(usleep_time);
465 0
                        continue;
466
                }
467
468 25
                h->pid = pid;
469
470 50
                vtc_log(h->vl, 2, "haproxy PID %ld successfully started",
471 25
                    (long)pid);
472 25
                return;
473
        }
474 0
        vtc_fatal(h->vl, "haproxy %s PID file check failed:\n\t%s\n",
475 0
                  h->name, buf_err);
476 25
}
477
478
/**********************************************************************
479
 * Bind the sd_notify socket
480
 */
481
static void
482 10
haproxy_bind_sdnotify(struct haproxy *h)
483
{
484
        char sd_path[PATH_MAX];
485
        int sd;
486
        int ret;
487 10
        const char *err = NULL;
488 10
        struct sockaddr_un *uds = &h->sd_uds;
489 10
        socklen_t sl = sizeof(*uds);
490
491 10
        bprintf(sd_path, "%s/sd_notify.sock", h->workdir);
492 10
        assert(sd_path[0] == '/');
493
494 10
        if (strlen(sd_path) + 1 > sizeof(uds->sun_path)) {
495 0
                vtc_fatal(h->vl, "Path %s too long for a Unix domain socket", sd_path);
496
        }
497 10
        memset(uds->sun_path, 0, sizeof(uds->sun_path));
498 10
        bprintf(uds->sun_path, "%s", sd_path);
499 10
        uds->sun_family = PF_UNIX;
500
501 10
        sd = socket(AF_UNIX, SOCK_DGRAM, 0);
502 10
        if (sd < 0) {
503 0
                err = "socket(2)";
504 0
                goto error;
505
        }
506
507 10
        if (unlink(uds->sun_path) != 0 && errno != ENOENT) {
508 0
                err = "unlink(2)";
509 0
                closefd(&sd);
510 0
                goto error;
511
        }
512
513 10
        if (bind(sd, (const void*)uds, sl) != 0) {
514 0
                err = "bind(2)";
515 0
                closefd(&sd);
516 0
                goto error;
517
        }
518
519 10
        h->sd_sock = sd;
520
521 10
        assert(h->sd_sock > 0);
522 10
        vtc_log(h->vl, 4, "sd_notify %s", sd_path);
523 10
        ret = setenv("NOTIFY_SOCKET", sd_path, 1);
524 10
        assert(ret == 0);
525
526
error:
527 10
        if (err != NULL)
528 0
                vtc_fatal(h->vl, "Create sd_notify socket failed: %s", err);
529 10
}
530
531
/**********************************************************************
532
 * Wait for the "READY" from sd_notify
533
 */
534
static void
535 10
haproxy_wait_sdnotify_ready(struct haproxy *h)
536
{
537
        struct pollfd fd[1];
538
        char buf[BUFSIZ];
539
        int i, r;
540 10
        char *ready = NULL;
541
542 10
        vtc_log(h->vl, 3, "wait-sdnotify-ready");
543
544
        /* First try to do an accept on h->sd_sock */
545 10
        memset(fd, 0, sizeof(fd));
546 10
        fd[0].fd = h->sd_sock;
547 10
        fd[0].events = POLLIN;
548
549 10
        i = poll(fd, 1, (int)(vtc_maxdur * 1000 / 3));
550 10
        vtc_log(h->vl, 4, "sd_notify recv poll %d 0x%x ", i, fd[0].revents);
551 10
        if (i == 0)
552 0
                vtc_fatal(h->vl, "FAIL timeout waiting for sd_notify recv");
553 10
        if (!(fd[0].revents & POLLIN))
554 0
                vtc_fatal(h->vl, "FAIL sd_notify recv wait failure");
555
556 10
        r = recv(h->sd_sock, buf, sizeof(buf) - 1, 0);
557 10
        if (r > 0) {
558 10
                buf[r] = '\0';
559 10
                ready = strstr(buf, "READY=1");
560 10
        }
561
562 10
        if (!ready)
563 0
                vtc_fatal(h->vl, "FAIL sd_notify recv READY failure");
564
        else
565 10
                vtc_log(h->vl, 3, "sd_notify READY=1");
566 10
}
567
/**********************************************************************
568
 * Allocate and initialize a CLI client
569
 */
570
571
static struct haproxy_cli *
572 60
haproxy_cli_new(struct haproxy *h)
573
{
574
        struct haproxy_cli *hc;
575
576 60
        ALLOC_OBJ(hc, HAPROXY_CLI_MAGIC);
577 60
        AN(hc);
578
579 60
        hc->vl = h->vl;
580 60
        vtc_log_set_cmd(hc->vl, haproxy_cli_cmds);
581 60
        hc->sock = -1;
582 60
        bprintf(hc->connect, "${%s_cli_sock}", h->name);
583
584 60
        hc->txbuf_sz = hc->rxbuf_sz = 2048 * 1024;
585 60
        hc->txbuf = malloc(hc->txbuf_sz);
586 60
        AN(hc->txbuf);
587 60
        hc->rxbuf = malloc(hc->rxbuf_sz);
588 60
        AN(hc->rxbuf);
589
590 60
        return (hc);
591
}
592
593
/* creates a master CLI client (-mcli) */
594
static struct haproxy_cli *
595 60
haproxy_mcli_new(struct haproxy *h)
596
{
597
        struct haproxy_cli *hc;
598
599 60
        ALLOC_OBJ(hc, HAPROXY_CLI_MAGIC);
600 60
        AN(hc);
601
602 60
        hc->vl = h->vl;
603 60
        vtc_log_set_cmd(hc->vl, haproxy_cli_cmds);
604 60
        hc->sock = -1;
605 60
        bprintf(hc->connect, "${%s_mcli_sock}", h->name);
606
607 60
        hc->txbuf_sz = hc->rxbuf_sz = 2048 * 1024;
608 60
        hc->txbuf = malloc(hc->txbuf_sz);
609 60
        AN(hc->txbuf);
610 60
        hc->rxbuf = malloc(hc->rxbuf_sz);
611 60
        AN(hc->rxbuf);
612
613 60
        return (hc);
614
}
615
616
/* Bind an address/port for the master CLI (-mcli) */
617
static int
618 10
haproxy_create_mcli(struct haproxy *h)
619
{
620
        int sock;
621
        const char *err;
622
        char buf[128], addr[128], port[128];
623 10
        char vsabuf[vsa_suckaddr_len];
624
        const struct suckaddr *sua;
625
626 10
        sock = VTCP_listen_on(default_listen_addr, NULL, 100, &err);
627 10
        if (err != NULL)
628 0
                vtc_fatal(h->vl,
629 0
                          "Create listen socket failed: %s", err);
630 10
        assert(sock > 0);
631 10
        sua = VSA_getsockname(sock, vsabuf, sizeof vsabuf);
632 10
        AN(sua);
633
634 10
        VTCP_name(sua, addr, sizeof addr, port, sizeof port);
635 10
        bprintf(buf, "%s_mcli", h->name);
636 10
        if (VSA_Get_Proto(sua) == AF_INET)
637 10
                macro_def(h->vl, buf, "sock", "%s:%s", addr, port);
638
        else
639 0
                macro_def(h->vl, buf, "sock", "[%s]:%s", addr, port);
640 10
        macro_def(h->vl, buf, "addr", "%s", addr);
641 10
        macro_def(h->vl, buf, "port", "%s", port);
642
643 10
        return (sock);
644 10
}
645
646
static void
647 120
haproxy_cli_delete(struct haproxy_cli *hc)
648
{
649 120
        CHECK_OBJ_NOTNULL(hc, HAPROXY_CLI_MAGIC);
650 120
        REPLACE(hc->spec, NULL);
651 120
        REPLACE(hc->txbuf, NULL);
652 120
        REPLACE(hc->rxbuf, NULL);
653 120
        FREE_OBJ(hc);
654 120
}
655
656
/**********************************************************************
657
 * Allocate and initialize a haproxy
658
 */
659
660
static struct haproxy *
661 60
haproxy_new(const char *name)
662
{
663
        struct haproxy *h;
664
        struct vsb *vsb;
665
        char buf[PATH_MAX];
666
        int closed_sock;
667
        char addr[128], port[128];
668
        const char *err;
669
        const char *env_args;
670 60
        char vsabuf[vsa_suckaddr_len];
671
        const struct suckaddr *sua;
672
673 60
        ALLOC_OBJ(h, HAPROXY_MAGIC);
674 60
        AN(h);
675 60
        REPLACE(h->name, name);
676
677 60
        h->args = VSB_new_auto();
678 60
        env_args = getenv(HAPROXY_ARGS_ENV_VAR);
679 60
        if (env_args) {
680 0
                VSB_cat(h->args, env_args);
681 0
                VSB_cat(h->args, " ");
682 0
        }
683
684 60
        h->vl = vtc_logopen("%s", name);
685 60
        vtc_log_set_cmd(h->vl, haproxy_cli_cmds);
686 60
        AN(h->vl);
687
688 60
        h->filename = getenv(HAPROXY_PROGRAM_ENV_VAR);
689 60
        if (h->filename == NULL)
690 60
                h->filename = "haproxy";
691
692 60
        bprintf(buf, "${tmpdir}/%s", name);
693 60
        vsb = macro_expand(h->vl, buf);
694 60
        AN(vsb);
695 60
        h->workdir = strdup(VSB_data(vsb));
696 60
        AN(h->workdir);
697 60
        VSB_destroy(&vsb);
698
699 60
        bprintf(buf, "%s/stats.sock", h->workdir);
700 60
        h->cli_fn = strdup(buf);
701 60
        AN(h->cli_fn);
702
703 60
        bprintf(buf, "%s/cfg", h->workdir);
704 60
        h->cfg_fn = strdup(buf);
705 60
        AN(h->cfg_fn);
706
707
        /* Create a new TCP socket to reserve an IP:port and close it asap.
708
         * May be useful to simulate an unreachable server.
709
         */
710 60
        bprintf(h->closed_sock, "%s_closed", h->name);
711 60
        closed_sock = VTCP_listen_on("127.0.0.1:0", NULL, 100, &err);
712 60
        if (err != NULL)
713 0
                vtc_fatal(h->vl,
714 0
                        "Create listen socket failed: %s", err);
715 60
        assert(closed_sock > 0);
716 60
        sua = VSA_getsockname(closed_sock, vsabuf, sizeof vsabuf);
717 60
        AN(sua);
718 60
        VTCP_name(sua, addr, sizeof addr, port, sizeof port);
719 60
        if (VSA_Get_Proto(sua) == AF_INET)
720 60
                macro_def(h->vl, h->closed_sock, "sock", "%s:%s", addr, port);
721
        else
722 0
                macro_def(h->vl, h->closed_sock, "sock", "[%s]:%s", addr, port);
723 60
        macro_def(h->vl, h->closed_sock, "addr", "%s", addr);
724 60
        macro_def(h->vl, h->closed_sock, "port", "%s", port);
725 60
        VTCP_close(&closed_sock);
726
727 60
        h->cli = haproxy_cli_new(h);
728 60
        AN(h->cli);
729
730 60
        h->mcli = haproxy_mcli_new(h);
731 60
        AN(h->mcli);
732
733 60
        bprintf(buf, "rm -rf \"%s\" ; mkdir -p \"%s\"", h->workdir, h->workdir);
734 60
        AZ(system(buf));
735
736 60
        h->sd_sock = -1;
737
738 60
        VTAILQ_INIT(&h->envars);
739 60
        VTAILQ_INSERT_TAIL(&haproxies, h, list);
740
741 60
        return (h);
742 60
}
743
744
/**********************************************************************
745
 * Delete a haproxy instance
746
 */
747
748
static void
749 60
haproxy_delete(struct haproxy *h)
750
{
751
        char buf[PATH_MAX];
752
753 60
        CHECK_OBJ_NOTNULL(h, HAPROXY_MAGIC);
754 60
        vtc_logclose(h->vl);
755
756 60
        if (!leave_temp) {
757 60
                bprintf(buf, "rm -rf \"%s\"", h->workdir);
758 60
                AZ(system(buf));
759 60
        }
760
761 110
        if (h->sd_sock >= 0)
762 10
                closefd(&h->sd_sock);
763
764 60
        free(h->name);
765 60
        free(h->workdir);
766 60
        free(h->cli_fn);
767 60
        free(h->cfg_fn);
768 60
        free(h->pid_fn);
769 60
        VSB_destroy(&h->args);
770 60
        haproxy_cli_delete(h->cli);
771 60
        haproxy_cli_delete(h->mcli);
772
773
        /* XXX: MEMLEAK (?) */
774 60
        FREE_OBJ(h);
775 60
}
776
777
/**********************************************************************
778
 * HAProxy listener
779
 */
780
781
static void *
782 60
haproxy_thread(void *priv)
783
{
784
        struct haproxy *h;
785
786 60
        CAST_OBJ_NOTNULL(h, priv, HAPROXY_MAGIC);
787 60
        (void)vtc_record(h->vl, h->fds[0], h->msgs);
788 60
        h->its_dead_jim = 1;
789 60
        return (NULL);
790
}
791
792
793
/**********************************************************************
794
 * Start a HAProxy instance.
795
 */
796
797
static void
798 60
haproxy_start(struct haproxy *h)
799
{
800
        char buf[PATH_MAX];
801
        struct vsb *vsb;
802
803 60
        vtc_log(h->vl, 2, "%s", __func__);
804
805 60
        AZ(VSB_finish(h->args));
806 120
        vtc_log(h->vl, 4, "opt_worker %d opt_daemon %d opt_check_mode %d opt_mcli %d",
807 60
            h->opt_worker, h->opt_daemon, h->opt_check_mode, h->opt_mcli);
808
809 60
        vsb = VSB_new_auto();
810 60
        AN(vsb);
811
812 60
        VSB_printf(vsb, "exec \"%s\"", h->filename);
813 60
        if (h->opt_check_mode)
814 10
                VSB_cat(vsb, " -c");
815 50
        else if (h->opt_daemon)
816 15
                VSB_cat(vsb, " -D");
817
        else
818 35
                VSB_cat(vsb, " -d");
819
820 60
        if (h->opt_worker) {
821 10
                if (h->opt_worker == 2) { /* sd_notify mode */
822 10
                        VSB_cat(vsb, " -Ws");
823 10
                        haproxy_bind_sdnotify(h);
824 10
                } else {
825 0
                        VSB_cat(vsb, " -W");
826
                }
827 10
                if (h->opt_mcli) {
828
                        int sock;
829 10
                        sock = haproxy_create_mcli(h);
830 10
                        VSB_printf(vsb, " -S \"fd@%d\"", sock);
831 10
                }
832 10
        }
833
834 50
        VSB_printf(vsb, " %s", VSB_data(h->args));
835
836 50
        VSB_printf(vsb, " -f \"%s\" ", h->cfg_fn);
837
838 50
        if (h->opt_worker || h->opt_daemon) {
839 25
                bprintf(buf, "%s/pid", h->workdir);
840 25
                h->pid_fn = strdup(buf);
841 25
                AN(h->pid_fn);
842 25
                VSB_printf(vsb, " -p \"%s\"", h->pid_fn);
843 25
        }
844
845 60
        AZ(VSB_finish(vsb));
846 60
        vtc_dump(h->vl, 4, "argv", VSB_data(vsb), -1);
847
848 60
        if (h->opt_worker && !h->opt_daemon) {
849
                /*
850
                 * HAProxy master process must exit with status 128 + <signum>
851
                 * if signaled by <signum> signal.
852
                 */
853 10
                h->expect_exit = HAPROXY_EXPECT_EXIT;
854 10
        }
855
856 60
        haproxy_write_conf(h);
857
858 60
        AZ(pipe(&h->fds[0]));
859 60
        vtc_log(h->vl, 4, "XXX %d @%d", h->fds[1], __LINE__);
860 60
        AZ(pipe(&h->fds[2]));
861 60
        h->pid = h->ppid = fork();
862 60
        assert(h->pid >= 0);
863 120
        if (h->pid == 0) {
864 60
                haproxy_build_env(h);
865 60
                haproxy_delete_envars(h);
866 60
                AZ(chdir(h->name));
867 60
                AZ(dup2(h->fds[0], 0));
868 60
                assert(dup2(h->fds[3], 1) == 1);
869 60
                assert(dup2(1, 2) == 2);
870 60
                closefd(&h->fds[0]);
871 60
                closefd(&h->fds[1]);
872 60
                closefd(&h->fds[2]);
873 60
                closefd(&h->fds[3]);
874 60
                AZ(execl("/bin/sh", "/bin/sh", "-c", VSB_data(vsb), (char*)0));
875 0
                exit(1);
876
        }
877 60
        VSB_destroy(&vsb);
878
879 60
        vtc_log(h->vl, 3, "PID: %ld", (long)h->pid);
880 60
        macro_def(h->vl, h->name, "pid", "%ld", (long)h->pid);
881 60
        macro_def(h->vl, h->name, "name", "%s", h->workdir);
882
883 60
        closefd(&h->fds[0]);
884 60
        closefd(&h->fds[3]);
885 60
        h->fds[0] = h->fds[2];
886 60
        h->fds[2] = h->fds[3] = -1;
887
888 60
        PTOK(pthread_create(&h->tp, NULL, haproxy_thread, h));
889
890 60
        if (h->pid_fn != NULL)
891 25
                haproxy_wait_pidfile(h);
892
893 40
        if (h->opt_worker == 2) /* sd_notify mode */
894 10
                haproxy_wait_sdnotify_ready(h);
895 60
}
896
897
898
/**********************************************************************
899
 * Wait for a HAProxy instance.
900
 */
901
902
static void
903 60
haproxy_wait(struct haproxy *h)
904
{
905
        void *p;
906
        int i, n, sig;
907
908 60
        vtc_log(h->vl, 2, "Wait");
909
910 60
        if (h->pid < 0)
911 0
                haproxy_start(h);
912
913 0
        if (h->cli->spec)
914 0
                haproxy_cli_run(h->cli);
915
916 0
        if (h->mcli->spec)
917 0
                haproxy_cli_run(h->mcli);
918
919 60
        closefd(&h->fds[1]);
920
921 60
        sig = SIGINT;
922 60
        n = 0;
923 60
        vtc_log(h->vl, 2, "Stop HAproxy pid=%ld", (long)h->pid);
924 395
        while (h->opt_daemon || (!h->opt_check_mode && !h->its_dead_jim)) {
925 350
                assert(h->pid > 0);
926 350
                if (n == 0) {
927 65
                        i = kill(h->pid, sig);
928 65
                        if (i == 0)
929 50
                                h->expect_signal = -sig;
930 85
                        if (i && errno == ESRCH)
931 15
                                break;
932 100
                        vtc_log(h->vl, 4,
933 50
                            "Kill(%d)=%d: %s", sig, i, strerror(errno));
934 50
                }
935 85
                VTIM_sleep(0.1);
936 85
                if (++n == 20) {
937 15
                        switch (sig) {
938 15
                        case SIGINT:    sig = SIGTERM ; break;
939 0
                        case SIGTERM:   sig = SIGKILL ; break;
940 0
                        default:        break;
941
                        }
942 15
                        n = 0;
943 15
                }
944
        }
945
946 60
        PTOK(pthread_join(h->tp, &p));
947 60
        AZ(p);
948 60
        closefd(&h->fds[0]);
949 60
        if (!h->opt_daemon) {
950 45
                vtc_wait4(h->vl, h->ppid, h->expect_exit, h->expect_signal, 0);
951 45
                h->ppid = -1;
952 45
        }
953 60
        h->pid = -1;
954 60
}
955
956
#define HAPROXY_FD_ADDR_FAM_PREFIX        "fd@${"
957
#define HAPROXY_FD_ADDR_FAM_PREFIX_LEN    strlen(HAPROXY_FD_ADDR_FAM_PREFIX)
958
959
#define HAPROXY_QUIC_SOCK_TYPE            "quic"
960
#define HAPROXY_QUIC_SOCK_TYPE_PREFIX     HAPROXY_QUIC_SOCK_TYPE "+"
961
#define HAPROXY_QUIC_SOCK_TYPE_PREFIX_LEN strlen(HAPROXY_QUIC_SOCK_TYPE_PREFIX)
962
963
#define HAPROXY_VTC_SOCK_TYPE_ENV_VAR     "VTC_SOCK_TYPE"
964
#define HAPROXY_VTC_SOCK_TYPE_PREFIX      "${" HAPROXY_VTC_SOCK_TYPE_ENV_VAR "}+"
965
#define HAPROXY_VTC_SOCK_TYPE_PREFIX_LEN  strlen(HAPROXY_VTC_SOCK_TYPE_PREFIX)
966
967
static int
968 60
haproxy_build_backends(struct haproxy *h, const char *vsb_data)
969
{
970
        char *s, *p, *q;
971 60
        char *sock_type = getenv(HAPROXY_VTC_SOCK_TYPE_ENV_VAR);
972
973 60
        s = strdup(vsb_data);
974 60
        if (!s)
975 0
                return (-1);
976
977 60
        if (sock_type)
978 0
                vtc_log(h->vl, 4, "%s value: '%s'",
979 0
                        HAPROXY_VTC_SOCK_TYPE_ENV_VAR, sock_type);
980 60
        p = s;
981 165
        while (1) {
982
                int sock;
983
                char buf[128], addr[128], port[128];
984
                const char *err;
985 165
                char vsabuf[vsa_suckaddr_len];
986
                const struct suckaddr *sua;
987
                int quic_sock;
988
989 165
                p = strstr(p, HAPROXY_FD_ADDR_FAM_PREFIX);
990 165
                if (!p)
991 60
                        break;
992
993
                /* The socket to be used is a QUIC one if the fd addresses
994
                 * are prefixed by the haproxy sock type "quic" as follows:
995
                 *    bind "quic+fd@${...}"
996
                 *    bind "${VTC_SOCK_TYPE}+fd@${...}"
997
                 * with "quic" as VTC_SOCK_TYPE environment variable value.
998
                 */
999 105
                quic_sock =
1000 105
                        (p - s >= HAPROXY_QUIC_SOCK_TYPE_PREFIX_LEN &&
1001 105
                         !memcmp(p - HAPROXY_QUIC_SOCK_TYPE_PREFIX_LEN,
1002
                                 HAPROXY_QUIC_SOCK_TYPE_PREFIX,
1003 210
                                 HAPROXY_QUIC_SOCK_TYPE_PREFIX_LEN)) ||
1004 105
                        (p - s >= HAPROXY_VTC_SOCK_TYPE_PREFIX_LEN &&
1005 105
                         !memcmp(p - HAPROXY_VTC_SOCK_TYPE_PREFIX_LEN,
1006
                                 HAPROXY_VTC_SOCK_TYPE_PREFIX,
1007 105
                                 HAPROXY_VTC_SOCK_TYPE_PREFIX_LEN) &&
1008 0
                         sock_type != NULL &&
1009 0
                         !strcmp(sock_type, HAPROXY_QUIC_SOCK_TYPE));
1010
1011 105
                q = p += HAPROXY_FD_ADDR_FAM_PREFIX_LEN;
1012 450
                while (*q && *q != '}')
1013 345
                        q++;
1014 105
                if (*q != '}')
1015 0
                        break;
1016
1017 105
                *q++ = '\0';
1018 105
                if (quic_sock) {
1019 0
                        sock = VUDP_bind_on("127.0.0.1:0", "0", &err);
1020 0
                }
1021
                else {
1022 105
                        sock = VTCP_listen_on("127.0.0.1:0", NULL, 100, &err);
1023
                }
1024 105
                if (err != NULL)
1025 0
                        vtc_fatal(h->vl,
1026 0
                            "Create listen socket failed: %s", err);
1027 105
                assert(sock > 0);
1028 105
                sua = VSA_getsockname(sock, vsabuf, sizeof vsabuf);
1029 105
                AN(sua);
1030
1031 105
                VTCP_name(sua, addr, sizeof addr, port, sizeof port);
1032 105
                bprintf(buf, "%s_%s", h->name, p);
1033 105
                if (VSA_Get_Proto(sua) == AF_INET)
1034 105
                        macro_def(h->vl, buf, "sock", "%s:%s", addr, port);
1035
                else
1036 0
                        macro_def(h->vl, buf, "sock", "[%s]:%s", addr, port);
1037 105
                macro_def(h->vl, buf, "addr", "%s", addr);
1038 105
                macro_def(h->vl, buf, "port", "%s", port);
1039
1040 105
                bprintf(buf, "%d", sock);
1041 210
                vtc_log(h->vl, 4, "setenv(%s, %s) for %s socket", p, buf,
1042 105
                        quic_sock ? "QUIC" : "TCP");
1043 105
                haproxy_add_envar(h, p, buf);
1044 105
                p = q;
1045 165
        }
1046 60
        free(s);
1047 60
        return (0);
1048 60
}
1049
1050
static void
1051 10
haproxy_check_conf(struct haproxy *h, const char *expect)
1052
{
1053
1054 10
        h->msgs = VSB_new_auto();
1055 10
        AN(h->msgs);
1056 10
        h->opt_check_mode = 1;
1057 10
        haproxy_start(h);
1058 10
        haproxy_wait(h);
1059 10
        AZ(VSB_finish(h->msgs));
1060 10
        if (strstr(VSB_data(h->msgs), expect) == NULL)
1061 0
                vtc_fatal(h->vl, "Did not find expected string '%s'", expect);
1062 10
        vtc_log(h->vl, 2, "Found expected '%s'", expect);
1063 10
        VSB_destroy(&h->msgs);
1064 10
}
1065
1066
/**********************************************************************
1067
 * Write a configuration for <h> HAProxy instance.
1068
 */
1069
1070
static void
1071 60
haproxy_store_conf(struct haproxy *h, const char *cfg, int auto_be)
1072
{
1073
        struct vsb *vsb, *vsb2;
1074
1075 60
        vsb = VSB_new_auto();
1076 60
        AN(vsb);
1077
1078 60
        vsb2 = VSB_new_auto();
1079 60
        AN(vsb2);
1080
1081 120
        VSB_printf(vsb, "    global\n\tstats socket \"%s\" "
1082 60
                   "level admin mode 600\n", h->cli_fn);
1083 60
        VSB_cat(vsb, "    stats socket \"fd@${cli}\" level admin\n");
1084 60
        AZ(VSB_cat(vsb, cfg));
1085
1086 60
        if (auto_be)
1087 5
                cmd_server_gen_haproxy_conf(vsb);
1088
1089 60
        AZ(VSB_finish(vsb));
1090
1091 60
        AZ(haproxy_build_backends(h, VSB_data(vsb)));
1092
1093 60
        h->cfg_vsb = macro_expand(h->vl, VSB_data(vsb));
1094 60
        AN(h->cfg_vsb);
1095
1096 60
        VSB_destroy(&vsb2);
1097 60
        VSB_destroy(&vsb);
1098 60
}
1099
1100
static void
1101 60
haproxy_write_conf(struct haproxy *h)
1102
{
1103
        struct vsb *vsb;
1104
1105 60
        vsb = macro_expand(h->vl, VSB_data(h->cfg_vsb));
1106 60
        AN(vsb);
1107 60
        assert(VSB_len(vsb) >= 0);
1108
1109 60
        vtc_dump(h->vl, 4, "conf", VSB_data(vsb), VSB_len(vsb));
1110 180
        if (VFIL_writefile(h->workdir, h->cfg_fn,
1111 120
            VSB_data(vsb), VSB_len(vsb)) != 0)
1112 0
                vtc_fatal(h->vl,
1113
                    "failed to write haproxy configuration file: %s (%d)",
1114 0
                    strerror(errno), errno);
1115
1116 60
        VSB_destroy(&vsb);
1117 60
}
1118
1119
/* SECTION: haproxy haproxy
1120
 *
1121
 * Define and interact with haproxy instances.
1122
 *
1123
 * To define a haproxy server, you'll use this syntax::
1124
 *
1125
 *      haproxy hNAME -conf-OK CONFIG
1126
 *      haproxy hNAME -conf-BAD ERROR CONFIG
1127
 *      haproxy hNAME [-D] [-W] [-arg STRING] [-conf[+vcl] STRING]
1128
 *
1129
 * The first ``haproxy hNAME`` invocation will start the haproxy master
1130
 * process in the background, waiting for the ``-start`` switch to actually
1131
 * start the child.
1132
 *
1133
 * Arguments:
1134
 *
1135
 * hNAME
1136
 *         Identify the HAProxy server with a string, it must starts with 'h'.
1137
 *
1138
 * \-conf-OK CONFIG
1139
 *         Run haproxy in '-c' mode to check config is OK
1140
 *         stdout/stderr should contain 'Configuration file is valid'
1141
 *         The exit code should be 0.
1142
 *
1143
 * \-conf-BAD ERROR CONFIG
1144
 *         Run haproxy in '-c' mode to check config is BAD.
1145
 *         "ERROR" should be part of the diagnostics on stdout/stderr.
1146
 *         The exit code should be 1.
1147
 *
1148
 * \-D
1149
 *         Run HAproxy in daemon mode.  If not given '-d' mode used.
1150
 *
1151
 * \-W
1152
 *         Enable HAproxy in Worker mode.
1153
 *
1154
 * \-S
1155
 *         Enable HAproxy Master CLI in Worker mode
1156
 *
1157
 * \-arg STRING
1158
 *         Pass an argument to haproxy, for example "-h simple_list".
1159
 *
1160
 * \-cli STRING
1161
 *         Specify the spec to be run by the command line interface (CLI).
1162
 *
1163
 * \-mcli STRING
1164
 *         Specify the spec to be run by the command line interface (CLI)
1165
 *         of the Master process.
1166
 *
1167
 * \-conf STRING
1168
 *         Specify the configuration to be loaded by this HAProxy instance.
1169
 *
1170
 * \-conf+backend STRING
1171
 *         Specify the configuration to be loaded by this HAProxy instance,
1172
 *         all server instances will be automatically appended
1173
 *
1174
 * \-start
1175
 *         Start this HAProxy instance.
1176
 *
1177
 * \-wait
1178
 *         Stop this HAProxy instance.
1179
 *
1180
 * \-expectexit NUMBER
1181
 *         Expect haproxy to exit(3) with this value
1182
 *
1183
 */
1184
1185
void
1186 5535
cmd_haproxy(CMD_ARGS)
1187
{
1188
        struct haproxy *h, *h2;
1189
1190 5535
        (void)priv;
1191
1192 5535
        if (av == NULL) {
1193
                /* Reset and free */
1194 5515
                VTAILQ_FOREACH_SAFE(h, &haproxies, list, h2) {
1195 120
                        vtc_log(h->vl, 2,
1196
                            "Reset and free %s haproxy %ld",
1197 60
                            h->name, (long)h->pid);
1198 60
                        if (h->pid >= 0)
1199 30
                                haproxy_wait(h);
1200 60
                        VTAILQ_REMOVE(&haproxies, h, list);
1201 60
                        haproxy_delete(h);
1202 60
                }
1203 5455
                return;
1204
        }
1205
1206 80
        AZ(strcmp(av[0], "haproxy"));
1207 80
        av++;
1208
1209 80
        VTC_CHECK_NAME(vl, av[0], "haproxy", 'h');
1210 90
        VTAILQ_FOREACH(h, &haproxies, list)
1211 30
                if (!strcmp(h->name, av[0]))
1212 20
                        break;
1213 60
        if (h == NULL)
1214 60
                h = haproxy_new(av[0]);
1215 80
        av++;
1216
1217 260
        for (; *av != NULL; av++) {
1218 180
                if (vtc_error)
1219 0
                        break;
1220
1221 180
                if (!strcmp(*av, "-conf-OK")) {
1222 5
                        AN(av[1]);
1223 5
                        haproxy_store_conf(h, av[1], 0);
1224 5
                        h->expect_exit = 0;
1225 5
                        haproxy_check_conf(h, "");
1226 5
                        av++;
1227 5
                        continue;
1228
                }
1229 175
                if (!strcmp(*av, "-conf-BAD")) {
1230 5
                        AN(av[1]);
1231 5
                        AN(av[2]);
1232 5
                        haproxy_store_conf(h, av[2], 0);
1233 5
                        h->expect_exit = 1;
1234 5
                        haproxy_check_conf(h, av[1]);
1235 5
                        av += 2;
1236 5
                        continue;
1237
                }
1238
1239 170
                if (!strcmp(*av, HAPROXY_OPT_DAEMON)) {
1240 15
                        h->opt_daemon = 1;
1241 15
                        continue;
1242
                }
1243 155
                if (!strcmp(*av, HAPROXY_OPT_WORKER)) {
1244 0
                        h->opt_worker = 1;
1245 0
                        continue;
1246
                }
1247 155
                if (!strcmp(*av, HAPROXY_OPT_SD_WORKER)) {
1248 10
                        h->opt_worker = 2;
1249 10
                        continue;
1250
                }
1251 145
                if (!strcmp(*av, HAPROXY_OPT_MCLI)) {
1252 10
                        h->opt_mcli = 1;
1253 10
                        continue;
1254
                }
1255 135
                if (!strcmp(*av, "-arg")) {
1256 0
                        AN(av[1]);
1257 0
                        AZ(h->pid);
1258 0
                        VSB_cat(h->args, " ");
1259 0
                        VSB_cat(h->args, av[1]);
1260 0
                        av++;
1261 0
                        continue;
1262
                }
1263
1264 135
                if (!strcmp(*av, "-cli")) {
1265 5
                        REPLACE(h->cli->spec, av[1]);
1266 5
                        if (h->tp)
1267 5
                                haproxy_cli_run(h->cli);
1268 5
                        av++;
1269 5
                        continue;
1270
                }
1271
1272 130
                if (!strcmp(*av, "-mcli")) {
1273 10
                        REPLACE(h->mcli->spec, av[1]);
1274 10
                        if (h->tp)
1275 10
                                haproxy_cli_run(h->mcli);
1276 10
                        av++;
1277 10
                        continue;
1278
                }
1279
1280 120
                if (!strcmp(*av, "-conf")) {
1281 45
                        AN(av[1]);
1282 45
                        haproxy_store_conf(h, av[1], 0);
1283 45
                        av++;
1284 45
                        continue;
1285
                }
1286 75
                if (!strcmp(*av, "-conf+backend")) {
1287 5
                        AN(av[1]);
1288 5
                        haproxy_store_conf(h, av[1], 1);
1289 5
                        av++;
1290 5
                        continue;
1291
                }
1292
1293 70
                if (!strcmp(*av, "-expectexit")) {
1294 0
                        h->expect_exit = strtoul(av[1], NULL, 0);
1295 0
                        av++;
1296 0
                        continue;
1297
                }
1298 70
                if (!strcmp(*av, "-start")) {
1299 50
                        haproxy_start(h);
1300 50
                        continue;
1301
                }
1302 20
                if (!strcmp(*av, "-wait")) {
1303 20
                        haproxy_wait(h);
1304 20
                        continue;
1305
                }
1306 0
                vtc_fatal(h->vl, "Unknown haproxy argument: %s", *av);
1307
        }
1308 5535
}