]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/analyze/analyze-verify.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / analyze / analyze-verify.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
8b835fcc
ZJS
2/***
3 This file is part of systemd.
4
5 Copyright 2014 Zbigniew Jędrzejewski-Szmek
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 <stdlib.h>
8b835fcc 22
b5efdb8a 23#include "alloc-util.h"
5f311f8c 24#include "analyze-verify.h"
4bd29fe5 25#include "bus-error.h"
8b835fcc
ZJS
26#include "bus-util.h"
27#include "log.h"
5f311f8c 28#include "manager.h"
78002a67 29#include "pager.h"
5f311f8c
LP
30#include "path-util.h"
31#include "strv.h"
25f17e47
EV
32#include "unit-name.h"
33
34static int prepare_filename(const char *filename, char **ret) {
35 int r;
36 const char *name;
37 _cleanup_free_ char *abspath = NULL;
38 _cleanup_free_ char *dir = NULL;
39 _cleanup_free_ char *with_instance = NULL;
40 char *c;
41
42 assert(filename);
43 assert(ret);
44
45 r = path_make_absolute_cwd(filename, &abspath);
46 if (r < 0)
47 return r;
48
49 name = basename(abspath);
50 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
51 return -EINVAL;
52
53 if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) {
54 r = unit_name_replace_instance(name, "i", &with_instance);
55 if (r < 0)
56 return r;
57 }
58
59 dir = dirname_malloc(abspath);
60 if (!dir)
61 return -ENOMEM;
62
63 if (with_instance)
64 c = path_join(NULL, dir, with_instance);
65 else
66 c = path_join(NULL, dir, name);
67 if (!c)
68 return -ENOMEM;
69
70 *ret = c;
71 return 0;
72}
8b835fcc
ZJS
73
74static int generate_path(char **var, char **filenames) {
d941ea22 75 const char *old;
8b835fcc
ZJS
76 char **filename;
77
78 _cleanup_strv_free_ char **ans = NULL;
79 int r;
80
81 STRV_FOREACH(filename, filenames) {
82 char *t;
83
84 t = dirname_malloc(*filename);
85 if (!t)
86 return -ENOMEM;
87
88 r = strv_consume(&ans, t);
89 if (r < 0)
90 return r;
91 }
92
93 assert_se(strv_uniq(ans));
94
d941ea22
ZJS
95 /* First, prepend our directories. Second, if some path was specified, use that, and
96 * otherwise use the defaults. Any duplicates will be filtered out in path-lookup.c.
97 * Treat explicit empty path to mean that nothing should be appended.
98 */
99 old = getenv("SYSTEMD_UNIT_PATH");
100 if (!streq_ptr(old, "")) {
101 if (!old)
102 old = ":";
103
104 r = strv_extend(&ans, old);
105 if (r < 0)
106 return r;
107 }
8b835fcc
ZJS
108
109 *var = strv_join(ans, ":");
110 if (!*var)
111 return -ENOMEM;
112
113 return 0;
114}
115
116static int verify_socket(Unit *u) {
117 int r;
118
119 assert(u);
120
121 if (u->type != UNIT_SOCKET)
122 return 0;
123
124 /* Cannot run this without the service being around */
125
126 /* This makes sure instance is created if necessary. */
127 r = socket_instantiate_service(SOCKET(u));
128 if (r < 0) {
f2341e0a 129 log_unit_error_errno(u, r, "Socket cannot be started, failed to create instance: %m");
8b835fcc
ZJS
130 return r;
131 }
132
133 /* This checks both type of sockets */
134 if (UNIT_ISSET(SOCKET(u)->service)) {
135 Service *service;
136
137 service = SERVICE(UNIT_DEREF(SOCKET(u)->service));
f2341e0a 138 log_unit_debug(u, "Using %s", UNIT(service)->id);
8b835fcc
ZJS
139
140 if (UNIT(service)->load_state != UNIT_LOADED) {
f2341e0a 141 log_unit_error(u, "Service %s not loaded, %s cannot be started.", UNIT(service)->id, u->id);
8b835fcc
ZJS
142 return -ENOENT;
143 }
144 }
145
146 return 0;
147}
148
149static int verify_executable(Unit *u, ExecCommand *exec) {
150 if (exec == NULL)
151 return 0;
152
f2341e0a
LP
153 if (access(exec->path, X_OK) < 0)
154 return log_unit_error_errno(u, errno, "Command %s is not executable: %m", exec->path);
8b835fcc
ZJS
155
156 return 0;
157}
158
159static int verify_executables(Unit *u) {
160 ExecCommand *exec;
161 int r = 0, k;
162 unsigned i;
163
164 assert(u);
165
166 exec = u->type == UNIT_SOCKET ? SOCKET(u)->control_command :
167 u->type == UNIT_MOUNT ? MOUNT(u)->control_command :
168 u->type == UNIT_SWAP ? SWAP(u)->control_command : NULL;
169 k = verify_executable(u, exec);
170 if (k < 0 && r == 0)
171 r = k;
172
173 if (u->type == UNIT_SERVICE)
174 for (i = 0; i < ELEMENTSOF(SERVICE(u)->exec_command); i++) {
175 k = verify_executable(u, SERVICE(u)->exec_command[i]);
176 if (k < 0 && r == 0)
177 r = k;
178 }
179
180 if (u->type == UNIT_SOCKET)
181 for (i = 0; i < ELEMENTSOF(SOCKET(u)->exec_command); i++) {
182 k = verify_executable(u, SOCKET(u)->exec_command[i]);
183 if (k < 0 && r == 0)
184 r = k;
185 }
186
187 return r;
188}
189
1d3bc017 190static int verify_documentation(Unit *u, bool check_man) {
78002a67
ZJS
191 char **p;
192 int r = 0, k;
193
78002a67 194 STRV_FOREACH(p, u->documentation) {
f2341e0a
LP
195 log_unit_debug(u, "Found documentation item: %s", *p);
196
1d3bc017 197 if (check_man && startswith(*p, "man:")) {
78002a67
ZJS
198 k = show_man_page(*p + 4, true);
199 if (k != 0) {
200 if (k < 0)
f2341e0a 201 log_unit_error_errno(u, r, "Can't show %s: %m", *p);
78002a67 202 else {
f2341e0a 203 log_unit_error_errno(u, r, "man %s command failed with code %d", *p + 4, k);
78002a67
ZJS
204 k = -ENOEXEC;
205 }
206 if (r == 0)
207 r = k;
208 }
209 }
210 }
211
212 /* Check remote URLs? */
213
214 return r;
215}
216
1d3bc017 217static int verify_unit(Unit *u, bool check_man) {
4afd3348 218 _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
8b835fcc
ZJS
219 int r, k;
220
221 assert(u);
222
223 if (log_get_max_level() >= LOG_DEBUG)
224 unit_dump(u, stdout, "\t");
225
f2341e0a 226 log_unit_debug(u, "Creating %s/start job", u->id);
4bd29fe5 227 r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, &err, NULL);
8b835fcc 228 if (r < 0)
4bd29fe5 229 log_unit_error_errno(u, r, "Failed to create %s/start: %s", u->id, bus_error_message(&err, r));
8b835fcc
ZJS
230
231 k = verify_socket(u);
232 if (k < 0 && r == 0)
233 r = k;
234
235 k = verify_executables(u);
236 if (k < 0 && r == 0)
237 r = k;
238
1d3bc017 239 k = verify_documentation(u, check_man);
78002a67
ZJS
240 if (k < 0 && r == 0)
241 r = k;
242
8b835fcc
ZJS
243 return r;
244}
245
641c0fd1 246int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators) {
4afd3348 247 _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
463d0d15 248 _cleanup_free_ char *var = NULL;
8b835fcc
ZJS
249 Manager *m = NULL;
250 FILE *serial = NULL;
251 FDSet *fdset = NULL;
8b835fcc
ZJS
252 char **filename;
253 int r = 0, k;
254
255 Unit *units[strv_length(filenames)];
256 int i, count = 0;
641c0fd1
ZJS
257 const uint8_t flags = MANAGER_TEST_RUN_ENV_GENERATORS |
258 run_generators * MANAGER_TEST_RUN_GENERATORS;
8b835fcc 259
1d3bc017
ZJS
260 if (strv_isempty(filenames))
261 return 0;
262
8b835fcc
ZJS
263 /* set the path */
264 r = generate_path(&var, filenames);
23bbb0de
MS
265 if (r < 0)
266 return log_error_errno(r, "Failed to generate unit load path: %m");
8b835fcc
ZJS
267
268 assert_se(set_unit_path(var) >= 0);
269
641c0fd1 270 r = manager_new(scope, flags, &m);
23bbb0de 271 if (r < 0)
ff9b60f3 272 return log_error_errno(r, "Failed to initialize manager: %m");
8b835fcc
ZJS
273
274 log_debug("Starting manager...");
275
276 r = manager_startup(m, serial, fdset);
277 if (r < 0) {
da927ba9 278 log_error_errno(r, "Failed to start manager: %m");
8b835fcc
ZJS
279 goto finish;
280 }
281
282 manager_clear_jobs(m);
283
284 log_debug("Loading remaining units from the command line...");
285
286 STRV_FOREACH(filename, filenames) {
25f17e47 287 _cleanup_free_ char *prepared = NULL;
1d3bc017 288
8b835fcc
ZJS
289 log_debug("Handling %s...", *filename);
290
25f17e47
EV
291 k = prepare_filename(*filename, &prepared);
292 if (k < 0) {
293 log_error_errno(k, "Failed to prepare filename %s: %m", *filename);
294 if (r == 0)
295 r = k;
296 continue;
297 }
298
299 k = manager_load_unit(m, NULL, prepared, &err, &units[count]);
8b835fcc 300 if (k < 0) {
da927ba9 301 log_error_errno(k, "Failed to load %s: %m", *filename);
8b835fcc
ZJS
302 if (r == 0)
303 r = k;
1d3bc017 304 } else
313cefa1 305 count++;
8b835fcc
ZJS
306 }
307
308 for (i = 0; i < count; i++) {
1d3bc017 309 k = verify_unit(units[i], check_man);
8b835fcc
ZJS
310 if (k < 0 && r == 0)
311 r = k;
312 }
313
314finish:
315 manager_free(m);
316
317 return r;
318}