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;
36 static int arg_diff = -1;
40 SHOW_EQUIVALENT = 1 << 1,
41 SHOW_REDIRECTED = 1 << 2,
42 SHOW_OVERRIDDEN = 1 << 3,
43 SHOW_UNCHANGED = 1 << 4,
46 (SHOW_MASKED | SHOW_EQUIVALENT | SHOW_REDIRECTED | SHOW_OVERRIDDEN)
49 static int equivalent(const char *a, const char *b) {
53 x = canonicalize_file_name(a);
57 y = canonicalize_file_name(b);
70 static int notify_override_masked(const char *top, const char *bottom) {
71 if (!(arg_flags & SHOW_MASKED))
74 printf(ANSI_HIGHLIGHT_RED_ON "[MASKED]" ANSI_HIGHLIGHT_OFF " %s → %s\n", top, bottom);
78 static int notify_override_equivalent(const char *top, const char *bottom) {
79 if (!(arg_flags & SHOW_EQUIVALENT))
82 printf(ANSI_HIGHLIGHT_GREEN_ON "[EQUIVALENT]" ANSI_HIGHLIGHT_OFF " %s → %s\n", top, bottom);
86 static int notify_override_redirected(const char *top, const char *bottom) {
87 if (!(arg_flags & SHOW_REDIRECTED))
90 printf(ANSI_HIGHLIGHT_ON "[REDIRECTED]" ANSI_HIGHLIGHT_OFF " %s → %s\n", top, bottom);
94 static int notify_override_overridden(const char *top, const char *bottom) {
95 if (!(arg_flags & SHOW_OVERRIDDEN))
98 printf(ANSI_HIGHLIGHT_ON "[OVERRIDDEN]" ANSI_HIGHLIGHT_OFF " %s → %s\n", top, bottom);
102 static int notify_override_unchanged(const char *f) {
103 if (!(arg_flags & SHOW_UNCHANGED))
106 printf("[UNCHANGED] %s\n", f);
110 static int found_override(const char *top, const char *bottom) {
118 if (null_or_empty_path(top) > 0) {
119 notify_override_masked(top, bottom);
123 k = readlink_malloc(top, &dest);
125 if (equivalent(dest, bottom) > 0)
126 notify_override_equivalent(top, bottom);
128 notify_override_redirected(top, bottom);
134 notify_override_overridden(top, bottom);
144 log_error("Failed to fork off diff: %m");
146 } else if (pid == 0) {
147 execlp("diff", "diff", "-us", "--", bottom, top, NULL);
148 log_error("Failed to execute diff: %m");
152 wait_for_terminate(pid, NULL);
161 static int enumerate_dir(Hashmap *top, Hashmap *bottom, const char *path) {
174 log_error("Failed to enumerate %s: %m", path);
180 union dirent_storage buf;
184 k = readdir_r(d, &buf.de, &de);
193 if (!dirent_is_file(de))
196 p = strjoin(path, "/", de->d_name, NULL);
202 path_kill_slashes(p);
204 k = hashmap_put(top, path_get_file_name(p), p);
211 } else if (k != -EEXIST) {
217 free(hashmap_remove(bottom, path_get_file_name(p)));
218 k = hashmap_put(bottom, path_get_file_name(p), p);
232 static int process_suffix(const char *prefixes, const char *suffix) {
235 Hashmap *top, *bottom=NULL;
243 top = hashmap_new(string_hash_func, string_compare_func);
249 bottom = hashmap_new(string_hash_func, string_compare_func);
255 NULSTR_FOREACH(p, prefixes) {
258 t = strjoin(p, "/", suffix, NULL);
264 k = enumerate_dir(top, bottom, t);
268 log_debug("Looking at %s", t);
272 HASHMAP_FOREACH(f, top, i) {
275 o = hashmap_get(bottom, path_get_file_name(f));
278 if (path_equal(o, f)) {
279 notify_override_unchanged(f);
283 k = found_override(f, o);
292 hashmap_free_free(top);
294 hashmap_free_free(bottom);
296 return r < 0 ? r : n_found;
299 static int process_suffix_chop(const char *prefixes, const char *suffix) {
305 if (!path_is_absolute(suffix))
306 return process_suffix(prefixes, suffix);
308 /* Strip prefix from the suffix */
309 NULSTR_FOREACH(p, prefixes) {
310 if (startswith(suffix, p)) {
311 suffix += strlen(p);;
312 suffix += strspn(suffix, "/");
313 return process_suffix(prefixes, suffix);
317 log_error("Invalid suffix specification %s.", suffix);
321 static void help(void) {
323 printf("%s [OPTIONS...] [SUFFIX...]\n\n"
324 "Find overridden configuration files.\n\n"
325 " -h --help Show this help\n"
326 " --version Show package version\n"
327 " --no-pager Do not pipe output into a pager\n"
328 " --diff[=1|0] Show a diff when overridden files differ\n"
329 " -t --type=LIST... Only display a selected set of override types\n",
330 program_invocation_short_name);
333 static int parse_flags(const char *flag_str, int flags) {
337 FOREACH_WORD(w, l, flag_str, state) {
338 if (strncmp("masked", w, l) == 0)
339 flags |= SHOW_MASKED;
340 else if (strncmp ("equivalent", w, l) == 0)
341 flags |= SHOW_EQUIVALENT;
342 else if (strncmp("redirected", w, l) == 0)
343 flags |= SHOW_REDIRECTED;
344 else if (strncmp("overridden", w, l) == 0)
345 flags |= SHOW_OVERRIDDEN;
346 else if (strncmp("unchanged", w, l) == 0)
347 flags |= SHOW_UNCHANGED;
348 else if (strncmp("default", w, l) == 0)
349 flags |= SHOW_DEFAULTS;
356 static int parse_argv(int argc, char *argv[]) {
359 ARG_NO_PAGER = 0x100,
364 static const struct option options[] = {
365 { "help", no_argument, NULL, 'h' },
366 { "version", no_argument, NULL, ARG_VERSION },
367 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
368 { "diff", optional_argument, NULL, ARG_DIFF },
369 { "type", required_argument, NULL, 't' },
378 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
387 puts(PACKAGE_STRING);
389 puts(SYSTEMD_FEATURES);
401 f = parse_flags(optarg, arg_flags);
403 log_error("Failed to parse flags field.");
416 b = parse_boolean(optarg);
418 log_error("Failed to parse diff boolean.");
428 log_error("Unknown option code %c", c);
436 int main(int argc, char *argv[]) {
438 const char prefixes[] =
445 #ifdef HAVE_SPLIT_USR
450 const char suffixes[] =
457 "systemd/system-preset\0"
458 "systemd/user-preset\0"
465 log_parse_environment();
468 r = parse_argv(argc, argv);
473 arg_flags = SHOW_DEFAULTS;
476 arg_diff = !!(arg_flags & SHOW_OVERRIDDEN);
478 arg_flags |= SHOW_OVERRIDDEN;
486 for (i = optind; i < argc; i++) {
487 k = process_suffix_chop(prefixes, argv[i]);
497 NULSTR_FOREACH(n, suffixes) {
498 k = process_suffix(prefixes, n);
507 printf("\n%i overridden configuration files found.\n", n_found);
512 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;