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);
179 struct dirent *de, buf;
183 k = readdir_r(d, &buf, &de);
192 if (!dirent_is_file(de))
195 p = strjoin(path, "/", de->d_name, NULL);
201 path_kill_slashes(p);
203 k = hashmap_put(top, path_get_file_name(p), p);
210 } else if (k != -EEXIST) {
216 free(hashmap_remove(bottom, path_get_file_name(p)));
217 k = hashmap_put(bottom, path_get_file_name(p), p);
231 static int process_suffix(const char *prefixes, const char *suffix) {
234 Hashmap *top, *bottom=NULL;
242 top = hashmap_new(string_hash_func, string_compare_func);
248 bottom = hashmap_new(string_hash_func, string_compare_func);
254 NULSTR_FOREACH(p, prefixes) {
257 t = strjoin(p, "/", suffix, NULL);
263 k = enumerate_dir(top, bottom, t);
267 log_debug("Looking at %s", t);
271 HASHMAP_FOREACH(f, top, i) {
274 o = hashmap_get(bottom, path_get_file_name(f));
277 if (path_equal(o, f)) {
278 notify_override_unchanged(f);
282 k = found_override(f, o);
291 hashmap_free_free(top);
293 hashmap_free_free(bottom);
295 return r < 0 ? r : n_found;
298 static int process_suffix_chop(const char *prefixes, const char *suffix) {
304 if (!path_is_absolute(suffix))
305 return process_suffix(prefixes, suffix);
307 /* Strip prefix from the suffix */
308 NULSTR_FOREACH(p, prefixes) {
309 if (startswith(suffix, p)) {
310 suffix += strlen(p);;
311 suffix += strspn(suffix, "/");
312 return process_suffix(prefixes, suffix);
316 log_error("Invalid suffix specification %s.", suffix);
320 static void help(void) {
322 printf("%s [OPTIONS...] [SUFFIX...]\n\n"
323 "Find overridden configuration files.\n\n"
324 " -h --help Show this help\n"
325 " --version Show package version\n"
326 " --no-pager Do not pipe output into a pager\n"
327 " --diff[=1|0] Show a diff when overridden files differ\n"
328 " -t --type=LIST... Only display a selected set of override types\n",
329 program_invocation_short_name);
332 static int parse_flags(const char *flag_str, int flags) {
336 FOREACH_WORD(w, l, flag_str, state) {
337 if (strncmp("masked", w, l) == 0)
338 flags |= SHOW_MASKED;
339 else if (strncmp ("equivalent", w, l) == 0)
340 flags |= SHOW_EQUIVALENT;
341 else if (strncmp("redirected", w, l) == 0)
342 flags |= SHOW_REDIRECTED;
343 else if (strncmp("overridden", w, l) == 0)
344 flags |= SHOW_OVERRIDDEN;
345 else if (strncmp("unchanged", w, l) == 0)
346 flags |= SHOW_UNCHANGED;
347 else if (strncmp("default", w, l) == 0)
348 flags |= SHOW_DEFAULTS;
355 static int parse_argv(int argc, char *argv[]) {
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);
400 f = parse_flags(optarg, arg_flags);
402 log_error("Failed to parse flags field.");
415 b = parse_boolean(optarg);
417 log_error("Failed to parse diff boolean.");
427 log_error("Unknown option code %c", c);
435 int main(int argc, char *argv[]) {
437 const char prefixes[] =
444 #ifdef HAVE_SPLIT_USR
449 const char suffixes[] =
456 "systemd/system-preset\0"
457 "systemd/user-preset\0"
464 log_parse_environment();
467 r = parse_argv(argc, argv);
472 arg_flags = SHOW_DEFAULTS;
475 arg_diff = !!(arg_flags & SHOW_OVERRIDDEN);
477 arg_flags |= SHOW_OVERRIDDEN;
485 for (i = optind; i < argc; i++) {
486 k = process_suffix_chop(prefixes, argv[i]);
496 NULSTR_FOREACH(n, suffixes) {
497 k = process_suffix(prefixes, n);
506 printf("\n%i overridden configuration files found.\n", n_found);
511 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;