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