cc_log_argv("Executing ", orig_args->argv);
exitfn_call();
execv(orig_args->argv[0], orig_args->argv);
- fatal("%s: execv returned (%s)", orig_args->argv[0], strerror(errno));
+ fatal("execv of %s failed: %s", orig_args->argv[0], strerror(errno));
+}
+
- static void
- clean_up_tmp_files()
- {
- /* delete intermediate pre-processor file if needed */
- if (i_tmpfile) {
- if (!direct_i_file) {
- tmp_unlink(i_tmpfile);
- }
- free(i_tmpfile);
- i_tmpfile = NULL;
- }
-
- /* delete the cpp stderr file if necessary */
- if (cpp_stderr) {
- tmp_unlink(cpp_stderr);
- free(cpp_stderr);
- cpp_stderr = NULL;
- }
- }
-
+static const char *
+temp_dir()
+{
+ static char *path = NULL;
+ if (path) return path; /* Memoize */
+ path = conf->temporary_dir;
+ if (str_eq(path, "")) {
+ path = format("%s/tmp", conf->cache_dir);
+ }
+ return path;
}
- stat(cache_dir, &st);
+ static void
+ add_pending_tmp_file(const char *path)
+ {
+ struct pending_tmp_file *e = x_malloc(sizeof(*e));
+ e->path = x_strdup(path);
+ e->next = pending_tmp_files;
+ pending_tmp_files = e;
+ }
+
+ static void
+ clean_up_pending_tmp_files(void)
+ {
+ struct pending_tmp_file *p = pending_tmp_files;
+ while (p) {
+ tmp_unlink(p->path);
+ p = p->next;
+ /* Leak p->path and p here because clean_up_pending_tmp_files needs to be signal
+ * safe. */
+ }
+ }
+
+ static void
+ signal_handler(int signo)
+ {
+ (void)signo;
+ clean_up_pending_tmp_files();
+ }
+
+ static void
+ clean_up_internal_tempdir(void)
+ {
+ DIR *dir;
+ struct dirent *entry;
+ struct stat st;
+ time_t now = time(NULL);
+
- update_mtime(cache_dir);
++ stat(conf->cache_dir, &st);
+ if (st.st_mtime + 3600 >= now) {
+ /* No cleanup needed. */
+ return;
+ }
+
- dir = opendir(temp_dir);
++ update_mtime(conf->cache_dir);
+
- path = format("%s/%s", temp_dir, entry->d_name);
++ dir = opendir(temp_dir());
+ if (!dir) {
+ return;
+ }
+
+ while ((entry = readdir(dir))) {
+ char *path;
+
+ if (str_eq(entry->d_name, ".") || str_eq(entry->d_name, "..")) {
+ continue;
+ }
+
++ path = format("%s/%s", temp_dir(), entry->d_name);
+ if (lstat(path, &st) == 0 && st.st_mtime + 3600 < now) {
+ tmp_unlink(path);
+ }
+ free(path);
+ }
+
+ closedir(dir);
+ }
+
/*
* Transform a name to a full path into the cache directory, creating needed
* sublevels if needed. Caller frees.
input_base[10] = 0;
}
- /* now the run */
- path_stderr = format("%s/tmp.cpp_stderr.%s", temp_dir, tmp_string());
+ path_stdout = format(
+ "%s/%s.tmp.%s.%s",
+ temp_dir(), input_base, tmp_string(), conf->cpp_extension);
+ path_stderr = format("%s/tmp.cpp_stderr.%s", temp_dir(), tmp_string());
+
+ if (create_parent_dirs(path_stdout) != 0) {
+ fatal("Failed to create parent directory for %s: %s\n",
+ path_stdout, strerror(errno));
+ }
+
++ add_pending_tmp_file(path_stdout);
+ add_pending_tmp_file(path_stderr);
+
time_of_compilation = time(NULL);
if (!direct_i_file) {
i_tmpfile = path_stdout;
- if (compile_preprocessed_source_code) {
+ if (conf->run_second_cpp) {
- tmp_unlink(path_stderr);
+ free(path_stderr);
+ } else {
/*
* If we are using the CPP trick, we need to remember this
* stderr data and output it just before the main stderr from
return result;
}
- exitfn_add_nullary(clean_up_tmp_files);
+static void
+create_initial_config_file(struct conf *conf, const char *path)
+{
+ unsigned max_files;
+ uint64_t max_size;
+ char *stats_dir;
+ FILE *f;
+ struct stat st;
+
+ if (create_parent_dirs(path) != 0) {
+ return;
+ }
+
+ stats_dir = format("%s/0", conf->cache_dir);
+ if (stat(stats_dir, &st) == 0) {
+ stats_get_obsolete_limits(stats_dir, &max_files, &max_size);
+ /* STATS_MAXFILES and STATS_MAXSIZE was stored for each top directory. */
+ max_files *= 16;
+ max_size *= 16;
+ } else {
+ max_files = 0;
+ max_size = conf->max_size;
+ }
+ free(stats_dir);
+
+ f = fopen(path, "w");
+ if (!f) {
+ return;
+ }
+ if (max_files != 0) {
+ fprintf(f, "max_files = %u\n", max_files);
+ conf->max_files = max_files;
+ }
+ if (max_size != 0) {
+ char *size = format_parsable_size_with_suffix(max_size);
+ fprintf(f, "max_size = %s\n", size);
+ free(size);
+ conf->max_size = max_size;
+ }
+ fclose(f);
+}
+
+/*
+ * Read config file(s), populate variables, create configuration file in cache
+ * directory if missing, etc.
+ */
+static void
+initialize(void)
+{
+ char *errmsg;
+ char *p;
+ struct stat st;
+ bool should_create_initial_config = false;
+
+ conf_free(conf);
+ conf = conf_create();
+
+ p = getenv("CCACHE_CONFIGPATH");
+ if (p) {
+ primary_config_path = x_strdup(p);
+ } else {
+ secondary_config_path = format("%s/ccache.conf", TO_STRING(SYSCONFDIR));
+ if (!conf_read(conf, secondary_config_path, &errmsg)) {
+ if (stat(secondary_config_path, &st) == 0) {
+ fatal("%s", errmsg);
+ }
+ /* Missing config file in SYSCONFDIR is OK. */
+ free(errmsg);
+ }
+
+ if ((p = getenv("CCACHE_DIR"))) {
+ free(conf->cache_dir);
+ conf->cache_dir = strdup(p);
+ }
+
+ primary_config_path = format("%s/ccache.conf", conf->cache_dir);
+ }
+
+ if (!conf_read(conf, primary_config_path, &errmsg)) {
+ if (stat(primary_config_path, &st) == 0) {
+ fatal("%s", errmsg);
+ }
+ should_create_initial_config = true;
+ }
+
+ if (!conf_update_from_environment(conf, &errmsg)) {
+ fatal("%s", errmsg);
+ }
+
+ if (conf->disable) {
+ should_create_initial_config = false;
+ }
+
+ if (should_create_initial_config) {
+ create_initial_config_file(conf, primary_config_path);
+ }
+
+ exitfn_init();
+ exitfn_add_nullary(stats_flush);
++ exitfn_add_nullary(clean_up_pending_tmp_files);
+
+ cc_log("=== CCACHE %s STARTED =========================================",
+ CCACHE_VERSION);
+
+ if (conf->umask != UINT_MAX) {
+ umask(conf->umask);
+ }
+}
+
/* Reset the global state. Used by the test suite. */
void
cc_reset(void)
/* Arguments to send to the real compiler. */
struct args *compiler_args;
- setup_uncached_err();
-
- if (!getenv("CCACHE_READONLY")) {
- if (create_cachedirtag(cache_dir) != 0) {
- cc_log("failed to create %s/CACHEDIR.TAG (%s)\n",
- cache_dir, strerror(errno));
- failed();
- }
- }
+ orig_args = args_init(argc, argv);
- sloppiness = parse_sloppiness(getenv("CCACHE_SLOPPINESS"));
+ initialize();
+ find_compiler(argv);
- cc_log_argv("Command line: ", argv);
- cc_log("Hostname: %s", get_hostname());
- cc_log("Working directory: %s", current_working_dir);
++ signal(SIGHUP, signal_handler);
++ signal(SIGINT, signal_handler);
++ signal(SIGTERM, signal_handler);
+
- if (base_dir) {
- cc_log("Base directory: %s", base_dir);
++ if (str_eq(conf->temporary_dir, "")) {
++ clean_up_internal_tempdir();
+ }
+
- if (getenv("CCACHE_UNIFY")) {
- cc_log("Unify mode enabled");
- enable_unify = true;
+ if (!str_eq(conf->log_file, "")) {
+ conf_print_items(conf, configuration_logger, NULL);
}
- if (getenv("CCACHE_NODIRECT") || enable_unify) {
- cc_log("Direct mode disabled");
- enable_direct = false;
+ if (conf->disable) {
+ cc_log("ccache is disabled");
+ failed();
}
- if (getenv("CCACHE_COMPRESS")) {
- cc_log("Compression enabled");
- enable_compression = true;
- }
+ setup_uncached_err();
- if ((env = getenv("CCACHE_NLEVELS"))) {
- nlevels = atoi(env);
- if (nlevels < 1) nlevels = 1;
- if (nlevels > 8) nlevels = 8;
+ cc_log_argv("Command line: ", argv);
+ cc_log("Hostname: %s", get_hostname());
+ cc_log("Working directory: %s", current_working_dir);
+
+ if (conf->unify) {
+ cc_log("Direct mode disabled because unify mode is enabled");
+ conf->direct_mode = false;
}
if (!cc_process_args(orig_args, &preprocessor_args, &compiler_args)) {