varnish-cache/bin/varnishd/storage/mgt_stevedore.c
1
/*-
2
 * Copyright (c) 2007-2011 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Dag-Erling Smørgav <des@des.no>
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 *
28
 * STEVEDORE: one who works at or is responsible for loading and
29
 * unloading ships in port.  Example: "on the wharves, stevedores were
30
 * unloading cargo from the far corners of the world." Origin: Spanish
31
 * estibador, from estibar to pack.  First Known Use: 1788
32
 */
33
34
#include "config.h"
35
36
#include <stdio.h>
37
#include <stdlib.h>
38
#include <string.h>
39
#include <unistd.h>
40
41
#include "mgt/mgt.h"
42
#include "common/heritage.h"
43
#include "vcli_serve.h"
44
45
#include "storage/storage.h"
46
47
static VTAILQ_HEAD(, stevedore) stevedores =
48
    VTAILQ_HEAD_INITIALIZER(stevedores);
49
50
/* Name of transient storage */
51
#define TRANSIENT_STORAGE       "Transient"
52
53
struct stevedore *stv_transient;
54
55
/*--------------------------------------------------------------------*/
56
57
int
58 37014
STV__iter(struct stevedore ** const pp)
59
{
60
61 37014
        AN(pp);
62 37014
        CHECK_OBJ_ORNULL(*pp, STEVEDORE_MAGIC);
63 37014
        if (*pp != NULL)
64 22648
                *pp = VTAILQ_NEXT(*pp, list);
65
        else
66 14366
                *pp = VTAILQ_FIRST(&stevedores);
67 37014
        return (*pp != NULL);
68
}
69
70
/*--------------------------------------------------------------------*/
71
72
static void v_matchproto_(cli_func_t)
73 8
stv_cli_list(struct cli *cli, const char * const *av, void *priv)
74
{
75
        struct stevedore *stv;
76
77 8
        ASSERT_MGT();
78
        (void)av;
79
        (void)priv;
80 8
        VCLI_Out(cli, "Storage devices:\n");
81 34
        STV_Foreach(stv)
82 18
                VCLI_Out(cli, "\tstorage.%s = %s\n", stv->ident, stv->name);
83 8
}
84
85
static void v_matchproto_(cli_func_t)
86 2
stv_cli_list_json(struct cli *cli, const char * const *av, void *priv)
87
{
88
        struct stevedore *stv;
89 2
        int n = 0;
90
91
        (void)priv;
92 2
        ASSERT_MGT();
93 2
        VCLI_JSON_begin(cli, 2, av);
94 2
        VCLI_Out(cli, ",\n");
95 8
        STV_Foreach(stv) {
96 4
                VCLI_Out(cli, "%s", n ? ",\n" : "");
97 4
                n++;
98 4
                VCLI_Out(cli, "{\n");
99 4
                VSB_indent(cli->sb, 2);
100 4
                VCLI_Out(cli, "\"name\": ");
101 4
                VCLI_JSON_str(cli, stv->ident);
102 4
                VCLI_Out(cli, ",\n");
103 4
                VCLI_Out(cli, "\"storage\": ");
104 4
                VCLI_JSON_str(cli, stv->name);
105 4
                VSB_indent(cli->sb, -2);
106 4
                VCLI_Out(cli, "\n}");
107
        }
108 2
        VCLI_JSON_end(cli);
109 2
}
110
111
/*--------------------------------------------------------------------*/
112
113
static struct cli_proto cli_stv[] = {
114
        { CLICMD_STORAGE_LIST,          "", stv_cli_list, stv_cli_list_json },
115
        { NULL}
116
};
117
118
/*--------------------------------------------------------------------
119
 */
120
121
#ifdef WITH_PERSISTENT_STORAGE
122
static void v_matchproto_(storage_init_f)
123 2
smp_fake_init(struct stevedore *parent, int ac, char * const *av)
124
{
125
126
        (void)parent;
127
        (void)ac;
128
        (void)av;
129 2
        ARGV_ERR(
130
            "-spersistent has been deprecated, please see:\n"
131
            "  https://www.varnish-cache.org/docs/trunk/phk/persistent.html\n"
132
            "for details.\n"
133
        );
134
}
135
136
static const struct stevedore smp_fake_stevedore = {
137
        .magic = STEVEDORE_MAGIC,
138
        .name = "deprecated_persistent",
139
        .init = smp_fake_init,
140
};
141
#endif
142
143
/*--------------------------------------------------------------------
144
 * Parse a stevedore argument on the form:
145
 *      [ name '=' ] strategy [ ',' arg ] *
146
 */
147
148
static const struct choice STV_choice[] = {
149
        { "file",                       &smf_stevedore },
150
        { "malloc",                     &sma_stevedore },
151
#ifdef WITH_PERSISTENT_STORAGE
152
        { "deprecated_persistent",      &smp_stevedore },
153
        { "persistent",                 &smp_fake_stevedore },
154
#endif
155
#if defined(HAVE_UMEM_H)
156
        { "umem",                       &smu_stevedore },
157
        { "default",                    &smu_stevedore },
158
#else
159
        { "default",                    &sma_stevedore },
160
#endif
161
        { NULL,         NULL }
162
};
163
164
static void
165 2898
stv_check_ident(const char *spec, const char *ident)
166
{
167
        struct stevedore *stv;
168 2898
        unsigned found = 0;
169
170 2898
        if (!strcmp(ident, TRANSIENT_STORAGE))
171 1438
                found = (stv_transient != NULL);
172
        else {
173 2958
                STV_Foreach(stv)
174 42
                        if (!strcmp(stv->ident, ident)) {
175 4
                                found = 1;
176 4
                                break;
177
                        }
178
        }
179
180 2898
        if (found)
181 6
                ARGV_ERR("(-s %s) '%s' is already defined\n", spec, ident);
182 2892
}
183
184
void
185 2902
STV_Config(const char *spec)
186
{
187
        char **av, buf[8];
188
        const char *ident;
189
        struct stevedore *stv;
190
        const struct stevedore *stv2;
191
        int ac;
192
        static unsigned seq = 0;
193
194 2902
        av = MGT_NamedArg(spec, &ident, "-s");
195 2898
        AN(av);
196
197 2898
        if (av[1] == NULL)
198 0
                ARGV_ERR("-s argument lacks strategy {malloc, file, ...}\n");
199
200 4416
        for (ac = 0; av[ac + 2] != NULL; ac++)
201 1518
                continue;
202
203 2898
        stv2 = MGT_Pick(STV_choice, av[1], "storage");
204 2898
        AN(stv2);
205
206
        /* Append strategy to ident string */
207 2898
        VSB_printf(vident, ",-s%s", av[1]);
208
209 2898
        av += 2;
210
211 2898
        CHECK_OBJ_NOTNULL(stv2, STEVEDORE_MAGIC);
212 2898
        ALLOC_OBJ(stv, STEVEDORE_MAGIC);
213 2898
        AN(stv);
214
215 2898
        *stv = *stv2;
216 2898
        AN(stv->name);
217
218 2898
        if (ident) {
219 1474
                stv->ident = ident;
220
        } else {
221 1424
                bprintf(buf, "s%u", seq++);
222 1424
                stv->ident = strdup(buf);
223
        }
224 2898
        AN(stv->ident);
225 2898
        stv_check_ident(spec, stv->ident);
226
227 2892
        if (stv->init != NULL)
228 2892
                stv->init(stv, ac, av);
229 0
        else if (ac != 0)
230 0
                ARGV_ERR("(-s %s) too many arguments\n", stv->name);
231
232 2890
        AN(stv->allocobj);
233 2890
        AN(stv->methods);
234
235 2890
        if (!strcmp(stv->ident, TRANSIENT_STORAGE)) {
236 1436
                AZ(stv_transient);
237 1436
                stv_transient = stv;
238
        } else
239 1454
                VTAILQ_INSERT_TAIL(&stevedores, stv, list);
240
        /* NB: Do not free av, stevedore gets to keep it */
241 2890
}
242
243
/*--------------------------------------------------------------------*/
244
245
void
246 1434
STV_Config_Transient(void)
247
{
248
249 1434
        ASSERT_MGT();
250
251 1434
        VCLS_AddFunc(mgt_cls, MCF_AUTH, cli_stv);
252 1434
        if (stv_transient == NULL)
253 1412
                STV_Config(TRANSIENT_STORAGE "=default");
254 1434
        AN(stv_transient);
255 1434
        VTAILQ_INSERT_TAIL(&stevedores, stv_transient, list);
256 1434
}