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