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