varnish-cache/bin/varnishd/storage/mgt_stevedore.c
0
/*-
1
 * Copyright (c) 2007-2011 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Dag-Erling Smørgav <des@des.no>
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
 * STEVEDORE: one who works at or is responsible for loading and
30
 * unloading ships in port.  Example: "on the wharves, stevedores were
31
 * unloading cargo from the far corners of the world." Origin: Spanish
32
 * estibador, from estibar to pack.  First Known Use: 1788
33
 */
34
35
#include "config.h"
36
37
#include <stdio.h>
38
#include <stdlib.h>
39
#include <string.h>
40
#include <unistd.h>
41
42
#include "mgt/mgt.h"
43
#include "common/heritage.h"
44
#include "vcli_serve.h"
45
46
#include "storage/storage.h"
47
48
VTAILQ_HEAD(stevedore_head, stevedore);
49
50
static struct stevedore_head proto_stevedores =
51
    VTAILQ_HEAD_INITIALIZER(proto_stevedores);
52
53
static struct stevedore_head pre_stevedores =
54
    VTAILQ_HEAD_INITIALIZER(pre_stevedores);
55
56
static struct stevedore_head stevedores =
57
    VTAILQ_HEAD_INITIALIZER(stevedores);
58
59
/* Name of transient storage */
60
#define TRANSIENT_STORAGE       "Transient"
61
62
struct stevedore *stv_transient;
63
64
const char *mgt_stv_h2_rxbuf;
65
66
/*--------------------------------------------------------------------*/
67
68
int
69 1028021
STV__iter(struct stevedore ** const pp)
70
{
71
72 1028021
        AN(pp);
73 1028021
        CHECK_OBJ_ORNULL(*pp, STEVEDORE_MAGIC);
74 1028021
        if (*pp != NULL)
75 644600
                *pp = VTAILQ_NEXT(*pp, list);
76 383421
        else if (!VTAILQ_EMPTY(&stevedores))
77 285261
                *pp = VTAILQ_FIRST(&stevedores);
78
        else
79 98160
                *pp = VTAILQ_FIRST(&pre_stevedores);
80 1028021
        return (*pp != NULL);
81
}
82
83
/*--------------------------------------------------------------------*/
84
85
static void v_matchproto_(cli_func_t)
86 160
stv_cli_list(struct cli *cli, const char * const *av, void *priv)
87
{
88
        struct stevedore *stv;
89
90 160
        ASSERT_MGT();
91 160
        (void)av;
92 160
        (void)priv;
93 160
        VCLI_Out(cli, "Storage devices:\n");
94 520
        STV_Foreach(stv)
95 360
                VCLI_Out(cli, "\tstorage.%s = %s\n", stv->ident, stv->name);
96 160
}
97
98
static void v_matchproto_(cli_func_t)
99 40
stv_cli_list_json(struct cli *cli, const char * const *av, void *priv)
100
{
101
        struct stevedore *stv;
102 40
        int n = 0;
103
104 40
        (void)priv;
105 40
        ASSERT_MGT();
106 40
        VCLI_JSON_begin(cli, 2, av);
107 40
        VCLI_Out(cli, ",\n");
108 120
        STV_Foreach(stv) {
109 80
                VCLI_Out(cli, "%s", n ? ",\n" : "");
110 80
                n++;
111 80
                VCLI_Out(cli, "{\n");
112 80
                VSB_indent(cli->sb, 2);
113 80
                VCLI_Out(cli, "\"name\": ");
114 80
                VCLI_JSON_str(cli, stv->ident);
115 80
                VCLI_Out(cli, ",\n");
116 80
                VCLI_Out(cli, "\"storage\": ");
117 80
                VCLI_JSON_str(cli, stv->name);
118 80
                VSB_indent(cli->sb, -2);
119 80
                VCLI_Out(cli, "\n}");
120
        }
121 40
        VCLI_JSON_end(cli);
122 40
}
123
124
/*--------------------------------------------------------------------*/
125
126
static struct cli_proto cli_stv[] = {
127
        { CLICMD_STORAGE_LIST,          "", stv_cli_list, stv_cli_list_json },
128
        { NULL}
129
};
130
131
/*--------------------------------------------------------------------
132
 */
133
134
#ifdef WITH_PERSISTENT_STORAGE
135
static void v_noreturn_ v_matchproto_(storage_init_f)
136 40
smp_fake_init(struct stevedore *parent, int ac, char * const *av)
137
{
138
139 40
        (void)parent;
140 40
        (void)ac;
141 40
        (void)av;
142 40
        ARGV_ERR(
143
            "-spersistent has been deprecated, please see:\n"
144
            "  https://www.varnish-cache.org/docs/trunk/phk/persistent.html\n"
145
            "for details.\n"
146
        );
147 0
}
148
149
static const struct stevedore smp_fake_stevedore = {
150
        .magic = STEVEDORE_MAGIC,
151
        .name = "persistent",
152
        .init = smp_fake_init,
153
};
154
#endif
155
156
/*--------------------------------------------------------------------
157
 * Register a stevedore implementation by name.
158
 * VEXTs get to do this first, and since the list is searched front to
159
 * back a VEXT stevedore which inadvisably wants to steal "default" or
160
 * the name of another stevedore implementation can do so.
161
 */
162
163
void
164 220740
STV_Register(const struct stevedore *cstv, const char *altname)
165
{
166
        struct stevedore *stv;
167
168 220740
        CHECK_OBJ_NOTNULL(cstv, STEVEDORE_MAGIC);
169 220740
        ALLOC_OBJ(stv, STEVEDORE_MAGIC);
170 220740
        AN(stv);
171 220740
        *stv = *cstv;
172 220740
        if (altname != NULL)
173 36790
                stv->ident = altname;
174
        else
175 183950
                stv->ident = stv->name;
176 220740
        VTAILQ_INSERT_TAIL(&proto_stevedores, stv, list);
177 220740
}
178
179
static void
180 36790
STV_Register_The_Usual_Suspects(void)
181
{
182 36790
        STV_Register(&smf_stevedore, NULL);
183 36790
        STV_Register(&sma_stevedore, NULL);
184 36790
        STV_Register(&smd_stevedore, NULL);
185
#ifdef WITH_PERSISTENT_STORAGE
186 36790
        STV_Register(&smp_stevedore, NULL);
187 36790
        STV_Register(&smp_fake_stevedore, NULL);
188
#endif
189
#if defined(HAVE_UMEM_H)
190
        STV_Register(&smu_stevedore, NULL);
191
        STV_Register(&smu_stevedore, "default");
192
#else
193 36790
        STV_Register(&sma_stevedore, "default");
194
#endif
195 36790
}
196
197
/*--------------------------------------------------------------------
198
 * Parse a stevedore argument on the form:
199
 *     [ name '=' ] strategy [ ',' arg ] *
200
 */
201
202
void
203 76440
STV_Config(const char *spec)
204
{
205
        char **av, buf[8];
206
        const char *ident;
207
        struct stevedore *stv;
208
        static unsigned seq = 0;
209
210 76440
        av = MGT_NamedArg(spec, &ident, "-s");
211 76440
        AN(av);
212
213 76440
        if (av[1] == NULL)
214 0
                ARGV_ERR("-s argument lacks strategy {malloc, file, ...}\n");
215
216
        /* Append strategy to ident string */
217 76440
        VSB_printf(vident, ",-s%s", av[1]);
218
219 76440
        if (ident == NULL) {
220 37200
                bprintf(buf, "s%u", seq++);
221 37200
                ident = strdup(buf);
222 37200
        }
223
224 115440
        VTAILQ_FOREACH(stv, &pre_stevedores, list)
225 39120
                if (!strcmp(stv->ident, ident))
226 120
                        ARGV_ERR("(-s %s) '%s' is already defined\n",
227
                            spec, ident);
228
229 76320
        ALLOC_OBJ(stv, STEVEDORE_MAGIC);
230 76320
        AN(stv);
231 76320
        stv->av = av;
232 76320
        stv->ident = ident;
233 76320
        stv->name = av[1];
234 76320
        VTAILQ_INSERT_TAIL(&pre_stevedores, stv, list);
235 76320
}
236
237
/*--------------------------------------------------------------------*/
238
239
void
240 38040
STV_Config_Final(void)
241
{
242
        struct stevedore *stv;
243 38040
        ASSERT_MGT();
244
245 38040
        VCLS_AddFunc(mgt_cls, MCF_AUTH, cli_stv);
246 76120
        STV_Foreach(stv)
247 38880
                if (!strcmp(stv->ident, TRANSIENT_STORAGE))
248 800
                        return;
249 37240
        STV_Config(TRANSIENT_STORAGE "=default");
250 38040
}
251
252
/*--------------------------------------------------------------------
253
 * Initialize configured stevedores in the worker process
254
 */
255
256
void
257 36950
STV_Init(void)
258
{
259
        char **av;
260
        const char *ident;
261
        struct stevedore *stv;
262
        const struct stevedore *stv2;
263
        int ac;
264
265 36950
        STV_Register_The_Usual_Suspects();
266 110610
        while (!VTAILQ_EMPTY(&pre_stevedores)) {
267 73980
                stv = VTAILQ_FIRST(&pre_stevedores);
268 73980
                VTAILQ_REMOVE(&pre_stevedores, stv, list);
269 73980
                CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
270 73980
                AN(stv->av);
271 73980
                av = stv->av;
272 73980
                AN(stv->ident);
273 73980
                ident = stv->ident;
274
275 113290
                for (ac = 0; av[ac + 2] != NULL; ac++)
276 39310
                        continue;
277
278 436870
                VTAILQ_FOREACH(stv2, &proto_stevedores, list)
279 436710
                        if (!strcmp(stv2->ident, av[1]))
280 73820
                                break;
281 73980
                if (stv2 == NULL)
282 0
                        ARGV_ERR("Unknown stevedore method \"%s\"\n", av[1]);
283
284 73660
                CHECK_OBJ_NOTNULL(stv2, STEVEDORE_MAGIC);
285 73660
                *stv = *stv2;
286 73660
                AN(stv->name);
287
288 73660
                av += 2;
289
290 73660
                stv->ident = ident;
291 73660
                stv->av = av;
292
293 73660
                if (stv->init != NULL)
294 73660
                        stv->init(stv, ac, av);
295 0
                else if (ac != 0)
296 0
                        ARGV_ERR("(-s %s) too many arguments\n", stv->name);
297
298 73660
                AN(stv->allocobj);
299 73660
                AN(stv->methods);
300
301 73660
                if (!strcmp(stv->ident, TRANSIENT_STORAGE)) {
302 36630
                        AZ(stv_transient);
303 36630
                        stv_transient = stv;
304 36630
                } else
305 37030
                        VTAILQ_INSERT_TAIL(&stevedores, stv, list);
306
                /* NB: Do not free av, stevedore gets to keep it */
307
        }
308 36630
        AN(stv_transient);
309 36630
        VTAILQ_INSERT_TAIL(&stevedores, stv_transient, list);
310 36630
}