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 625396
STV__iter(struct stevedore ** const pp)
70
{
71
72 625396
        AN(pp);
73 625396
        CHECK_OBJ_ORNULL(*pp, STEVEDORE_MAGIC);
74 625396
        if (*pp != NULL)
75 391914
                *pp = VTAILQ_NEXT(*pp, list);
76 233482
        else if (!VTAILQ_EMPTY(&stevedores))
77 173707
                *pp = VTAILQ_FIRST(&stevedores);
78
        else
79 59775
                *pp = VTAILQ_FIRST(&pre_stevedores);
80 625396
        return (*pp != NULL);
81
}
82
83
/*--------------------------------------------------------------------*/
84
85
static void v_matchproto_(cli_func_t)
86 100
stv_cli_list(struct cli *cli, const char * const *av, void *priv)
87
{
88
        struct stevedore *stv;
89
90 100
        ASSERT_MGT();
91 100
        (void)av;
92 100
        (void)priv;
93 100
        VCLI_Out(cli, "Storage devices:\n");
94 325
        STV_Foreach(stv)
95 225
                VCLI_Out(cli, "\tstorage.%s = %s\n", stv->ident, stv->name);
96 100
}
97
98
static void v_matchproto_(cli_func_t)
99 25
stv_cli_list_json(struct cli *cli, const char * const *av, void *priv)
100
{
101
        struct stevedore *stv;
102 25
        int n = 0;
103
104 25
        (void)priv;
105 25
        ASSERT_MGT();
106 25
        VCLI_JSON_begin(cli, 2, av);
107 25
        VCLI_Out(cli, ",\n");
108 75
        STV_Foreach(stv) {
109 50
                VCLI_Out(cli, "%s", n ? ",\n" : "");
110 50
                n++;
111 50
                VCLI_Out(cli, "{\n");
112 50
                VSB_indent(cli->sb, 2);
113 50
                VCLI_Out(cli, "\"name\": ");
114 50
                VCLI_JSON_str(cli, stv->ident);
115 50
                VCLI_Out(cli, ",\n");
116 50
                VCLI_Out(cli, "\"storage\": ");
117 50
                VCLI_JSON_str(cli, stv->name);
118 50
                VSB_indent(cli->sb, -2);
119 50
                VCLI_Out(cli, "\n}");
120
        }
121 25
        VCLI_JSON_end(cli);
122 25
}
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 25
smp_fake_init(struct stevedore *parent, int ac, char * const *av)
137
{
138
139 25
        (void)parent;
140 25
        (void)ac;
141 25
        (void)av;
142 25
        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 133782
STV_Register(const struct stevedore *cstv, const char *altname)
165
{
166
        struct stevedore *stv;
167
168 133782
        CHECK_OBJ_NOTNULL(cstv, STEVEDORE_MAGIC);
169 133782
        ALLOC_OBJ(stv, STEVEDORE_MAGIC);
170 133782
        AN(stv);
171 133782
        *stv = *cstv;
172 133782
        if (altname != NULL)
173 22297
                stv->ident = altname;
174
        else
175 111485
                stv->ident = stv->name;
176 133782
        VTAILQ_INSERT_TAIL(&proto_stevedores, stv, list);
177 133782
}
178
179
static void
180 22297
STV_Register_The_Usual_Suspects(void)
181
{
182 22297
        STV_Register(&smf_stevedore, NULL);
183 22297
        STV_Register(&sma_stevedore, NULL);
184 22297
        STV_Register(&smd_stevedore, NULL);
185
#ifdef WITH_PERSISTENT_STORAGE
186 22297
        STV_Register(&smp_stevedore, NULL);
187 22297
        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 22297
        STV_Register(&sma_stevedore, "default");
194
#endif
195 22297
}
196
197
/*--------------------------------------------------------------------
198
 * Parse a stevedore argument on the form:
199
 *     [ name '=' ] strategy [ ',' arg ] *
200
 */
201
202
void
203 46475
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 46475
        av = MGT_NamedArg(spec, &ident, "-s");
211 46475
        AN(av);
212
213 46475
        if (av[1] == NULL)
214 0
                ARGV_ERR("-s argument lacks strategy {malloc, file, ...}\n");
215
216
        /* Append strategy to ident string */
217 46475
        VSB_printf(vident, ",-s%s", av[1]);
218
219 46475
        if (ident == NULL) {
220 22600
                bprintf(buf, "s%u", seq++);
221 22600
                ident = strdup(buf);
222 22600
        }
223
224 70200
        VTAILQ_FOREACH(stv, &pre_stevedores, list)
225 23800
                if (!strcmp(stv->ident, ident))
226 75
                        ARGV_ERR("(-s %s) '%s' is already defined\n",
227
                            spec, ident);
228
229 46400
        ALLOC_OBJ(stv, STEVEDORE_MAGIC);
230 46400
        AN(stv);
231 46400
        stv->av = av;
232 46400
        stv->ident = ident;
233 46400
        stv->name = av[1];
234 46400
        VTAILQ_INSERT_TAIL(&pre_stevedores, stv, list);
235 46400
}
236
237
/*--------------------------------------------------------------------*/
238
239
void
240 23125
STV_Config_Final(void)
241
{
242
        struct stevedore *stv;
243 23125
        ASSERT_MGT();
244
245 23125
        VCLS_AddFunc(mgt_cls, MCF_AUTH, cli_stv);
246 46275
        STV_Foreach(stv)
247 23650
                if (!strcmp(stv->ident, TRANSIENT_STORAGE))
248 500
                        return;
249 22625
        STV_Config(TRANSIENT_STORAGE "=default");
250 23125
}
251
252
/*--------------------------------------------------------------------
253
 * Initialize configured stevedores in the worker process
254
 */
255
256
void
257 22397
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 22397
        STV_Register_The_Usual_Suspects();
266 67041
        while (!VTAILQ_EMPTY(&pre_stevedores)) {
267 44844
                stv = VTAILQ_FIRST(&pre_stevedores);
268 44844
                VTAILQ_REMOVE(&pre_stevedores, stv, list);
269 44844
                CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
270 44844
                AN(stv->av);
271 44844
                av = stv->av;
272 44844
                AN(stv->ident);
273 44844
                ident = stv->ident;
274
275 68716
                for (ac = 0; av[ac + 2] != NULL; ac++)
276 23872
                        continue;
277
278 264673
                VTAILQ_FOREACH(stv2, &proto_stevedores, list)
279 264573
                        if (!strcmp(stv2->ident, av[1]))
280 44744
                                break;
281 44844
                if (stv2 == NULL)
282 0
                        ARGV_ERR("Unknown stevedore method \"%s\"\n", av[1]);
283
284 44644
                CHECK_OBJ_NOTNULL(stv2, STEVEDORE_MAGIC);
285 44644
                *stv = *stv2;
286 44644
                AN(stv->name);
287
288 44644
                av += 2;
289
290 44644
                stv->ident = ident;
291 44644
                stv->av = av;
292
293 44644
                if (stv->init != NULL)
294 44644
                        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 44644
                AN(stv->allocobj);
299 44644
                AN(stv->methods);
300
301 44644
                if (!strcmp(stv->ident, TRANSIENT_STORAGE)) {
302 22197
                        AZ(stv_transient);
303 22197
                        stv_transient = stv;
304 22197
                } else
305 22447
                        VTAILQ_INSERT_TAIL(&stevedores, stv, list);
306
                /* NB: Do not free av, stevedore gets to keep it */
307
        }
308 22197
        AN(stv_transient);
309 22197
        VTAILQ_INSERT_TAIL(&stevedores, stv_transient, list);
310 22197
}