]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/delta/delta.c
raw-clone: beef up raw_clone() wrapper a bit
[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;
7e8d5761 164 pid_t pid;
4c253ed1 165 int r;
7e8d5761
LP
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 172
4c253ed1
LP
173 r = readlink_malloc(top, &dest);
174 if (r >= 0) {
7e8d5761 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
4c253ed1 181 r = notify_override_overridden(top, bottom);
866062b1 182 if (!arg_diff)
4c253ed1 183 return r;
7e8d5761
LP
184
185 putchar('\n');
186
187 fflush(stdout);
188
4c253ed1
LP
189 r = safe_fork("(diff)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS, &pid);
190 if (r < 0)
191 return log_error_errno(pid, "Failed to fork off diff: %m");
192 if (r == 0) {
7e8d5761 193 execlp("diff", "diff", "-us", "--", bottom, top, NULL);
56f64d95 194 log_error_errno(errno, "Failed to execute diff: %m");
ce30c8dc 195 _exit(EXIT_FAILURE);
7e8d5761
LP
196 }
197
820d3acf 198 wait_for_terminate_and_warn("diff", pid, false);
7e8d5761
LP
199 putchar('\n');
200
4c253ed1 201 return r;
7e8d5761
LP
202}
203
9f5ebb8a
ZJS
204static int enumerate_dir_d(
205 OrderedHashmap *top,
206 OrderedHashmap *bottom,
207 OrderedHashmap *drops,
208 const char *toppath, const char *drop) {
209
f939e9a4 210 _cleanup_free_ char *unit = NULL;
0000ce05
LN
211 _cleanup_free_ char *path = NULL;
212 _cleanup_strv_free_ char **list = NULL;
213 char **file;
214 char *c;
215 int r;
216
f939e9a4
ZJS
217 assert(!endswith(drop, "/"));
218
605405c6 219 path = strjoin(toppath, "/", drop);
0000ce05
LN
220 if (!path)
221 return -ENOMEM;
222
f939e9a4 223 log_debug("Looking at %s", path);
0000ce05 224
f939e9a4
ZJS
225 unit = strdup(drop);
226 if (!unit)
0000ce05
LN
227 return -ENOMEM;
228
f939e9a4 229 c = strrchr(unit, '.');
0000ce05
LN
230 if (!c)
231 return -EINVAL;
232 *c = 0;
233
234 r = get_files_in_directory(path, &list);
23bbb0de
MS
235 if (r < 0)
236 return log_error_errno(r, "Failed to enumerate %s: %m", path);
0000ce05 237
9f5ebb8a
ZJS
238 strv_sort(list);
239
0000ce05 240 STRV_FOREACH(file, list) {
9f5ebb8a 241 OrderedHashmap *h;
0000ce05
LN
242 int k;
243 char *p;
244 char *d;
245
246 if (!endswith(*file, ".conf"))
247 continue;
248
605405c6 249 p = strjoin(path, "/", *file);
0000ce05
LN
250 if (!p)
251 return -ENOMEM;
f939e9a4 252 d = p + strlen(toppath) + 1;
0000ce05 253
323b7dc9 254 log_debug("Adding at top: %s %s %s", d, special_glyph(ARROW), p);
9f5ebb8a 255 k = ordered_hashmap_put(top, d, p);
0000ce05
LN
256 if (k >= 0) {
257 p = strdup(p);
258 if (!p)
259 return -ENOMEM;
f939e9a4 260 d = p + strlen(toppath) + 1;
0000ce05
LN
261 } else if (k != -EEXIST) {
262 free(p);
263 return k;
264 }
265
323b7dc9 266 log_debug("Adding at bottom: %s %s %s", d, special_glyph(ARROW), p);
9f5ebb8a
ZJS
267 free(ordered_hashmap_remove(bottom, d));
268 k = ordered_hashmap_put(bottom, d, p);
0000ce05
LN
269 if (k < 0) {
270 free(p);
271 return k;
272 }
273
9f5ebb8a 274 h = ordered_hashmap_get(drops, unit);
0000ce05 275 if (!h) {
9f5ebb8a 276 h = ordered_hashmap_new(&string_hash_ops);
0000ce05
LN
277 if (!h)
278 return -ENOMEM;
9f5ebb8a 279 ordered_hashmap_put(drops, unit, h);
f939e9a4
ZJS
280 unit = strdup(unit);
281 if (!unit)
0000ce05
LN
282 return -ENOMEM;
283 }
284
285 p = strdup(p);
286 if (!p)
287 return -ENOMEM;
288
00a5cc3a 289 log_debug("Adding to drops: %s %s %s %s %s",
323b7dc9 290 unit, special_glyph(ARROW), basename(p), special_glyph(ARROW), p);
9f5ebb8a 291 k = ordered_hashmap_put(h, basename(p), p);
0000ce05
LN
292 if (k < 0) {
293 free(p);
294 if (k != -EEXIST)
295 return k;
296 }
297 }
298 return 0;
299}
300
9f5ebb8a
ZJS
301static int enumerate_dir(
302 OrderedHashmap *top,
303 OrderedHashmap *bottom,
304 OrderedHashmap *drops,
305 const char *path, bool dropins) {
306
307 _cleanup_closedir_ DIR *d = NULL;
8fb3f009 308 struct dirent *de;
9f5ebb8a
ZJS
309 _cleanup_strv_free_ char **files = NULL, **dirs = NULL;
310 size_t n_files = 0, allocated_files = 0, n_dirs = 0, allocated_dirs = 0;
311 char **t;
312 int r;
7e8d5761
LP
313
314 assert(top);
315 assert(bottom);
0000ce05 316 assert(drops);
7e8d5761
LP
317 assert(path);
318
f939e9a4
ZJS
319 log_debug("Looking at %s", path);
320
7e8d5761
LP
321 d = opendir(path);
322 if (!d) {
323 if (errno == ENOENT)
324 return 0;
325
e1427b13 326 return log_error_errno(errno, "Failed to open %s: %m", path);
7e8d5761
LP
327 }
328
8fb3f009 329 FOREACH_DIRENT_ALL(de, d, return -errno) {
277f2f75
LN
330 dirent_ensure_type(d, de);
331
9f5ebb8a
ZJS
332 if (dropins && de->d_type == DT_DIR && endswith(de->d_name, ".d")) {
333 if (!GREEDY_REALLOC0(dirs, allocated_dirs, n_dirs + 2))
334 return -ENOMEM;
335
336 dirs[n_dirs] = strdup(de->d_name);
337 if (!dirs[n_dirs])
338 return -ENOMEM;
339 n_dirs ++;
340 }
0000ce05 341
7e8d5761
LP
342 if (!dirent_is_file(de))
343 continue;
344
9f5ebb8a
ZJS
345 if (!GREEDY_REALLOC0(files, allocated_files, n_files + 2))
346 return -ENOMEM;
347
348 files[n_files] = strdup(de->d_name);
349 if (!files[n_files])
350 return -ENOMEM;
351 n_files ++;
352 }
353
354 strv_sort(dirs);
355 strv_sort(files);
356
357 STRV_FOREACH(t, dirs) {
358 r = enumerate_dir_d(top, bottom, drops, path, *t);
359 if (r < 0)
360 return r;
361 }
362
363 STRV_FOREACH(t, files) {
364 _cleanup_free_ char *p = NULL;
365
366 p = strjoin(path, "/", *t);
e26970a8
TA
367 if (!p)
368 return -ENOMEM;
7e8d5761 369
323b7dc9 370 log_debug("Adding at top: %s %s %s", basename(p), special_glyph(ARROW), p);
9f5ebb8a
ZJS
371 r = ordered_hashmap_put(top, basename(p), p);
372 if (r >= 0) {
7e8d5761 373 p = strdup(p);
e26970a8
TA
374 if (!p)
375 return -ENOMEM;
9f5ebb8a
ZJS
376 } else if (r != -EEXIST)
377 return r;
7e8d5761 378
323b7dc9 379 log_debug("Adding at bottom: %s %s %s", basename(p), special_glyph(ARROW), p);
9f5ebb8a
ZJS
380 free(ordered_hashmap_remove(bottom, basename(p)));
381 r = ordered_hashmap_put(bottom, basename(p), p);
382 if (r < 0)
383 return r;
384 p = NULL;
7e8d5761 385 }
9f5ebb8a 386
8fb3f009 387 return 0;
7e8d5761
LP
388}
389
b05422a8 390static int should_skip_prefix(const char* p) {
349cc4a5 391#if HAVE_SPLIT_USR
b05422a8
FS
392 int r;
393 _cleanup_free_ char *target = NULL;
394
c4f4fce7 395 r = chase_symlinks(p, NULL, 0, &target);
b05422a8
FS
396 if (r < 0)
397 return r;
398
399 return !streq(p, target) && nulstr_contains(prefixes, target);
400#else
401 return 0;
402#endif
403}
404
6096dfd6 405static int process_suffix(const char *suffix, const char *onlyprefix) {
7e8d5761
LP
406 const char *p;
407 char *f;
9f5ebb8a
ZJS
408 OrderedHashmap *top, *bottom, *drops;
409 OrderedHashmap *h;
0000ce05 410 char *key;
7e8d5761 411 int r = 0, k;
0000ce05 412 Iterator i, j;
7e8d5761 413 int n_found = 0;
f939e9a4 414 bool dropins;
7e8d5761 415
7e8d5761 416 assert(suffix);
f939e9a4
ZJS
417 assert(!startswith(suffix, "/"));
418 assert(!strstr(suffix, "//"));
7e8d5761 419
f939e9a4 420 dropins = nulstr_contains(have_dropins, suffix);
7e8d5761 421
9f5ebb8a
ZJS
422 top = ordered_hashmap_new(&string_hash_ops);
423 bottom = ordered_hashmap_new(&string_hash_ops);
424 drops = ordered_hashmap_new(&string_hash_ops);
f939e9a4 425 if (!top || !bottom || !drops) {
0000ce05
LN
426 r = -ENOMEM;
427 goto finish;
428 }
429
7e8d5761 430 NULSTR_FOREACH(p, prefixes) {
e26970a8 431 _cleanup_free_ char *t = NULL;
b05422a8
FS
432 int skip;
433
434 skip = should_skip_prefix(p);
435 if (skip < 0) {
436 r = skip;
437 goto finish;
438 }
439 if (skip)
440 continue;
7e8d5761 441
605405c6 442 t = strjoin(p, "/", suffix);
7e8d5761
LP
443 if (!t) {
444 r = -ENOMEM;
445 goto finish;
446 }
447
0000ce05 448 k = enumerate_dir(top, bottom, drops, t, dropins);
f939e9a4 449 if (r == 0)
7e8d5761 450 r = k;
7e8d5761
LP
451 }
452
9f5ebb8a 453 ORDERED_HASHMAP_FOREACH_KEY(f, key, top, i) {
7e8d5761
LP
454 char *o;
455
9f5ebb8a 456 o = ordered_hashmap_get(bottom, key);
7e8d5761
LP
457 assert(o);
458
6096dfd6
ZJS
459 if (!onlyprefix || startswith(o, onlyprefix)) {
460 if (path_equal(o, f)) {
461 notify_override_unchanged(f);
462 } else {
463 k = found_override(f, o);
464 if (k < 0)
465 r = k;
466 else
467 n_found += k;
468 }
807f4645 469 }
7e8d5761 470
9f5ebb8a 471 h = ordered_hashmap_get(drops, key);
0000ce05 472 if (h)
9f5ebb8a 473 ORDERED_HASHMAP_FOREACH(o, h, j)
6096dfd6
ZJS
474 if (!onlyprefix || startswith(o, onlyprefix))
475 n_found += notify_override_extended(f, o);
7e8d5761
LP
476 }
477
478finish:
9f5ebb8a
ZJS
479 ordered_hashmap_free_free(top);
480 ordered_hashmap_free_free(bottom);
82376245 481
9f5ebb8a
ZJS
482 ORDERED_HASHMAP_FOREACH_KEY(h, key, drops, i) {
483 ordered_hashmap_free_free(ordered_hashmap_remove(drops, key));
484 ordered_hashmap_remove(drops, key);
82376245 485 free(key);
0000ce05 486 }
9f5ebb8a 487 ordered_hashmap_free(drops);
82376245 488
7e8d5761
LP
489 return r < 0 ? r : n_found;
490}
491
6096dfd6
ZJS
492static int process_suffixes(const char *onlyprefix) {
493 const char *n;
494 int n_found = 0, r;
495
496 NULSTR_FOREACH(n, suffixes) {
497 r = process_suffix(n, onlyprefix);
498 if (r < 0)
499 return r;
82376245
LP
500
501 n_found += r;
6096dfd6 502 }
82376245 503
6096dfd6
ZJS
504 return n_found;
505}
506
507static int process_suffix_chop(const char *arg) {
7e8d5761
LP
508 const char *p;
509
6096dfd6 510 assert(arg);
7e8d5761 511
6096dfd6
ZJS
512 if (!path_is_absolute(arg))
513 return process_suffix(arg, NULL);
7e8d5761
LP
514
515 /* Strip prefix from the suffix */
516 NULSTR_FOREACH(p, prefixes) {
82376245 517 const char *suffix;
b05422a8
FS
518 int skip;
519
520 skip = should_skip_prefix(p);
521 if (skip < 0)
522 return skip;
523 if (skip)
524 continue;
82376245
LP
525
526 suffix = startswith(arg, p);
6096dfd6 527 if (suffix) {
7e8d5761 528 suffix += strspn(suffix, "/");
6096dfd6
ZJS
529 if (*suffix)
530 return process_suffix(suffix, NULL);
531 else
532 return process_suffixes(arg);
7e8d5761
LP
533 }
534 }
535
6096dfd6 536 log_error("Invalid suffix specification %s.", arg);
7e8d5761
LP
537 return -EINVAL;
538}
539
601185b4 540static void help(void) {
7e8d5761
LP
541 printf("%s [OPTIONS...] [SUFFIX...]\n\n"
542 "Find overridden configuration files.\n\n"
543 " -h --help Show this help\n"
544 " --version Show package version\n"
807f4645 545 " --no-pager Do not pipe output into a pager\n"
386da858 546 " --diff[=1|0] Show a diff when overridden files differ\n"
601185b4
ZJS
547 " -t --type=LIST... Only display a selected set of override types\n"
548 , program_invocation_short_name);
7e8d5761
LP
549}
550
866062b1 551static int parse_flags(const char *flag_str, int flags) {
a2a5291b 552 const char *word, *state;
807f4645
GN
553 size_t l;
554
d0a2e1c3 555 FOREACH_WORD_SEPARATOR(word, l, flag_str, ",", state) {
a2a5291b 556 if (strneq("masked", word, l))
807f4645 557 flags |= SHOW_MASKED;
a2a5291b 558 else if (strneq ("equivalent", word, l))
c8021373 559 flags |= SHOW_EQUIVALENT;
a2a5291b 560 else if (strneq("redirected", word, l))
c8021373 561 flags |= SHOW_REDIRECTED;
a2a5291b 562 else if (strneq("overridden", word, l))
386da858 563 flags |= SHOW_OVERRIDDEN;
a2a5291b 564 else if (strneq("unchanged", word, l))
807f4645 565 flags |= SHOW_UNCHANGED;
a2a5291b 566 else if (strneq("extended", word, l))
0000ce05 567 flags |= SHOW_EXTENDED;
a2a5291b 568 else if (strneq("default", word, l))
807f4645 569 flags |= SHOW_DEFAULTS;
866062b1
LP
570 else
571 return -EINVAL;
807f4645
GN
572 }
573 return flags;
574}
575
866062b1 576static int parse_argv(int argc, char *argv[]) {
7e8d5761
LP
577
578 enum {
579 ARG_NO_PAGER = 0x100,
807f4645 580 ARG_DIFF,
7e8d5761
LP
581 ARG_VERSION
582 };
583
584 static const struct option options[] = {
585 { "help", no_argument, NULL, 'h' },
586 { "version", no_argument, NULL, ARG_VERSION },
587 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
807f4645
GN
588 { "diff", optional_argument, NULL, ARG_DIFF },
589 { "type", required_argument, NULL, 't' },
eb9da376 590 {}
7e8d5761
LP
591 };
592
593 int c;
594
595 assert(argc >= 1);
596 assert(argv);
597
601185b4 598 while ((c = getopt_long(argc, argv, "ht:", options, NULL)) >= 0)
7e8d5761
LP
599
600 switch (c) {
601
602 case 'h':
603 help();
604 return 0;
605
606 case ARG_VERSION:
3f6fd1ba 607 return version();
7e8d5761
LP
608
609 case ARG_NO_PAGER:
610 arg_no_pager = true;
611 break;
612
866062b1
LP
613 case 't': {
614 int f;
615 f = parse_flags(optarg, arg_flags);
616 if (f < 0) {
617 log_error("Failed to parse flags field.");
807f4645 618 return -EINVAL;
866062b1
LP
619 }
620 arg_flags = f;
807f4645 621 break;
866062b1 622 }
807f4645
GN
623
624 case ARG_DIFF:
866062b1
LP
625 if (!optarg)
626 arg_diff = 1;
627 else {
628 int b;
629
630 b = parse_boolean(optarg);
631 if (b < 0) {
632 log_error("Failed to parse diff boolean.");
633 return -EINVAL;
82376245
LP
634 }
635
636 arg_diff = b;
807f4645
GN
637 }
638 break;
639
eb9da376 640 case '?':
7e8d5761 641 return -EINVAL;
eb9da376
LP
642
643 default:
644 assert_not_reached("Unhandled option");
7e8d5761 645 }
7e8d5761
LP
646
647 return 1;
648}
649
650int main(int argc, char *argv[]) {
82376245 651 int r, k, n_found = 0;
7e8d5761
LP
652
653 log_parse_environment();
654 log_open();
655
866062b1 656 r = parse_argv(argc, argv);
7e8d5761
LP
657 if (r <= 0)
658 goto finish;
659
866062b1
LP
660 if (arg_flags == 0)
661 arg_flags = SHOW_DEFAULTS;
662
663 if (arg_diff < 0)
386da858 664 arg_diff = !!(arg_flags & SHOW_OVERRIDDEN);
866062b1 665 else if (arg_diff)
386da858 666 arg_flags |= SHOW_OVERRIDDEN;
807f4645 667
ea4b98e6 668 pager_open(arg_no_pager, false);
7e8d5761
LP
669
670 if (optind < argc) {
671 int i;
672
673 for (i = optind; i < argc; i++) {
f939e9a4 674 path_kill_slashes(argv[i]);
82376245 675
f939e9a4 676 k = process_suffix_chop(argv[i]);
7e8d5761
LP
677 if (k < 0)
678 r = k;
679 else
680 n_found += k;
681 }
682
683 } else {
6096dfd6
ZJS
684 k = process_suffixes(NULL);
685 if (k < 0)
686 r = k;
687 else
688 n_found += k;
7e8d5761
LP
689 }
690
691 if (r >= 0)
82376245 692 printf("%s%i overridden configuration files found.\n", n_found ? "\n" : "", n_found);
7e8d5761
LP
693
694finish:
695 pager_close();
696
697 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
698}