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