chiark / gitweb /
Prep v238: Uncomment now needed headers and unmask now needed functions in src/basic...
[elogind.git] / src / basic / verbs.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3   This file is part of systemd.
4
5   Copyright 2014 Lennart Poettering
6
7   systemd is free software; you can redistribute it and/or modify it
8   under the terms of the GNU Lesser General Public License as published by
9   the Free Software Foundation; either version 2.1 of the License, or
10   (at your option) any later version.
11
12   systemd is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   Lesser General Public License for more details.
16
17   You should have received a copy of the GNU Lesser General Public License
18   along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <errno.h>
22 #include <getopt.h>
23 #include <stdbool.h>
24 #include <stddef.h>
25 //#include <string.h>
26
27 #include "env-util.h"
28 #include "log.h"
29 #include "macro.h"
30 #include "process-util.h"
31 #include "string-util.h"
32 #include "verbs.h"
33 #include "virt.h"
34
35 /* Wraps running_in_chroot() which is used in various places, but also adds an environment variable check so external
36  * processes can reliably force this on.
37  */
38 bool running_in_chroot_or_offline(void) {
39         int r;
40
41         /* Added to support use cases like rpm-ostree, where from %post scripts we only want to execute "preset", but
42          * not "start"/"restart" for example.
43          *
44          * See doc/ENVIRONMENT.md for docs.
45          */
46         r = getenv_bool("SYSTEMD_OFFLINE");
47         if (r < 0 && r != -ENXIO)
48                 log_debug_errno(r, "Failed to parse $SYSTEMD_OFFLINE: %m");
49         else if (r >= 0)
50                 return r > 0;
51
52         /* We've had this condition check for a long time which basically checks for legacy chroot case like Fedora's
53          * "mock", which is used for package builds.  We don't want to try to start systemd services there, since
54          * without --new-chroot we don't even have systemd running, and even if we did, adding a concept of background
55          * daemons to builds would be an enormous change, requiring considering things like how the journal output is
56          * handled, etc.  And there's really not a use case today for a build talking to a service.
57          *
58          * Note this call itself also looks for a different variable SYSTEMD_IGNORE_CHROOT=1.
59          */
60         r = running_in_chroot();
61         if (r < 0)
62                 log_debug_errno(r, "running_in_chroot(): %m");
63
64         return r > 0;
65 }
66
67 int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) {
68         const Verb *verb;
69         const char *name;
70         unsigned i;
71         int left, r;
72
73         assert(verbs);
74         assert(verbs[0].dispatch);
75         assert(argc >= 0);
76         assert(argv);
77         assert(argc >= optind);
78
79         left = argc - optind;
80         name = argv[optind];
81
82         for (i = 0;; i++) {
83                 bool found;
84
85                 /* At the end of the list? */
86                 if (!verbs[i].dispatch) {
87                         if (name)
88                                 log_error("Unknown operation %s.", name);
89                         else
90                                 log_error("Requires operation parameter.");
91                         return -EINVAL;
92                 }
93
94                 if (name)
95                         found = streq(name, verbs[i].verb);
96                 else
97                         found = !!(verbs[i].flags & VERB_DEFAULT);
98
99                 if (found) {
100                         verb = &verbs[i];
101                         break;
102                 }
103         }
104
105         assert(verb);
106
107         if (!name)
108                 left = 1;
109
110         if (verb->min_args != VERB_ANY &&
111             (unsigned) left < verb->min_args) {
112                 log_error("Too few arguments.");
113                 return -EINVAL;
114         }
115
116         if (verb->max_args != VERB_ANY &&
117             (unsigned) left > verb->max_args) {
118                 log_error("Too many arguments.");
119                 return -EINVAL;
120         }
121
122         if ((verb->flags & VERB_ONLINE_ONLY) && running_in_chroot_or_offline()) {
123                 if (name)
124                         log_info("Running in chroot, ignoring request: %s", name);
125                 else
126                         log_info("Running in chroot, ignoring request.");
127                 return 0;
128         }
129
130         if (verb->flags & VERB_MUST_BE_ROOT) {
131                 r = must_be_root();
132                 if (r < 0)
133                         return r;
134         }
135
136         if (name)
137                 return verb->dispatch(left, argv + optind, userdata);
138         else {
139                 char* fake[2] = {
140                         (char*) verb->verb,
141                         NULL
142                 };
143
144                 return verb->dispatch(1, fake, userdata);
145         }
146 }