1 /*
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>
4 */
5 #include "cmogstored.h"
6 #include "cfg.h"
7
8 static void
paths_eql_or_die(const char * param,const char * a_orig,const char * b_orig,enum canonicalize_mode_t canon_mode)9 paths_eql_or_die(
10 const char *param, const char *a_orig, const char *b_orig,
11 enum canonicalize_mode_t canon_mode)
12 {
13 char *a = mog_canonpath_die(a_orig, canon_mode);
14 char *b = mog_canonpath_die(b_orig, canon_mode);
15 int ok = (strcmp(a, b) == 0);
16
17 free(a);
18 free(b);
19
20 if (ok) return;
21
22 die("conflicting path values for %s: `%s' != `%s'",
23 param, a_orig, b_orig);
24 }
25
merge_addr(struct mog_addrinfo ** dst,struct mog_addrinfo * src)26 static void merge_addr(struct mog_addrinfo **dst, struct mog_addrinfo *src)
27 {
28 if (!*dst && src) *dst = mog_listen_parse(src->orig);
29 }
30
merge_str(const char ** dst,const char * src)31 static void merge_str(const char **dst, const char *src)
32 {
33 if (!*dst && src) *dst = xstrdup(src);
34 }
35
validate_merge_common(struct mog_cfg * ent,struct mog_cfg * cli)36 static void validate_merge_common(struct mog_cfg *ent, struct mog_cfg *cli)
37 {
38 merge_addr(&cli->mgmtlisten, ent->mgmtlisten);
39 merge_addr(&cli->httplisten, ent->httplisten);
40 merge_addr(&cli->httpgetlisten, ent->httpgetlisten);
41
42 /* multiple config files can all specify the same pidfile */
43 if (cli->pidfile && ent->pidfile)
44 paths_eql_or_die("pidfile", cli->pidfile, ent->pidfile,
45 CAN_ALL_BUT_LAST);
46 merge_str(&cli->pidfile, ent->pidfile);
47
48 cli->maxconns += ent->maxconns;
49 cli->daemonize |= ent->daemonize;
50 }
51
mog_cfg_validate_one(void * ent_ptr,void * cli_ptr)52 bool mog_cfg_validate_one(void *ent_ptr, void *cli_ptr)
53 {
54 struct mog_cfg *ent = ent_ptr;
55 struct mog_cfg *cli = cli_ptr;
56
57 /*
58 * in the mixed single config file + CLI usage case, ensure docroot
59 * is the same (or only specified in one
60 */
61 if (cli->docroot && ent->docroot)
62 paths_eql_or_die("docroot", cli->docroot, ent->docroot,
63 CAN_EXISTING);
64 merge_str(&cli->docroot, ent->docroot);
65
66 validate_merge_common(ent, cli);
67
68 return true;
69 }
70
mog_cfg_validate_multi(void * ent_ptr,void * cli_ptr)71 bool mog_cfg_validate_multi(void *ent_ptr, void *cli_ptr)
72 {
73 struct mog_cfg *ent = ent_ptr;
74 struct mog_cfg *cli = cli_ptr;
75
76 if (!ent->configfile)
77 die("BUG: no config path");
78 if (!ent->httplisten && !ent->mgmtlisten && !ent->httpgetlisten)
79 die("no listeners in --config=%s", ent->configfile);
80 if (!ent->docroot)
81 die("no docroot in --config=%s", ent->configfile);
82
83 validate_merge_common(ent, cli);
84
85 return true;
86 }
87
warn_daemonize(size_t * nerr,const char * key,const char * val)88 static void warn_daemonize(size_t *nerr, const char *key, const char *val)
89 {
90 warn("%s=%s must use an absolute path", key, val);
91 (*nerr)++;
92 }
93
mog_cfg_validate_daemon(void * ent_ptr,void * nerr)94 bool mog_cfg_validate_daemon(void *ent_ptr, void *nerr)
95 {
96 struct mog_cfg *ent = ent_ptr;
97
98 if (ent->config&& ent->config[0] != '/')
99 warn_daemonize(nerr, "config", ent->config);
100 if (ent->pidfile && ent->pidfile[0] != '/')
101 warn_daemonize(nerr, "pidfile", ent->pidfile);
102 if (ent->docroot && ent->docroot[0] != '/')
103 warn_daemonize(nerr, "docroot", ent->docroot);
104
105 return true;
106 }
107
die_if_set(const void * a,const char * sw)108 static void die_if_set(const void *a, const char *sw)
109 {
110 if (!a) return;
111 die("--%s may not be used with multiple --config files", sw);
112 }
113
114 /*
115 * some settings we can't make sense of when supporting multiple
116 * config files
117 */
mog_cfg_die_if_cli_set(struct mog_cfg * cli)118 void mog_cfg_die_if_cli_set(struct mog_cfg *cli)
119 {
120 die_if_set(cli->docroot, "docroot");
121 die_if_set(cli->httplisten, "httplisten");
122 die_if_set(cli->mgmtlisten, "mgmtlisten");
123
124 /* we don't actually support --httpgetlisten on the CLI ... */
125 die_if_set(cli->httpgetlisten, "httpgetlisten");
126 }
127
mog_cfg_merge_defaults(struct mog_cfg * cli)128 void mog_cfg_merge_defaults(struct mog_cfg *cli)
129 {
130 if (!cli->docroot)
131 cli->docroot = xstrdup(MOG_DEFAULT_DOCROOT);
132
133 /* default listeners */
134 if (!cli->httplisten && !cli->httpgetlisten && !cli->mgmtlisten) {
135 cli->httplisten = mog_listen_parse(MOG_DEFAULT_HTTPLISTEN);
136 cli->mgmtlisten = mog_listen_parse(MOG_DEFAULT_MGMTLISTEN);
137 }
138 }
139
mog_cfg_check_server(struct mog_cfg * cfg)140 void mog_cfg_check_server(struct mog_cfg *cfg)
141 {
142 const char *s = cfg->server;
143
144 if (!s) return;
145
146 if (strcmp(s, "none") == 0) return;
147 if (strcmp(s, "perlbal") == 0)
148 warn("W: using internal HTTP for 'server = perlbal' instead");
149 else
150 die("E: 'server = %s' not understood by cmogstored", s);
151 }
152