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