2 * Copyright (C) 2012-2020 all contributors <cmogstored-public@yhbt.net>
3 * License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
5 #include "cmogstored.h"
8 static Hash_table
*all_cfg
; /* we support multiple configs -> svcs */
9 struct mog_cfg mog_cli
;
12 static void cfg_free_internal(struct mog_cfg
*cfg
)
14 mog_free(cfg
->docroot
);
15 mog_free(cfg
->pidfile
);
16 mog_free(cfg
->config
);
17 mog_free(cfg
->configfile
);
18 mog_free(cfg
->server
);
19 mog_addrinfo_free(&cfg
->mgmtlisten
);
20 mog_addrinfo_free(&cfg
->httplisten
);
21 mog_addrinfo_free(&cfg
->httpgetlisten
);
22 /* let svc.c deal with cfg->svc for now */
25 static void cfg_free(void *ptr
)
27 struct mog_cfg
*cfg
= ptr
;
28 cfg_free_internal(cfg
);
32 static size_t cfg_hash(const void *x
, size_t tablesize
)
34 const struct mog_cfg
*cfg
= x
;
36 return hash_string(cfg
->configfile
, tablesize
);
39 static bool cfg_cmp(const void *a
, const void *b
)
41 const struct mog_cfg
*cfg_a
= a
;
42 const struct mog_cfg
*cfg_b
= b
;
44 return strcmp(cfg_a
->configfile
, cfg_b
->configfile
) == 0;
47 static void cfg_atexit(void)
50 cfg_free_internal(&mog_cli
);
53 __attribute__((constructor
)) static void cfg_init(void)
55 all_cfg
= hash_initialize(7, NULL
, cfg_hash
, cfg_cmp
, cfg_free
);
56 mog_oom_if_null(all_cfg
);
61 struct mog_cfg
* mog_cfg_new(const char *configfile
)
63 struct mog_cfg
*cfg
= xzalloc(sizeof(struct mog_cfg
));
65 cfg
->configfile
= mog_canonpath_die(configfile
, CAN_EXISTING
);
66 cfg
->config
= xstrdup(configfile
);
68 switch (hash_insert_if_absent(all_cfg
, cfg
, NULL
)) {
79 int mog_cfg_load(struct mog_cfg
*cfg
)
85 int fd
= open(cfg
->configfile
, O_RDONLY
);
88 if (fstat(fd
, &sb
) < 0) goto out
;
90 buf
= xmalloc(sb
.st_size
+ strlen("\n"));
93 r
= read(fd
, buf
, sb
.st_size
);
95 die("read(..., %ld) failed on %s: %s",
96 (long)sb
.st_size
, cfg
->configfile
,
97 errno
? strerror(errno
) : "EOF");
99 buf
[r
] = '\n'; /* parser _needs_ a trailing newline */
100 rc
= mog_cfg_parse(cfg
, buf
, r
+ 1);
104 if (fd
>= 0) mog_close(fd
);
110 static size_t nr_config(void)
112 return all_cfg
? hash_get_n_entries(all_cfg
) : 0;
115 #define RELPATH_ERR \
116 "relative paths are incompatible with --daemonize and SIGUSR2 upgrades"
117 static void validate_daemonize(struct mog_cfg
*cli
)
120 const char *path
= getenv("PATH");
123 hash_do_for_each(all_cfg
, mog_cfg_validate_daemon
, &nerr
);
125 /* cli may have merged identical settings */
127 mog_cfg_validate_daemon(cli
, &nerr
);
129 /* we may use confstr(_CS_PATH) in the future, currently we do not */
131 die("PATH environment must be set");
135 /* trailing ':' in PATH is identical to trailing ":." (cwd) */
136 if (p
[strlen(p
) - 1] == ':')
148 warn("PATH environment contains relative path: %s", p
);
157 #define MULTI_CFG_ERR \
158 "--multi must be set if using multiple --config/-c switches"
160 void mog_cfg_validate_or_die(struct mog_cfg
*cli
)
162 switch (nr_config()) {
164 mog_cfg_merge_defaults(cli
);
165 assert(cli
->configfile
== NULL
&&
166 "BUG: --config was set but not detected");
167 break; /* CLI-only */
169 hash_do_for_each(all_cfg
, mog_cfg_validate_one
, cli
);
170 mog_cfg_merge_defaults(cli
);
172 default: /* multiple config files */
173 mog_cfg_die_if_cli_set(cli
);
174 hash_do_for_each(all_cfg
, mog_cfg_validate_multi
, cli
);
179 validate_daemonize(cli
);
180 mog_set_maxconns(cli
->maxconns
);
183 static struct mog_fd
*
184 bind_or_die(struct mog_addrinfo
*a
, struct mog_svc
*svc
, mog_post_accept_fn fn
)
188 if (a
== NULL
) return NULL
;
189 fd
= mog_bind_listen(a
->addr
);
191 die_errno("addr=%s failed to bind+listen", a
->orig
);
193 return mog_accept_init(fd
, svc
, a
, fn
);
196 static bool svc_from_cfg(void *cfg_ptr
, void *ignored
)
198 struct mog_cfg
*cfg
= cfg_ptr
;
201 assert(cfg
->docroot
&& "no docroot specified");
202 svc
= mog_svc_new(cfg
->docroot
);
204 die("failed to load svc from docroot=%s", cfg
->docroot
);
206 svc
->mgmt_mfd
= bind_or_die(cfg
->mgmtlisten
, svc
, mog_mgmt_post_accept
);
208 if (cfg
->server
&& strcmp(cfg
->server
, "none") == 0)
211 svc
->http_mfd
= bind_or_die(cfg
->httplisten
, svc
, mog_http_post_accept
);
212 svc
->httpget_mfd
= bind_or_die(cfg
->httpgetlisten
, svc
,
213 mog_httpget_post_accept
);
218 void mog_cfg_svc_start_or_die(struct mog_cfg
*cli
)
220 switch (nr_config()) {
223 svc_from_cfg(cli
, NULL
);
226 hash_do_for_each(all_cfg
, svc_from_cfg
, NULL
);