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