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 #define SHOW_MASKED 1 << 0
59 #define SHOW_EQUIV 1 << 1
60 #define SHOW_REDIR 1 << 2
61 #define SHOW_OVERRIDEN 1 << 3
62 #define SHOW_UNCHANGED 1 << 4
63 #define SHOW_DIFF 1 << 5
65 #define SHOW_DEFAULTS \
66 (SHOW_MASKED | SHOW_EQUIV | SHOW_REDIR | SHOW_OVERRIDEN | SHOW_DIFF)
68 static int notify_override_masked(int flags, const char *top, const char *bottom) {
69 if (!(flags & SHOW_MASKED))
72 printf(ANSI_HIGHLIGHT_RED_ON "[MASK]" ANSI_HIGHLIGHT_OFF " %s → %s\n", top, bottom);
76 static int notify_override_equiv(int flags, const char *top, const char *bottom) {
77 if (!(flags & SHOW_EQUIV))
80 printf(ANSI_HIGHLIGHT_GREEN_ON "[EQUIVALENT]" ANSI_HIGHLIGHT_OFF " %s → %s\n", top, bottom);
84 static int notify_override_redir(int flags, const char *top, const char *bottom) {
85 if (!(flags & SHOW_REDIR))
88 printf(ANSI_HIGHLIGHT_ON "[REDIRECT]" ANSI_HIGHLIGHT_OFF " %s → %s\n", top, bottom);
92 static int notify_override_overriden(int flags, const char *top, const char *bottom) {
93 if (!(flags & SHOW_OVERRIDEN))
96 printf(ANSI_HIGHLIGHT_ON "[OVERRIDE]" ANSI_HIGHLIGHT_OFF " %s → %s\n", top, bottom);
100 static int notify_override_unchanged(int flags, const char *top, const char *bottom) {
101 if (!(flags & SHOW_UNCHANGED))
104 printf(ANSI_HIGHLIGHT_ON "[UNCHANGED]" ANSI_HIGHLIGHT_OFF " %s → %s\n", top, bottom);
108 static int found_override(int flags, const char *top, const char *bottom) {
116 if (null_or_empty_path(top) > 0) {
117 notify_override_masked(flags, top, bottom);
121 k = readlink_malloc(top, &dest);
123 if (equivalent(dest, bottom) > 0)
124 notify_override_equiv(flags, top, bottom);
126 notify_override_redir(flags, top, bottom);
132 notify_override_overriden(flags, top, bottom);
133 if (!(flags & SHOW_DIFF))
142 log_error("Failed to fork off diff: %m");
144 } else if (pid == 0) {
145 execlp("diff", "diff", "-us", "--", bottom, top, NULL);
146 log_error("Failed to execute diff: %m");
150 wait_for_terminate(pid, NULL);
159 static int enumerate_dir(Hashmap *top, Hashmap *bottom, const char *path) {
172 log_error("Failed to enumerate %s: %m", path);
177 struct dirent *de, buf;
181 k = readdir_r(d, &buf, &de);
190 if (!dirent_is_file(de))
193 p = join(path, "/", de->d_name, NULL);
199 path_kill_slashes(p);
201 k = hashmap_put(top, path_get_file_name(p), p);
208 } else if (k != -EEXIST) {
214 free(hashmap_remove(bottom, path_get_file_name(p)));
215 k = hashmap_put(bottom, path_get_file_name(p), p);
229 static int process_suffix(int flags, const char *prefixes, const char *suffix) {
232 Hashmap *top, *bottom;
240 top = hashmap_new(string_hash_func, string_compare_func);
246 bottom = hashmap_new(string_hash_func, string_compare_func);
252 NULSTR_FOREACH(p, prefixes) {
255 t = join(p, "/", suffix, NULL);
261 k = enumerate_dir(top, bottom, t);
265 log_debug("Looking at %s", t);
269 HASHMAP_FOREACH(f, top, i) {
272 o = hashmap_get(bottom, path_get_file_name(f));
275 if (path_equal(o, f)) {
276 notify_override_unchanged(flags, f, o);
280 k = found_override(flags, f, o);
289 hashmap_free_free(top);
291 hashmap_free_free(bottom);
293 return r < 0 ? r : n_found;
296 static int process_suffix_chop(int flags, const char *prefixes, const char *suffix) {
302 if (!path_is_absolute(suffix))
303 return process_suffix(flags, prefixes, suffix);
305 /* Strip prefix from the suffix */
306 NULSTR_FOREACH(p, prefixes) {
307 if (startswith(suffix, p)) {
308 suffix += strlen(p);;
309 suffix += strspn(suffix, "/");
310 return process_suffix(flags, prefixes, suffix);
314 log_error("Invalid suffix specification %s.", suffix);
318 static void help(void) {
320 printf("%s [OPTIONS...] [SUFFIX...]\n\n"
321 "Find overridden configuration files.\n\n"
322 " -h --help Show this help\n"
323 " --version Show package version\n"
324 " --no-pager Do not pipe output into a pager\n"
325 " --diff[=1|0] Show a diff when overriden files differ\n"
326 " -t --type=LIST... Only display a selected set of override types\n",
327 program_invocation_short_name);
330 static int parse_flags(int flags, const char *flag_str) {
334 FOREACH_WORD(w, l, flag_str, state) {
335 if (strncmp("masked", w, l) == 0) {
336 flags |= SHOW_MASKED;
337 } else if (strncmp ("equivalent", w, l) == 0) {
339 } else if (strncmp("redirected", w, l) == 0) {
341 } else if (strncmp("override", w, l) == 0) {
342 flags |= SHOW_OVERRIDEN;
343 } else if (strncmp("unchanged", w, l) == 0) {
344 flags |= SHOW_UNCHANGED;
345 } else if (strncmp("default", w, l) == 0) {
346 flags |= SHOW_DEFAULTS;
348 log_error("Unknown type filter: %s", w);
355 static int parse_argv(int argc, char *argv[], int *flags) {
358 ARG_NO_PAGER = 0x100,
363 static const struct option options[] = {
364 { "help", no_argument, NULL, 'h' },
365 { "version", no_argument, NULL, ARG_VERSION },
366 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
367 { "diff", optional_argument, NULL, ARG_DIFF },
368 { "type", required_argument, NULL, 't' },
377 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
386 puts(PACKAGE_STRING);
388 puts(SYSTEMD_FEATURES);
399 *flags = parse_flags(*flags, optarg);
408 if (parse_boolean(optarg))
411 *flags &= ~SHOW_DIFF;
416 log_error("Unknown option code %c", c);
424 int main(int argc, char *argv[]) {
426 const char prefixes[] =
433 #ifdef HAVE_SPLIT_USR
438 const char suffixes[] =
445 "systemd/system.preset\0"
446 "systemd/user.preset\0"
454 log_parse_environment();
457 r = parse_argv(argc, argv, &flags);
462 flags = SHOW_DEFAULTS;
463 if (flags == SHOW_DIFF)
464 flags |= SHOW_OVERRIDEN;
472 for (i = optind; i < argc; i++) {
473 k = process_suffix_chop(flags, prefixes, argv[i]);
483 NULSTR_FOREACH(n, suffixes) {
484 k = process_suffix(flags, prefixes, n);
493 printf("\n%i overriden configuration files found.\n", n_found);
498 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;