1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
30 #include "path-util.h"
35 static bool arg_no_pager = false;
37 static int equivalent(const char *a, const char *b) {
41 x = canonicalize_file_name(a);
45 y = canonicalize_file_name(b);
58 static int found_override(const char *top, const char *bottom) {
66 if (null_or_empty_path(top) > 0) {
67 printf(ANSI_HIGHLIGHT_RED_ON "[MASK]" ANSI_HIGHLIGHT_OFF " %s → %s\n", top, bottom);
71 k = readlink_malloc(top, &dest);
73 if (equivalent(dest, bottom) > 0)
74 printf(ANSI_HIGHLIGHT_GREEN_ON "[EQUIVALENT]" ANSI_HIGHLIGHT_OFF " %s → %s\n", top, bottom);
76 printf(ANSI_HIGHLIGHT_ON "[REDIRECT]" ANSI_HIGHLIGHT_OFF " %s → %s\n", top, bottom);
82 printf(ANSI_HIGHLIGHT_ON "[OVERRIDE]" ANSI_HIGHLIGHT_OFF " %s → %s\n", top, bottom);
90 log_error("Failed to fork off diff: %m");
92 } else if (pid == 0) {
93 execlp("diff", "diff", "-us", "--", bottom, top, NULL);
94 log_error("Failed to execute diff: %m");
98 wait_for_terminate(pid, NULL);
107 static int enumerate_dir(Hashmap *top, Hashmap *bottom, const char *path) {
120 log_error("Failed to enumerate %s: %m", path);
125 struct dirent *de, buf;
129 k = readdir_r(d, &buf, &de);
138 if (!dirent_is_file(de))
141 p = join(path, "/", de->d_name, NULL);
147 path_kill_slashes(p);
149 k = hashmap_put(top, path_get_file_name(p), p);
156 } else if (k != -EEXIST) {
162 free(hashmap_remove(bottom, path_get_file_name(p)));
163 k = hashmap_put(bottom, path_get_file_name(p), p);
177 static int process_suffix(const char *prefixes, const char *suffix) {
180 Hashmap *top, *bottom;
188 top = hashmap_new(string_hash_func, string_compare_func);
194 bottom = hashmap_new(string_hash_func, string_compare_func);
200 NULSTR_FOREACH(p, prefixes) {
203 t = join(p, "/", suffix, NULL);
209 k = enumerate_dir(top, bottom, t);
213 log_debug("Looking at %s", t);
217 HASHMAP_FOREACH(f, top, i) {
220 o = hashmap_get(bottom, path_get_file_name(f));
223 if (path_equal(o, f))
226 k = found_override(f, o);
235 hashmap_free_free(top);
237 hashmap_free_free(bottom);
239 return r < 0 ? r : n_found;
242 static int process_suffix_chop(const char *prefixes, const char *suffix) {
248 if (!path_is_absolute(suffix))
249 return process_suffix(prefixes, suffix);
251 /* Strip prefix from the suffix */
252 NULSTR_FOREACH(p, prefixes) {
253 if (startswith(suffix, p)) {
254 suffix += strlen(p);;
255 suffix += strspn(suffix, "/");
256 return process_suffix(prefixes, suffix);
260 log_error("Invalid suffix specification %s.", suffix);
264 static void help(void) {
266 printf("%s [OPTIONS...] [SUFFIX...]\n\n"
267 "Find overridden configuration files.\n\n"
268 " -h --help Show this help\n"
269 " --version Show package version\n"
270 " --no-pager Do not pipe output into a pager\n",
271 program_invocation_short_name);
274 static int parse_argv(int argc, char *argv[]) {
277 ARG_NO_PAGER = 0x100,
281 static const struct option options[] = {
282 { "help", no_argument, NULL, 'h' },
283 { "version", no_argument, NULL, ARG_VERSION },
284 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
293 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
302 puts(PACKAGE_STRING);
304 puts(SYSTEMD_FEATURES);
315 log_error("Unknown option code %c", c);
323 int main(int argc, char *argv[]) {
325 const char prefixes[] =
332 #ifdef HAVE_SPLIT_USR
337 const char suffixes[] =
350 log_parse_environment();
353 r = parse_argv(argc, argv);
363 for (i = optind; i < argc; i++) {
364 k = process_suffix_chop(prefixes, argv[i]);
374 NULSTR_FOREACH(n, suffixes) {
375 k = process_suffix(prefixes, n);
384 printf("\n%i overriden configuration files found.\n", n_found);
389 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;