]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
dca59f62 | 2 | |
11c3a366 TA |
3 | #include <errno.h> |
4 | #include <getopt.h> | |
5 | #include <stdbool.h> | |
6 | #include <stddef.h> | |
7 | ||
f38951a6 | 8 | #include "env-util.h" |
11c3a366 TA |
9 | #include "log.h" |
10 | #include "macro.h" | |
dccca82b | 11 | #include "process-util.h" |
07630cea | 12 | #include "string-util.h" |
dca59f62 | 13 | #include "verbs.h" |
a16f96cd | 14 | #include "virt.h" |
dca59f62 | 15 | |
c944ca8e LP |
16 | /* Wraps running_in_chroot() which is used in various places, but also adds an environment variable check so external |
17 | * processes can reliably force this on. | |
f38951a6 CW |
18 | */ |
19 | bool running_in_chroot_or_offline(void) { | |
20 | int r; | |
21 | ||
c944ca8e LP |
22 | /* Added to support use cases like rpm-ostree, where from %post scripts we only want to execute "preset", but |
23 | * not "start"/"restart" for example. | |
f38951a6 | 24 | * |
eea98402 | 25 | * See docs/ENVIRONMENT.md for docs. |
f38951a6 CW |
26 | */ |
27 | r = getenv_bool("SYSTEMD_OFFLINE"); | |
c944ca8e LP |
28 | if (r < 0 && r != -ENXIO) |
29 | log_debug_errno(r, "Failed to parse $SYSTEMD_OFFLINE: %m"); | |
30 | else if (r >= 0) | |
31 | return r > 0; | |
f38951a6 | 32 | |
c944ca8e LP |
33 | /* We've had this condition check for a long time which basically checks for legacy chroot case like Fedora's |
34 | * "mock", which is used for package builds. We don't want to try to start systemd services there, since | |
35 | * without --new-chroot we don't even have systemd running, and even if we did, adding a concept of background | |
36 | * daemons to builds would be an enormous change, requiring considering things like how the journal output is | |
37 | * handled, etc. And there's really not a use case today for a build talking to a service. | |
f38951a6 CW |
38 | * |
39 | * Note this call itself also looks for a different variable SYSTEMD_IGNORE_CHROOT=1. | |
40 | */ | |
41 | r = running_in_chroot(); | |
42 | if (r < 0) | |
43 | log_debug_errno(r, "running_in_chroot(): %m"); | |
f38951a6 | 44 | |
c944ca8e | 45 | return r > 0; |
f38951a6 CW |
46 | } |
47 | ||
9321e23c ZJS |
48 | const Verb* verbs_find_verb(const char *name, const Verb verbs[]) { |
49 | for (size_t i = 0; verbs[i].dispatch; i++) | |
50 | if (streq_ptr(name, verbs[i].verb) || | |
51 | (!name && FLAGS_SET(verbs[i].flags, VERB_DEFAULT))) | |
52 | return &verbs[i]; | |
53 | ||
54 | /* At the end of the list? */ | |
55 | return NULL; | |
56 | } | |
57 | ||
dca59f62 LP |
58 | int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) { |
59 | const Verb *verb; | |
60 | const char *name; | |
62bf89d7 | 61 | int left; |
dca59f62 LP |
62 | |
63 | assert(verbs); | |
64 | assert(verbs[0].dispatch); | |
65 | assert(argc >= 0); | |
66 | assert(argv); | |
67 | assert(argc >= optind); | |
68 | ||
69 | left = argc - optind; | |
010d436e YW |
70 | argv += optind; |
71 | optind = 0; | |
72 | name = argv[0]; | |
dca59f62 | 73 | |
9321e23c ZJS |
74 | verb = verbs_find_verb(name, verbs); |
75 | if (!verb) { | |
43343ee7 | 76 | if (name) |
9321e23c ZJS |
77 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), |
78 | "Unknown command verb %s.", name); | |
43343ee7 | 79 | else |
9321e23c ZJS |
80 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), |
81 | "Command verb required."); | |
dca59f62 LP |
82 | } |
83 | ||
43343ee7 LP |
84 | if (!name) |
85 | left = 1; | |
86 | ||
dca59f62 | 87 | if (verb->min_args != VERB_ANY && |
baaa35ad ZJS |
88 | (unsigned) left < verb->min_args) |
89 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
90 | "Too few arguments."); | |
dca59f62 LP |
91 | |
92 | if (verb->max_args != VERB_ANY && | |
baaa35ad ZJS |
93 | (unsigned) left > verb->max_args) |
94 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
95 | "Too many arguments."); | |
dca59f62 | 96 | |
c56d1e2c | 97 | if ((verb->flags & VERB_ONLINE_ONLY) && running_in_chroot_or_offline()) { |
9321e23c | 98 | log_info("Running in chroot, ignoring command '%s'", name ?: verb->verb); |
a16f96cd LP |
99 | return 0; |
100 | } | |
101 | ||
43343ee7 | 102 | if (name) |
010d436e | 103 | return verb->dispatch(left, argv, userdata); |
43343ee7 LP |
104 | else { |
105 | char* fake[2] = { | |
106 | (char*) verb->verb, | |
107 | NULL | |
108 | }; | |
109 | ||
110 | return verb->dispatch(1, fake, userdata); | |
111 | } | |
dca59f62 | 112 | } |