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;
41 SHOW_OVERRIDEN = 1 << 3,
42 SHOW_UNCHANGED = 1 << 4,
46 (SHOW_MASKED | SHOW_EQUIV | SHOW_REDIR | SHOW_OVERRIDEN | SHOW_DIFF)
49 static int equivalent(const char *a, const char *b) {
53 x = canonicalize_file_name(a);
57 y = canonicalize_file_name(b);
72 static int notify_override_masked(int flags, const char *top, const char *bottom) {
73 if (!(flags & SHOW_MASKED))
76 printf(ANSI_HIGHLIGHT_RED_ON "[MASK]" ANSI_HIGHLIGHT_OFF " %s → %s\n", top, bottom);
80 static int notify_override_equiv(int flags, const char *top, const char *bottom) {
81 if (!(flags & SHOW_EQUIV))
84 printf(ANSI_HIGHLIGHT_GREEN_ON "[EQUIVALENT]" ANSI_HIGHLIGHT_OFF " %s → %s\n", top, bottom);
88 static int notify_override_redir(int flags, const char *top, const char *bottom) {
89 if (!(flags & SHOW_REDIR))
92 printf(ANSI_HIGHLIGHT_ON "[REDIRECT]" ANSI_HIGHLIGHT_OFF " %s → %s\n", top, bottom);
96 static int notify_override_overriden(int flags, const char *top, const char *bottom) {
97 if (!(flags & SHOW_OVERRIDEN))
100 printf(ANSI_HIGHLIGHT_ON "[OVERRIDE]" ANSI_HIGHLIGHT_OFF " %s → %s\n", top, bottom);
104 static int notify_override_unchanged(int flags, const char *top, const char *bottom) {
105 if (!(flags & SHOW_UNCHANGED))
108 printf(ANSI_HIGHLIGHT_ON "[UNCHANGED]" ANSI_HIGHLIGHT_OFF " %s → %s\n", top, bottom);
112 static int found_override(int flags, const char *top, const char *bottom) {
120 if (null_or_empty_path(top) > 0) {
121 notify_override_masked(flags, top, bottom);
125 k = readlink_malloc(top, &dest);
127 if (equivalent(dest, bottom) > 0)
128 notify_override_equiv(flags, top, bottom);
130 notify_override_redir(flags, top, bottom);
136 notify_override_overriden(flags, top, bottom);
137 if (!(flags & SHOW_DIFF))
146 log_error("Failed to fork off diff: %m");
148 } else if (pid == 0) {
149 execlp("diff", "diff", "-us", "--", bottom, top, NULL);
150 log_error("Failed to execute diff: %m");
154 wait_for_terminate(pid, NULL);
163 static int enumerate_dir(Hashmap *top, Hashmap *bottom, const char *path) {
176 log_error("Failed to enumerate %s: %m", path);
181 struct dirent *de, buf;
185 k = readdir_r(d, &buf, &de);
194 if (!dirent_is_file(de))
197 p = join(path, "/", de->d_name, NULL);
203 path_kill_slashes(p);
205 k = hashmap_put(top, path_get_file_name(p), p);
212 } else if (k != -EEXIST) {
218 free(hashmap_remove(bottom, path_get_file_name(p)));
219 k = hashmap_put(bottom, path_get_file_name(p), p);
233 static int process_suffix(int flags, const char *prefixes, const char *suffix) {
236 Hashmap *top, *bottom;
244 top = hashmap_new(string_hash_func, string_compare_func);
250 bottom = hashmap_new(string_hash_func, string_compare_func);
256 NULSTR_FOREACH(p, prefixes) {
259 t = join(p, "/", suffix, NULL);
265 k = enumerate_dir(top, bottom, t);
269 log_debug("Looking at %s", t);
273 HASHMAP_FOREACH(f, top, i) {
276 o = hashmap_get(bottom, path_get_file_name(f));
279 if (path_equal(o, f)) {
280 notify_override_unchanged(flags, f, o);
284 k = found_override(flags, f, o);
293 hashmap_free_free(top);
295 hashmap_free_free(bottom);
297 return r < 0 ? r : n_found;
300 static int process_suffix_chop(int flags, const char *prefixes, const char *suffix) {
306 if (!path_is_absolute(suffix))
307 return process_suffix(flags, prefixes, suffix);
309 /* Strip prefix from the suffix */
310 NULSTR_FOREACH(p, prefixes) {
311 if (startswith(suffix, p)) {
312 suffix += strlen(p);;
313 suffix += strspn(suffix, "/");
314 return process_suffix(flags, prefixes, suffix);
318 log_error("Invalid suffix specification %s.", suffix);
322 static void help(void) {
324 printf("%s [OPTIONS...] [SUFFIX...]\n\n"
325 "Find overridden configuration files.\n\n"
326 " -h --help Show this help\n"
327 " --version Show package version\n"
328 " --no-pager Do not pipe output into a pager\n"
329 " --diff[=1|0] Show a diff when overriden files differ\n"
330 " -t --type=LIST... Only display a selected set of override types\n",
331 program_invocation_short_name);
334 static int parse_flags(int flags, const char *flag_str) {
338 FOREACH_WORD(w, l, flag_str, state) {
339 if (strncmp("masked", w, l) == 0) {
340 flags |= SHOW_MASKED;
341 } else if (strncmp ("equivalent", w, l) == 0) {
343 } else if (strncmp("redirected", w, l) == 0) {
345 } else if (strncmp("override", w, l) == 0) {
346 flags |= SHOW_OVERRIDEN;
347 } else if (strncmp("unchanged", w, l) == 0) {
348 flags |= SHOW_UNCHANGED;
349 } else if (strncmp("default", w, l) == 0) {
350 flags |= SHOW_DEFAULTS;
352 log_error("Unknown type filter: %s", w);
359 static int parse_argv(int argc, char *argv[], int *flags) {
362 ARG_NO_PAGER = 0x100,
367 static const struct option options[] = {
368 { "help", no_argument, NULL, 'h' },
369 { "version", no_argument, NULL, ARG_VERSION },
370 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
371 { "diff", optional_argument, NULL, ARG_DIFF },
372 { "type", required_argument, NULL, 't' },
381 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
390 puts(PACKAGE_STRING);
392 puts(SYSTEMD_FEATURES);
403 *flags = parse_flags(*flags, optarg);
412 if (parse_boolean(optarg))
415 *flags &= ~SHOW_DIFF;
420 log_error("Unknown option code %c", c);
428 int main(int argc, char *argv[]) {
430 const char prefixes[] =
437 #ifdef HAVE_SPLIT_USR
442 const char suffixes[] =
449 "systemd/system.preset\0"
450 "systemd/user.preset\0"
458 log_parse_environment();
461 r = parse_argv(argc, argv, &flags);
466 flags = SHOW_DEFAULTS;
467 if (flags == SHOW_DIFF)
468 flags |= SHOW_OVERRIDEN;
476 for (i = optind; i < argc; i++) {
477 k = process_suffix_chop(flags, prefixes, argv[i]);
487 NULSTR_FOREACH(n, suffixes) {
488 k = process_suffix(flags, prefixes, n);
497 printf("\n%i overriden configuration files found.\n", n_found);
502 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;