]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/delta/delta.c
tree-wide: drop 'This file is part of systemd' blurb
[thirdparty/systemd.git] / src / delta / delta.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
7e8d5761 2/***
7e8d5761 3 Copyright 2012 Lennart Poettering
6096dfd6 4 Copyright 2013 Zbigniew Jędrzejewski-Szmek
7e8d5761
LP
5***/
6
7#include <errno.h>
7e8d5761 8#include <getopt.h>
3f6fd1ba 9#include <string.h>
ce30c8dc 10#include <sys/prctl.h>
3f6fd1ba 11#include <unistd.h>
7e8d5761 12
b5efdb8a 13#include "alloc-util.h"
a0956174 14#include "dirent-util.h"
3ffd4af2 15#include "fd-util.h"
f4f15635 16#include "fs-util.h"
7e8d5761 17#include "hashmap.h"
8752c575 18#include "locale-util.h"
7e8d5761
LP
19#include "log.h"
20#include "pager.h"
6bedfcbb 21#include "parse-util.h"
3f6fd1ba 22#include "path-util.h"
0b452006 23#include "process-util.h"
ce30c8dc 24#include "signal-util.h"
8fcde012 25#include "stat-util.h"
07630cea 26#include "string-util.h"
3f6fd1ba
LP
27#include "strv.h"
28#include "terminal-util.h"
29#include "util.h"
7e8d5761 30
f939e9a4
ZJS
31static const char prefixes[] =
32 "/etc\0"
33 "/run\0"
34 "/usr/local/lib\0"
35 "/usr/local/share\0"
36 "/usr/lib\0"
37 "/usr/share\0"
349cc4a5 38#if HAVE_SPLIT_USR
f939e9a4
ZJS
39 "/lib\0"
40#endif
41 ;
42
43static const char suffixes[] =
44 "sysctl.d\0"
45 "tmpfiles.d\0"
46 "modules-load.d\0"
47 "binfmt.d\0"
48 "systemd/system\0"
49 "systemd/user\0"
50 "systemd/system-preset\0"
51 "systemd/user-preset\0"
52 "udev/rules.d\0"
53 "modprobe.d\0";
54
55static const char have_dropins[] =
56 "systemd/system\0"
57 "systemd/user\0";
58
7e8d5761 59static bool arg_no_pager = false;
866062b1 60static int arg_diff = -1;
7e8d5761 61
866062b1 62static enum {
ef31828d 63 SHOW_MASKED = 1 << 0,
c8021373
LP
64 SHOW_EQUIVALENT = 1 << 1,
65 SHOW_REDIRECTED = 1 << 2,
386da858 66 SHOW_OVERRIDDEN = 1 << 3,
ef31828d
LP
67 SHOW_UNCHANGED = 1 << 4,
68 SHOW_EXTENDED = 1 << 5,
4c4e6431
LP
69
70 SHOW_DEFAULTS =
0000ce05 71 (SHOW_MASKED | SHOW_EQUIVALENT | SHOW_REDIRECTED | SHOW_OVERRIDDEN | SHOW_EXTENDED)
866062b1 72} arg_flags = 0;
4c4e6431 73
7e8d5761 74static int equivalent(const char *a, const char *b) {
e26970a8 75 _cleanup_free_ char *x = NULL, *y = NULL;
e1873695 76 int r;
7e8d5761 77
62570f6f 78 r = chase_symlinks(a, NULL, CHASE_TRAIL_SLASH, &x);
e1873695
LP
79 if (r < 0)
80 return r;
7e8d5761 81
62570f6f 82 r = chase_symlinks(b, NULL, CHASE_TRAIL_SLASH, &y);
e1873695
LP
83 if (r < 0)
84 return r;
7e8d5761 85
e26970a8 86 return path_equal(x, y);
7e8d5761
LP
87}
88
866062b1
LP
89static int notify_override_masked(const char *top, const char *bottom) {
90 if (!(arg_flags & SHOW_MASKED))
807f4645
GN
91 return 0;
92
00a5cc3a 93 printf("%s%s%s %s %s %s\n",
1fc464f6 94 ansi_highlight_red(), "[MASKED]", ansi_normal(),
323b7dc9 95 top, special_glyph(ARROW), bottom);
807f4645
GN
96 return 1;
97}
98
866062b1
LP
99static int notify_override_equivalent(const char *top, const char *bottom) {
100 if (!(arg_flags & SHOW_EQUIVALENT))
807f4645
GN
101 return 0;
102
00a5cc3a 103 printf("%s%s%s %s %s %s\n",
1fc464f6 104 ansi_highlight_green(), "[EQUIVALENT]", ansi_normal(),
323b7dc9 105 top, special_glyph(ARROW), bottom);
807f4645
GN
106 return 1;
107}
108
866062b1
LP
109static int notify_override_redirected(const char *top, const char *bottom) {
110 if (!(arg_flags & SHOW_REDIRECTED))
807f4645
GN
111 return 0;
112
9b6e0ce5 113 printf("%s%s%s %s %s %s\n",
1fc464f6 114 ansi_highlight(), "[REDIRECTED]", ansi_normal(),
323b7dc9 115 top, special_glyph(ARROW), bottom);
807f4645
GN
116 return 1;
117}
118
386da858
NM
119static int notify_override_overridden(const char *top, const char *bottom) {
120 if (!(arg_flags & SHOW_OVERRIDDEN))
807f4645
GN
121 return 0;
122
00a5cc3a 123 printf("%s%s%s %s %s %s\n",
1fc464f6 124 ansi_highlight(), "[OVERRIDDEN]", ansi_normal(),
323b7dc9 125 top, special_glyph(ARROW), bottom);
807f4645
GN
126 return 1;
127}
128
0000ce05
LN
129static int notify_override_extended(const char *top, const char *bottom) {
130 if (!(arg_flags & SHOW_EXTENDED))
131 return 0;
132
00a5cc3a 133 printf("%s%s%s %s %s %s\n",
1fc464f6 134 ansi_highlight(), "[EXTENDED]", ansi_normal(),
323b7dc9 135 top, special_glyph(ARROW), bottom);
0000ce05
LN
136 return 1;
137}
138
866062b1
LP
139static int notify_override_unchanged(const char *f) {
140 if (!(arg_flags & SHOW_UNCHANGED))
807f4645
GN
141 return 0;
142
8e812a23 143 printf("[UNCHANGED] %s\n", f);
807f4645
GN
144 return 1;
145}
146
866062b1 147static int found_override(const char *top, const char *bottom) {
e26970a8 148 _cleanup_free_ char *dest = NULL;
7e8d5761 149 pid_t pid;
4c253ed1 150 int r;
7e8d5761
LP
151
152 assert(top);
153 assert(bottom);
154
8fd57568
ZJS
155 if (null_or_empty_path(top) > 0)
156 return notify_override_masked(top, bottom);
7e8d5761 157
4c253ed1
LP
158 r = readlink_malloc(top, &dest);
159 if (r >= 0) {
7e8d5761 160 if (equivalent(dest, bottom) > 0)
8fd57568 161 return notify_override_equivalent(top, bottom);
7e8d5761 162 else
8fd57568 163 return notify_override_redirected(top, bottom);
7e8d5761
LP
164 }
165
4c253ed1 166 r = notify_override_overridden(top, bottom);
866062b1 167 if (!arg_diff)
4c253ed1 168 return r;
7e8d5761
LP
169
170 putchar('\n');
171
172 fflush(stdout);
173
b6e1fff1 174 r = safe_fork("(diff)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_LOG, &pid);
4c253ed1 175 if (r < 0)
b6e1fff1 176 return r;
4c253ed1 177 if (r == 0) {
7e8d5761 178 execlp("diff", "diff", "-us", "--", bottom, top, NULL);
0b1f3c76 179 log_open();
56f64d95 180 log_error_errno(errno, "Failed to execute diff: %m");
ce30c8dc 181 _exit(EXIT_FAILURE);
7e8d5761
LP
182 }
183
7d4904fe 184 (void) wait_for_terminate_and_check("diff", pid, WAIT_LOG_ABNORMAL);
7e8d5761
LP
185 putchar('\n');
186
4c253ed1 187 return r;
7e8d5761
LP
188}
189
9f5ebb8a
ZJS
190static int enumerate_dir_d(
191 OrderedHashmap *top,
192 OrderedHashmap *bottom,
193 OrderedHashmap *drops,
194 const char *toppath, const char *drop) {
195
f939e9a4 196 _cleanup_free_ char *unit = NULL;
0000ce05
LN
197 _cleanup_free_ char *path = NULL;
198 _cleanup_strv_free_ char **list = NULL;
199 char **file;
200 char *c;
201 int r;
202
f939e9a4
ZJS
203 assert(!endswith(drop, "/"));
204
605405c6 205 path = strjoin(toppath, "/", drop);
0000ce05
LN
206 if (!path)
207 return -ENOMEM;
208
f939e9a4 209 log_debug("Looking at %s", path);
0000ce05 210
f939e9a4
ZJS
211 unit = strdup(drop);
212 if (!unit)
0000ce05
LN
213 return -ENOMEM;
214
f939e9a4 215 c = strrchr(unit, '.');
0000ce05
LN
216 if (!c)
217 return -EINVAL;
218 *c = 0;
219
220 r = get_files_in_directory(path, &list);
23bbb0de
MS
221 if (r < 0)
222 return log_error_errno(r, "Failed to enumerate %s: %m", path);
0000ce05 223
9f5ebb8a
ZJS
224 strv_sort(list);
225
0000ce05 226 STRV_FOREACH(file, list) {
9f5ebb8a 227 OrderedHashmap *h;
0000ce05
LN
228 int k;
229 char *p;
230 char *d;
231
232 if (!endswith(*file, ".conf"))
233 continue;
234
605405c6 235 p = strjoin(path, "/", *file);
0000ce05
LN
236 if (!p)
237 return -ENOMEM;
f939e9a4 238 d = p + strlen(toppath) + 1;
0000ce05 239
323b7dc9 240 log_debug("Adding at top: %s %s %s", d, special_glyph(ARROW), p);
9f5ebb8a 241 k = ordered_hashmap_put(top, d, p);
0000ce05
LN
242 if (k >= 0) {
243 p = strdup(p);
244 if (!p)
245 return -ENOMEM;
f939e9a4 246 d = p + strlen(toppath) + 1;
0000ce05
LN
247 } else if (k != -EEXIST) {
248 free(p);
249 return k;
250 }
251
323b7dc9 252 log_debug("Adding at bottom: %s %s %s", d, special_glyph(ARROW), p);
9f5ebb8a
ZJS
253 free(ordered_hashmap_remove(bottom, d));
254 k = ordered_hashmap_put(bottom, d, p);
0000ce05
LN
255 if (k < 0) {
256 free(p);
257 return k;
258 }
259
9f5ebb8a 260 h = ordered_hashmap_get(drops, unit);
0000ce05 261 if (!h) {
9f5ebb8a 262 h = ordered_hashmap_new(&string_hash_ops);
0000ce05
LN
263 if (!h)
264 return -ENOMEM;
9f5ebb8a 265 ordered_hashmap_put(drops, unit, h);
f939e9a4
ZJS
266 unit = strdup(unit);
267 if (!unit)
0000ce05
LN
268 return -ENOMEM;
269 }
270
271 p = strdup(p);
272 if (!p)
273 return -ENOMEM;
274
00a5cc3a 275 log_debug("Adding to drops: %s %s %s %s %s",
323b7dc9 276 unit, special_glyph(ARROW), basename(p), special_glyph(ARROW), p);
9f5ebb8a 277 k = ordered_hashmap_put(h, basename(p), p);
0000ce05
LN
278 if (k < 0) {
279 free(p);
280 if (k != -EEXIST)
281 return k;
282 }
283 }
284 return 0;
285}
286
9f5ebb8a
ZJS
287static int enumerate_dir(
288 OrderedHashmap *top,
289 OrderedHashmap *bottom,
290 OrderedHashmap *drops,
291 const char *path, bool dropins) {
292
293 _cleanup_closedir_ DIR *d = NULL;
8fb3f009 294 struct dirent *de;
9f5ebb8a
ZJS
295 _cleanup_strv_free_ char **files = NULL, **dirs = NULL;
296 size_t n_files = 0, allocated_files = 0, n_dirs = 0, allocated_dirs = 0;
297 char **t;
298 int r;
7e8d5761
LP
299
300 assert(top);
301 assert(bottom);
0000ce05 302 assert(drops);
7e8d5761
LP
303 assert(path);
304
f939e9a4
ZJS
305 log_debug("Looking at %s", path);
306
7e8d5761
LP
307 d = opendir(path);
308 if (!d) {
309 if (errno == ENOENT)
310 return 0;
311
e1427b13 312 return log_error_errno(errno, "Failed to open %s: %m", path);
7e8d5761
LP
313 }
314
8fb3f009 315 FOREACH_DIRENT_ALL(de, d, return -errno) {
277f2f75
LN
316 dirent_ensure_type(d, de);
317
9f5ebb8a
ZJS
318 if (dropins && de->d_type == DT_DIR && endswith(de->d_name, ".d")) {
319 if (!GREEDY_REALLOC0(dirs, allocated_dirs, n_dirs + 2))
320 return -ENOMEM;
321
322 dirs[n_dirs] = strdup(de->d_name);
323 if (!dirs[n_dirs])
324 return -ENOMEM;
325 n_dirs ++;
326 }
0000ce05 327
7e8d5761
LP
328 if (!dirent_is_file(de))
329 continue;
330
9f5ebb8a
ZJS
331 if (!GREEDY_REALLOC0(files, allocated_files, n_files + 2))
332 return -ENOMEM;
333
334 files[n_files] = strdup(de->d_name);
335 if (!files[n_files])
336 return -ENOMEM;
337 n_files ++;
338 }
339
340 strv_sort(dirs);
341 strv_sort(files);
342
343 STRV_FOREACH(t, dirs) {
344 r = enumerate_dir_d(top, bottom, drops, path, *t);
345 if (r < 0)
346 return r;
347 }
348
349 STRV_FOREACH(t, files) {
350 _cleanup_free_ char *p = NULL;
351
352 p = strjoin(path, "/", *t);
e26970a8
TA
353 if (!p)
354 return -ENOMEM;
7e8d5761 355
323b7dc9 356 log_debug("Adding at top: %s %s %s", basename(p), special_glyph(ARROW), p);
9f5ebb8a
ZJS
357 r = ordered_hashmap_put(top, basename(p), p);
358 if (r >= 0) {
7e8d5761 359 p = strdup(p);
e26970a8
TA
360 if (!p)
361 return -ENOMEM;
9f5ebb8a
ZJS
362 } else if (r != -EEXIST)
363 return r;
7e8d5761 364
323b7dc9 365 log_debug("Adding at bottom: %s %s %s", basename(p), special_glyph(ARROW), p);
9f5ebb8a
ZJS
366 free(ordered_hashmap_remove(bottom, basename(p)));
367 r = ordered_hashmap_put(bottom, basename(p), p);
368 if (r < 0)
369 return r;
370 p = NULL;
7e8d5761 371 }
9f5ebb8a 372
8fb3f009 373 return 0;
7e8d5761
LP
374}
375
4cc893e7 376static bool should_skip_path(const char *prefix, const char *suffix) {
349cc4a5 377#if HAVE_SPLIT_USR
b05422a8 378 _cleanup_free_ char *target = NULL;
4cc893e7
FB
379 const char *p;
380 char *dirname;
b05422a8 381
4cc893e7 382 dirname = strjoina(prefix, "/", suffix);
b05422a8 383
4cc893e7
FB
384 if (chase_symlinks(dirname, NULL, 0, &target) < 0)
385 return false;
386
387 NULSTR_FOREACH(p, prefixes) {
388 if (path_startswith(dirname, p))
389 continue;
390
391 if (path_equal(target, strjoina(p, "/", suffix))) {
392 log_debug("%s redirects to %s, skipping.", dirname, target);
393 return true;
394 }
395 }
b05422a8 396#endif
4cc893e7 397 return false;
b05422a8
FS
398}
399
6096dfd6 400static int process_suffix(const char *suffix, const char *onlyprefix) {
7e8d5761
LP
401 const char *p;
402 char *f;
9f5ebb8a
ZJS
403 OrderedHashmap *top, *bottom, *drops;
404 OrderedHashmap *h;
0000ce05 405 char *key;
7e8d5761 406 int r = 0, k;
0000ce05 407 Iterator i, j;
7e8d5761 408 int n_found = 0;
f939e9a4 409 bool dropins;
7e8d5761 410
7e8d5761 411 assert(suffix);
f939e9a4
ZJS
412 assert(!startswith(suffix, "/"));
413 assert(!strstr(suffix, "//"));
7e8d5761 414
f939e9a4 415 dropins = nulstr_contains(have_dropins, suffix);
7e8d5761 416
9f5ebb8a
ZJS
417 top = ordered_hashmap_new(&string_hash_ops);
418 bottom = ordered_hashmap_new(&string_hash_ops);
419 drops = ordered_hashmap_new(&string_hash_ops);
f939e9a4 420 if (!top || !bottom || !drops) {
0000ce05
LN
421 r = -ENOMEM;
422 goto finish;
423 }
424
7e8d5761 425 NULSTR_FOREACH(p, prefixes) {
e26970a8 426 _cleanup_free_ char *t = NULL;
b05422a8 427
4cc893e7 428 if (should_skip_path(p, suffix))
b05422a8 429 continue;
7e8d5761 430
605405c6 431 t = strjoin(p, "/", suffix);
7e8d5761
LP
432 if (!t) {
433 r = -ENOMEM;
434 goto finish;
435 }
436
0000ce05 437 k = enumerate_dir(top, bottom, drops, t, dropins);
f939e9a4 438 if (r == 0)
7e8d5761 439 r = k;
7e8d5761
LP
440 }
441
9f5ebb8a 442 ORDERED_HASHMAP_FOREACH_KEY(f, key, top, i) {
7e8d5761
LP
443 char *o;
444
9f5ebb8a 445 o = ordered_hashmap_get(bottom, key);
7e8d5761
LP
446 assert(o);
447
6096dfd6
ZJS
448 if (!onlyprefix || startswith(o, onlyprefix)) {
449 if (path_equal(o, f)) {
450 notify_override_unchanged(f);
451 } else {
452 k = found_override(f, o);
453 if (k < 0)
454 r = k;
455 else
456 n_found += k;
457 }
807f4645 458 }
7e8d5761 459
9f5ebb8a 460 h = ordered_hashmap_get(drops, key);
0000ce05 461 if (h)
9f5ebb8a 462 ORDERED_HASHMAP_FOREACH(o, h, j)
6096dfd6
ZJS
463 if (!onlyprefix || startswith(o, onlyprefix))
464 n_found += notify_override_extended(f, o);
7e8d5761
LP
465 }
466
467finish:
9f5ebb8a
ZJS
468 ordered_hashmap_free_free(top);
469 ordered_hashmap_free_free(bottom);
82376245 470
9f5ebb8a
ZJS
471 ORDERED_HASHMAP_FOREACH_KEY(h, key, drops, i) {
472 ordered_hashmap_free_free(ordered_hashmap_remove(drops, key));
473 ordered_hashmap_remove(drops, key);
82376245 474 free(key);
0000ce05 475 }
9f5ebb8a 476 ordered_hashmap_free(drops);
82376245 477
7e8d5761
LP
478 return r < 0 ? r : n_found;
479}
480
6096dfd6
ZJS
481static int process_suffixes(const char *onlyprefix) {
482 const char *n;
483 int n_found = 0, r;
484
485 NULSTR_FOREACH(n, suffixes) {
486 r = process_suffix(n, onlyprefix);
487 if (r < 0)
488 return r;
82376245
LP
489
490 n_found += r;
6096dfd6 491 }
82376245 492
6096dfd6
ZJS
493 return n_found;
494}
495
496static int process_suffix_chop(const char *arg) {
7e8d5761
LP
497 const char *p;
498
6096dfd6 499 assert(arg);
7e8d5761 500
6096dfd6
ZJS
501 if (!path_is_absolute(arg))
502 return process_suffix(arg, NULL);
7e8d5761
LP
503
504 /* Strip prefix from the suffix */
505 NULSTR_FOREACH(p, prefixes) {
82376245
LP
506 const char *suffix;
507
508 suffix = startswith(arg, p);
6096dfd6 509 if (suffix) {
7e8d5761 510 suffix += strspn(suffix, "/");
6096dfd6 511 if (*suffix)
a9d041fa 512 return process_suffix(suffix, p);
6096dfd6
ZJS
513 else
514 return process_suffixes(arg);
7e8d5761
LP
515 }
516 }
517
6096dfd6 518 log_error("Invalid suffix specification %s.", arg);
7e8d5761
LP
519 return -EINVAL;
520}
521
601185b4 522static void help(void) {
7e8d5761
LP
523 printf("%s [OPTIONS...] [SUFFIX...]\n\n"
524 "Find overridden configuration files.\n\n"
525 " -h --help Show this help\n"
526 " --version Show package version\n"
807f4645 527 " --no-pager Do not pipe output into a pager\n"
386da858 528 " --diff[=1|0] Show a diff when overridden files differ\n"
601185b4
ZJS
529 " -t --type=LIST... Only display a selected set of override types\n"
530 , program_invocation_short_name);
7e8d5761
LP
531}
532
866062b1 533static int parse_flags(const char *flag_str, int flags) {
a2a5291b 534 const char *word, *state;
807f4645
GN
535 size_t l;
536
d0a2e1c3 537 FOREACH_WORD_SEPARATOR(word, l, flag_str, ",", state) {
a2a5291b 538 if (strneq("masked", word, l))
807f4645 539 flags |= SHOW_MASKED;
a2a5291b 540 else if (strneq ("equivalent", word, l))
c8021373 541 flags |= SHOW_EQUIVALENT;
a2a5291b 542 else if (strneq("redirected", word, l))
c8021373 543 flags |= SHOW_REDIRECTED;
a2a5291b 544 else if (strneq("overridden", word, l))
386da858 545 flags |= SHOW_OVERRIDDEN;
a2a5291b 546 else if (strneq("unchanged", word, l))
807f4645 547 flags |= SHOW_UNCHANGED;
a2a5291b 548 else if (strneq("extended", word, l))
0000ce05 549 flags |= SHOW_EXTENDED;
a2a5291b 550 else if (strneq("default", word, l))
807f4645 551 flags |= SHOW_DEFAULTS;
866062b1
LP
552 else
553 return -EINVAL;
807f4645
GN
554 }
555 return flags;
556}
557
866062b1 558static int parse_argv(int argc, char *argv[]) {
7e8d5761
LP
559
560 enum {
561 ARG_NO_PAGER = 0x100,
807f4645 562 ARG_DIFF,
7e8d5761
LP
563 ARG_VERSION
564 };
565
566 static const struct option options[] = {
567 { "help", no_argument, NULL, 'h' },
568 { "version", no_argument, NULL, ARG_VERSION },
569 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
807f4645
GN
570 { "diff", optional_argument, NULL, ARG_DIFF },
571 { "type", required_argument, NULL, 't' },
eb9da376 572 {}
7e8d5761
LP
573 };
574
575 int c;
576
577 assert(argc >= 1);
578 assert(argv);
579
601185b4 580 while ((c = getopt_long(argc, argv, "ht:", options, NULL)) >= 0)
7e8d5761
LP
581
582 switch (c) {
583
584 case 'h':
585 help();
586 return 0;
587
588 case ARG_VERSION:
3f6fd1ba 589 return version();
7e8d5761
LP
590
591 case ARG_NO_PAGER:
592 arg_no_pager = true;
593 break;
594
866062b1
LP
595 case 't': {
596 int f;
597 f = parse_flags(optarg, arg_flags);
598 if (f < 0) {
599 log_error("Failed to parse flags field.");
807f4645 600 return -EINVAL;
866062b1
LP
601 }
602 arg_flags = f;
807f4645 603 break;
866062b1 604 }
807f4645
GN
605
606 case ARG_DIFF:
866062b1
LP
607 if (!optarg)
608 arg_diff = 1;
609 else {
610 int b;
611
612 b = parse_boolean(optarg);
613 if (b < 0) {
614 log_error("Failed to parse diff boolean.");
615 return -EINVAL;
82376245
LP
616 }
617
618 arg_diff = b;
807f4645
GN
619 }
620 break;
621
eb9da376 622 case '?':
7e8d5761 623 return -EINVAL;
eb9da376
LP
624
625 default:
626 assert_not_reached("Unhandled option");
7e8d5761 627 }
7e8d5761
LP
628
629 return 1;
630}
631
632int main(int argc, char *argv[]) {
82376245 633 int r, k, n_found = 0;
7e8d5761
LP
634
635 log_parse_environment();
636 log_open();
637
866062b1 638 r = parse_argv(argc, argv);
7e8d5761
LP
639 if (r <= 0)
640 goto finish;
641
866062b1
LP
642 if (arg_flags == 0)
643 arg_flags = SHOW_DEFAULTS;
644
645 if (arg_diff < 0)
386da858 646 arg_diff = !!(arg_flags & SHOW_OVERRIDDEN);
866062b1 647 else if (arg_diff)
386da858 648 arg_flags |= SHOW_OVERRIDDEN;
807f4645 649
ee5324aa 650 (void) pager_open(arg_no_pager, false);
7e8d5761
LP
651
652 if (optind < argc) {
653 int i;
654
655 for (i = optind; i < argc; i++) {
858d36c1 656 path_simplify(argv[i], false);
82376245 657
f939e9a4 658 k = process_suffix_chop(argv[i]);
7e8d5761
LP
659 if (k < 0)
660 r = k;
661 else
662 n_found += k;
663 }
664
665 } else {
6096dfd6
ZJS
666 k = process_suffixes(NULL);
667 if (k < 0)
668 r = k;
669 else
670 n_found += k;
7e8d5761
LP
671 }
672
673 if (r >= 0)
82376245 674 printf("%s%i overridden configuration files found.\n", n_found ? "\n" : "", n_found);
7e8d5761
LP
675
676finish:
677 pager_close();
678
679 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
680}