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