1 // Copyright (C) 2011-2019 Joel Rosdahl
3 // This program is free software; you can redistribute it and/or modify it
4 // under the terms of the GNU General Public License as published by the Free
5 // Software Foundation; either version 3 of the License, or (at your option)
8 // This program is distributed in the hope that it will be useful, but WITHOUT
9 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 // You should have received a copy of the GNU General Public License along with
14 // this program; if not, write to the Free Software Foundation, Inc., 51
15 // Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 #include "confitems.h"
19 #include "envtoconfitems.h"
22 enum handle_conf_result {
28 static const struct conf_item *
29 find_conf(const char *name)
31 return confitems_get(name, strlen(name));
34 static const struct env_to_conf_item *
35 find_env_to_conf(const char *name)
37 return envtoconfitems_get(name, strlen(name));
40 static enum handle_conf_result
41 handle_conf_setting(struct conf *conf, const char *key, const char *value,
42 char **errmsg, bool from_env_variable, bool negate_boolean,
45 const struct conf_item *item = find_conf(key);
47 return HANDLE_CONF_UNKNOWN;
50 if (from_env_variable && item->parser == confitem_parse_bool) {
51 // Special rule for boolean settings from the environment: "0", "false",
52 // "disable" and "no" (case insensitive) are invalid, and all other values
55 // Previously any value meant true, but this was surprising to users, who
56 // might do something like CCACHE_DISABLE=0 and expect ccache to be
58 if (str_eq(value, "0") || strcasecmp(value, "false") == 0
59 || strcasecmp(value, "disable") == 0 || strcasecmp(value, "no") == 0) {
60 fatal("invalid boolean environment variable value \"%s\"", value);
63 bool *boolvalue = (bool *)((char *)conf + item->offset);
64 *boolvalue = !negate_boolean;
68 if (!item->parser(value, (char *)conf + item->offset, errmsg)) {
69 return HANDLE_CONF_FAIL;
71 if (item->verifier && !item->verifier((char *)conf + item->offset, errmsg)) {
72 return HANDLE_CONF_FAIL;
76 conf->item_origins[item->number] = origin;
77 return HANDLE_CONF_OK;
81 parse_line(const char *line, char **key, char **value, char **errmsg)
83 #define SKIP_WS(x) do { while (isspace(*x)) { ++x; } } while (false)
90 if (*p == '\0' || *p == '#') {
94 while (isalpha(*q) || *q == '_') {
97 *key = x_strndup(p, q - p);
101 *errmsg = x_strdup("missing equal sign");
108 // Skip leading whitespace.
114 // Skip trailing whitespace.
115 while (isspace(q[-1])) {
118 *value = x_strndup(p, q - p);
125 // Create a conf struct with default values.
129 struct conf *conf = x_malloc(sizeof(*conf));
130 conf->base_dir = x_strdup("");
131 conf->cache_dir = format("%s/.ccache", get_home_directory());
132 conf->cache_dir_levels = 2;
133 conf->compiler = x_strdup("");
134 conf->compiler_check = x_strdup("mtime");
135 conf->compression = false;
136 conf->compression_level = 6;
137 conf->cpp_extension = x_strdup("");
139 conf->depend_mode = false;
140 conf->direct_mode = true;
141 conf->disable = false;
142 conf->extra_files_to_hash = x_strdup("");
143 conf->hard_link = false;
144 conf->hash_dir = true;
145 conf->ignore_headers_in_manifest = x_strdup("");
146 conf->keep_comments_cpp = false;
147 conf->limit_multiple = 0.8;
148 conf->log_file = x_strdup("");
150 conf->max_size = (uint64_t)5 * 1000 * 1000 * 1000;
151 conf->path = x_strdup("");
152 conf->pch_external_checksum = false;
153 conf->prefix_command = x_strdup("");
154 conf->prefix_command_cpp = x_strdup("");
155 conf->read_only = false;
156 conf->read_only_direct = false;
157 conf->recache = false;
158 conf->run_second_cpp = true;
159 conf->sloppiness = 0;
161 conf->temporary_dir = x_strdup("");
162 conf->umask = UINT_MAX; // Default: don't set umask.
164 conf->item_origins = x_malloc(confitems_count() * sizeof(char *));
165 for (size_t i = 0; i < confitems_count(); ++i) {
166 conf->item_origins[i] = "default";
172 conf_free(struct conf *conf)
177 free(conf->base_dir);
178 free(conf->cache_dir);
179 free(conf->compiler);
180 free(conf->compiler_check);
181 free(conf->cpp_extension);
182 free(conf->extra_files_to_hash);
183 free(conf->ignore_headers_in_manifest);
184 free(conf->log_file);
186 free(conf->prefix_command);
187 free(conf->prefix_command_cpp);
188 free(conf->temporary_dir);
189 free((void *)conf->item_origins); // Workaround for MSVC warning
193 // Note: The path pointer is stored in conf, so path must outlive conf.
195 // On failure, if an I/O error occured errno is set appropriately, otherwise
196 // errno is set to zero indicating that config itself was invalid.
198 conf_read(struct conf *conf, const char *path, char **errmsg)
203 FILE *f = fopen(path, "r");
205 *errmsg = format("%s: %s", path, strerror(errno));
209 unsigned line_number = 0;
212 while (fgets(buf, sizeof(buf), f)) {
218 enum handle_conf_result hcr = HANDLE_CONF_OK;
219 bool ok = parse_line(buf, &key, &value, &errmsg2);
220 if (ok && key) { // key == NULL if comment or blank line.
222 handle_conf_setting(conf, key, value, &errmsg2, false, false, path);
223 ok = hcr != HANDLE_CONF_FAIL; // unknown is OK
228 *errmsg = format("%s:%u: %s", path, line_number, errmsg2);
236 *errmsg = x_strdup(strerror(errno));
246 conf_update_from_environment(struct conf *conf, char **errmsg)
248 for (char **p = environ; *p; ++p) {
249 if (!str_startswith(*p, "CCACHE_")) {
252 char *q = strchr(*p, '=');
259 if (str_startswith(*p + 7, "NO")) {
266 char *key = x_strndup(*p + key_start, q - *p - key_start);
268 ++q; // Now points to the value.
270 const struct env_to_conf_item *env_to_conf_item = find_env_to_conf(key);
271 if (!env_to_conf_item) {
276 char *errmsg2 = NULL;
277 enum handle_conf_result hcr = handle_conf_setting(
278 conf, env_to_conf_item->conf_name, q, &errmsg2, true, negate,
280 if (hcr != HANDLE_CONF_OK) {
281 *errmsg = format("%s: %s", key, errmsg2);
294 conf_set_value_in_file(const char *path, const char *key, const char *value,
297 const struct conf_item *item = find_conf(key);
299 *errmsg = format("unknown configuration option \"%s\"", key);
303 FILE *infile = fopen(path, "r");
305 *errmsg = format("%s: %s", path, strerror(errno));
309 char *outpath = format("%s.tmp", path);
310 FILE *outfile = create_tmp_file(&outpath, "w");
312 *errmsg = format("%s: %s", outpath, strerror(errno));
320 while (fgets(buf, sizeof(buf), infile)) {
324 bool ok = parse_line(buf, &key2, &value2, &errmsg2);
325 if (ok && key2 && str_eq(key2, key)) {
327 fprintf(outfile, "%s = %s\n", key, value);
336 fprintf(outfile, "%s = %s\n", key, value);
341 if (x_rename(outpath, path) != 0) {
342 *errmsg = format("rename %s to %s: %s", outpath, path, strerror(errno));
351 conf_print_value(struct conf *conf, const char *key,
352 FILE *file, char **errmsg)
354 const struct conf_item *item = find_conf(key);
356 *errmsg = format("unknown configuration option \"%s\"", key);
359 void *value = (char *)conf + item->offset;
360 char *str = item->formatter(value);
361 fprintf(file, "%s\n", str);
367 print_item(struct conf *conf, const char *key,
368 void (*printer)(const char *descr, const char *origin,
372 const struct conf_item *item = find_conf(key);
376 void *value = (char *)conf + item->offset;
377 char *str = item->formatter(value);
378 char *buf = x_strdup("");
379 reformat(&buf, "%s = %s", key, str);
380 printer(buf, conf->item_origins[item->number], context);
387 conf_print_items(struct conf *conf,
388 void (*printer)(const char *descr, const char *origin,
393 ok &= print_item(conf, "base_dir", printer, context);
394 ok &= print_item(conf, "cache_dir", printer, context);
395 ok &= print_item(conf, "cache_dir_levels", printer, context);
396 ok &= print_item(conf, "compiler", printer, context);
397 ok &= print_item(conf, "compiler_check", printer, context);
398 ok &= print_item(conf, "compression", printer, context);
399 ok &= print_item(conf, "compression_level", printer, context);
400 ok &= print_item(conf, "cpp_extension", printer, context);
401 ok &= print_item(conf, "debug", printer, context);
402 ok &= print_item(conf, "depend_mode", printer, context);
403 ok &= print_item(conf, "direct_mode", printer, context);
404 ok &= print_item(conf, "disable", printer, context);
405 ok &= print_item(conf, "extra_files_to_hash", printer, context);
406 ok &= print_item(conf, "hard_link", printer, context);
407 ok &= print_item(conf, "hash_dir", printer, context);
408 ok &= print_item(conf, "ignore_headers_in_manifest", printer, context);
409 ok &= print_item(conf, "keep_comments_cpp", printer, context);
410 ok &= print_item(conf, "limit_multiple", printer, context);
411 ok &= print_item(conf, "log_file", printer, context);
412 ok &= print_item(conf, "max_files", printer, context);
413 ok &= print_item(conf, "max_size", printer, context);
414 ok &= print_item(conf, "path", printer, context);
415 ok &= print_item(conf, "pch_external_checksum", printer, context);
416 ok &= print_item(conf, "prefix_command", printer, context);
417 ok &= print_item(conf, "prefix_command_cpp", printer, context);
418 ok &= print_item(conf, "read_only", printer, context);
419 ok &= print_item(conf, "read_only_direct", printer, context);
420 ok &= print_item(conf, "recache", printer, context);
421 ok &= print_item(conf, "run_second_cpp", printer, context);
422 ok &= print_item(conf, "sloppiness", printer, context);
423 ok &= print_item(conf, "stats", printer, context);
424 ok &= print_item(conf, "temporary_dir", printer, context);
425 ok &= print_item(conf, "umask", printer, context);
426 ok &= print_item(conf, "unify", printer, context);