]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/analyze/analyze-verify.c
resolved: fix error propagation
[thirdparty/systemd.git] / src / analyze / analyze-verify.c
CommitLineData
8b835fcc
ZJS
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Zbigniew Jędrzejewski-Szmek
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <stdlib.h>
8b835fcc 23
b5efdb8a 24#include "alloc-util.h"
5f311f8c 25#include "analyze-verify.h"
4bd29fe5 26#include "bus-error.h"
8b835fcc
ZJS
27#include "bus-util.h"
28#include "log.h"
5f311f8c 29#include "manager.h"
78002a67 30#include "pager.h"
5f311f8c
LP
31#include "path-util.h"
32#include "strv.h"
25f17e47
EV
33#include "unit-name.h"
34
35static int prepare_filename(const char *filename, char **ret) {
36 int r;
37 const char *name;
38 _cleanup_free_ char *abspath = NULL;
39 _cleanup_free_ char *dir = NULL;
40 _cleanup_free_ char *with_instance = NULL;
41 char *c;
42
43 assert(filename);
44 assert(ret);
45
46 r = path_make_absolute_cwd(filename, &abspath);
47 if (r < 0)
48 return r;
49
50 name = basename(abspath);
51 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
52 return -EINVAL;
53
54 if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) {
55 r = unit_name_replace_instance(name, "i", &with_instance);
56 if (r < 0)
57 return r;
58 }
59
60 dir = dirname_malloc(abspath);
61 if (!dir)
62 return -ENOMEM;
63
64 if (with_instance)
65 c = path_join(NULL, dir, with_instance);
66 else
67 c = path_join(NULL, dir, name);
68 if (!c)
69 return -ENOMEM;
70
71 *ret = c;
72 return 0;
73}
8b835fcc
ZJS
74
75static int generate_path(char **var, char **filenames) {
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
95 r = strv_extend(&ans, "");
96 if (r < 0)
97 return r;
98
99 *var = strv_join(ans, ":");
100 if (!*var)
101 return -ENOMEM;
102
103 return 0;
104}
105
106static int verify_socket(Unit *u) {
107 int r;
108
109 assert(u);
110
111 if (u->type != UNIT_SOCKET)
112 return 0;
113
114 /* Cannot run this without the service being around */
115
116 /* This makes sure instance is created if necessary. */
117 r = socket_instantiate_service(SOCKET(u));
118 if (r < 0) {
f2341e0a 119 log_unit_error_errno(u, r, "Socket cannot be started, failed to create instance: %m");
8b835fcc
ZJS
120 return r;
121 }
122
123 /* This checks both type of sockets */
124 if (UNIT_ISSET(SOCKET(u)->service)) {
125 Service *service;
126
127 service = SERVICE(UNIT_DEREF(SOCKET(u)->service));
f2341e0a 128 log_unit_debug(u, "Using %s", UNIT(service)->id);
8b835fcc
ZJS
129
130 if (UNIT(service)->load_state != UNIT_LOADED) {
f2341e0a 131 log_unit_error(u, "Service %s not loaded, %s cannot be started.", UNIT(service)->id, u->id);
8b835fcc
ZJS
132 return -ENOENT;
133 }
134 }
135
136 return 0;
137}
138
139static int verify_executable(Unit *u, ExecCommand *exec) {
140 if (exec == NULL)
141 return 0;
142
f2341e0a
LP
143 if (access(exec->path, X_OK) < 0)
144 return log_unit_error_errno(u, errno, "Command %s is not executable: %m", exec->path);
8b835fcc
ZJS
145
146 return 0;
147}
148
149static int verify_executables(Unit *u) {
150 ExecCommand *exec;
151 int r = 0, k;
152 unsigned i;
153
154 assert(u);
155
156 exec = u->type == UNIT_SOCKET ? SOCKET(u)->control_command :
157 u->type == UNIT_MOUNT ? MOUNT(u)->control_command :
158 u->type == UNIT_SWAP ? SWAP(u)->control_command : NULL;
159 k = verify_executable(u, exec);
160 if (k < 0 && r == 0)
161 r = k;
162
163 if (u->type == UNIT_SERVICE)
164 for (i = 0; i < ELEMENTSOF(SERVICE(u)->exec_command); i++) {
165 k = verify_executable(u, SERVICE(u)->exec_command[i]);
166 if (k < 0 && r == 0)
167 r = k;
168 }
169
170 if (u->type == UNIT_SOCKET)
171 for (i = 0; i < ELEMENTSOF(SOCKET(u)->exec_command); i++) {
172 k = verify_executable(u, SOCKET(u)->exec_command[i]);
173 if (k < 0 && r == 0)
174 r = k;
175 }
176
177 return r;
178}
179
1d3bc017 180static int verify_documentation(Unit *u, bool check_man) {
78002a67
ZJS
181 char **p;
182 int r = 0, k;
183
78002a67 184 STRV_FOREACH(p, u->documentation) {
f2341e0a
LP
185 log_unit_debug(u, "Found documentation item: %s", *p);
186
1d3bc017 187 if (check_man && startswith(*p, "man:")) {
78002a67
ZJS
188 k = show_man_page(*p + 4, true);
189 if (k != 0) {
190 if (k < 0)
f2341e0a 191 log_unit_error_errno(u, r, "Can't show %s: %m", *p);
78002a67 192 else {
f2341e0a 193 log_unit_error_errno(u, r, "man %s command failed with code %d", *p + 4, k);
78002a67
ZJS
194 k = -ENOEXEC;
195 }
196 if (r == 0)
197 r = k;
198 }
199 }
200 }
201
202 /* Check remote URLs? */
203
204 return r;
205}
206
1d3bc017 207static int verify_unit(Unit *u, bool check_man) {
4afd3348 208 _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
8b835fcc
ZJS
209 int r, k;
210
211 assert(u);
212
213 if (log_get_max_level() >= LOG_DEBUG)
214 unit_dump(u, stdout, "\t");
215
f2341e0a 216 log_unit_debug(u, "Creating %s/start job", u->id);
4bd29fe5 217 r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, &err, NULL);
8b835fcc 218 if (r < 0)
4bd29fe5 219 log_unit_error_errno(u, r, "Failed to create %s/start: %s", u->id, bus_error_message(&err, r));
8b835fcc
ZJS
220
221 k = verify_socket(u);
222 if (k < 0 && r == 0)
223 r = k;
224
225 k = verify_executables(u);
226 if (k < 0 && r == 0)
227 r = k;
228
1d3bc017 229 k = verify_documentation(u, check_man);
78002a67
ZJS
230 if (k < 0 && r == 0)
231 r = k;
232
8b835fcc
ZJS
233 return r;
234}
235
b2c23da8 236int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man) {
4afd3348 237 _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
8b835fcc
ZJS
238 Manager *m = NULL;
239 FILE *serial = NULL;
240 FDSet *fdset = NULL;
241
1d3bc017 242 _cleanup_free_ char *var = NULL;
8b835fcc
ZJS
243
244 char **filename;
245 int r = 0, k;
246
247 Unit *units[strv_length(filenames)];
248 int i, count = 0;
249
1d3bc017
ZJS
250 if (strv_isempty(filenames))
251 return 0;
252
8b835fcc
ZJS
253 /* set the path */
254 r = generate_path(&var, filenames);
23bbb0de
MS
255 if (r < 0)
256 return log_error_errno(r, "Failed to generate unit load path: %m");
8b835fcc
ZJS
257
258 assert_se(set_unit_path(var) >= 0);
259
1d3bc017 260 r = manager_new(running_as, true, &m);
23bbb0de 261 if (r < 0)
ff9b60f3 262 return log_error_errno(r, "Failed to initialize manager: %m");
8b835fcc
ZJS
263
264 log_debug("Starting manager...");
265
266 r = manager_startup(m, serial, fdset);
267 if (r < 0) {
da927ba9 268 log_error_errno(r, "Failed to start manager: %m");
8b835fcc
ZJS
269 goto finish;
270 }
271
272 manager_clear_jobs(m);
273
274 log_debug("Loading remaining units from the command line...");
275
276 STRV_FOREACH(filename, filenames) {
25f17e47 277 _cleanup_free_ char *prepared = NULL;
1d3bc017 278
8b835fcc
ZJS
279 log_debug("Handling %s...", *filename);
280
25f17e47
EV
281 k = prepare_filename(*filename, &prepared);
282 if (k < 0) {
283 log_error_errno(k, "Failed to prepare filename %s: %m", *filename);
284 if (r == 0)
285 r = k;
286 continue;
287 }
288
289 k = manager_load_unit(m, NULL, prepared, &err, &units[count]);
8b835fcc 290 if (k < 0) {
da927ba9 291 log_error_errno(k, "Failed to load %s: %m", *filename);
8b835fcc
ZJS
292 if (r == 0)
293 r = k;
1d3bc017
ZJS
294 } else
295 count ++;
8b835fcc
ZJS
296 }
297
298 for (i = 0; i < count; i++) {
1d3bc017 299 k = verify_unit(units[i], check_man);
8b835fcc
ZJS
300 if (k < 0 && r == 0)
301 r = k;
302 }
303
304finish:
305 manager_free(m);
306
307 return r;
308}