]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/verify/verify.c
configure: add -Wno-typedef-redefinition
[thirdparty/systemd.git] / src / verify / 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>
23#include <getopt.h>
24
25#include "manager.h"
26#include "bus-util.h"
27#include "log.h"
28#include "strv.h"
29#include "build.h"
78002a67 30#include "pager.h"
8b835fcc
ZJS
31
32SystemdRunningAs arg_running_as = SYSTEMD_SYSTEM;
78002a67 33bool arg_no_man = false;
8b835fcc
ZJS
34
35static int generate_path(char **var, char **filenames) {
36 char **filename;
37
38 _cleanup_strv_free_ char **ans = NULL;
39 int r;
40
41 STRV_FOREACH(filename, filenames) {
42 char *t;
43
44 t = dirname_malloc(*filename);
45 if (!t)
46 return -ENOMEM;
47
48 r = strv_consume(&ans, t);
49 if (r < 0)
50 return r;
51 }
52
53 assert_se(strv_uniq(ans));
54
55 r = strv_extend(&ans, "");
56 if (r < 0)
57 return r;
58
59 *var = strv_join(ans, ":");
60 if (!*var)
61 return -ENOMEM;
62
63 return 0;
64}
65
66static int verify_socket(Unit *u) {
67 int r;
68
69 assert(u);
70
71 if (u->type != UNIT_SOCKET)
72 return 0;
73
74 /* Cannot run this without the service being around */
75
76 /* This makes sure instance is created if necessary. */
77 r = socket_instantiate_service(SOCKET(u));
78 if (r < 0) {
79 log_error_unit(u->id, "Socket %s cannot be started, failed to create instance.",
80 u->id);
81 return r;
82 }
83
84 /* This checks both type of sockets */
85 if (UNIT_ISSET(SOCKET(u)->service)) {
86 Service *service;
87
88 service = SERVICE(UNIT_DEREF(SOCKET(u)->service));
89 log_debug_unit(u->id, "%s uses %s", u->id, UNIT(service)->id);
90
91 if (UNIT(service)->load_state != UNIT_LOADED) {
92 log_error_unit(u->id, "Service %s not loaded, %s cannot be started.",
93 UNIT(service)->id, u->id);
94 return -ENOENT;
95 }
96 }
97
98 return 0;
99}
100
101static int verify_executable(Unit *u, ExecCommand *exec) {
102 if (exec == NULL)
103 return 0;
104
105 if (access(exec->path, X_OK) < 0) {
106 log_error_unit(u->id, "%s: command %s is not executable: %m",
107 u->id, exec->path);
108 return -errno;
109 }
110
111 return 0;
112}
113
114static int verify_executables(Unit *u) {
115 ExecCommand *exec;
116 int r = 0, k;
117 unsigned i;
118
119 assert(u);
120
121 exec = u->type == UNIT_SOCKET ? SOCKET(u)->control_command :
122 u->type == UNIT_MOUNT ? MOUNT(u)->control_command :
123 u->type == UNIT_SWAP ? SWAP(u)->control_command : NULL;
124 k = verify_executable(u, exec);
125 if (k < 0 && r == 0)
126 r = k;
127
128 if (u->type == UNIT_SERVICE)
129 for (i = 0; i < ELEMENTSOF(SERVICE(u)->exec_command); i++) {
130 k = verify_executable(u, SERVICE(u)->exec_command[i]);
131 if (k < 0 && r == 0)
132 r = k;
133 }
134
135 if (u->type == UNIT_SOCKET)
136 for (i = 0; i < ELEMENTSOF(SOCKET(u)->exec_command); i++) {
137 k = verify_executable(u, SOCKET(u)->exec_command[i]);
138 if (k < 0 && r == 0)
139 r = k;
140 }
141
142 return r;
143}
144
78002a67
ZJS
145static int verify_documentation(Unit *u) {
146 char **p;
147 int r = 0, k;
148
149 if (arg_no_man)
150 return 0;
151
152 STRV_FOREACH(p, u->documentation) {
153 log_debug_unit(u->id, "%s: found documentation item %s.", u->id, *p);
154 if (startswith(*p, "man:")) {
155 k = show_man_page(*p + 4, true);
156 if (k != 0) {
157 if (k < 0)
158 log_error_unit(u->id, "%s: can't show %s: %s",
159 u->id, *p, strerror(-r));
160 else {
161 log_error_unit(u->id, "%s: man %s command failed with code %d",
162 u->id, *p + 4, k);
163 k = -ENOEXEC;
164 }
165 if (r == 0)
166 r = k;
167 }
168 }
169 }
170
171 /* Check remote URLs? */
172
173 return r;
174}
175
8b835fcc
ZJS
176static int test_unit(Unit *u) {
177 _cleanup_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL;
178 Job *j;
179 int r, k;
180
181 assert(u);
182
183 if (log_get_max_level() >= LOG_DEBUG)
184 unit_dump(u, stdout, "\t");
185
186 log_debug_unit(u->id, "Creating %s/start job", u->id);
187 r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, false, &err, &j);
188 if (sd_bus_error_is_set(&err))
189 log_error_unit(u->id, "Error: %s: %s",
190 err.name, err.message);
191 if (r < 0)
192 log_error_unit(u->id, "Failed to create %s/start: %s",
193 u->id, strerror(-r));
194
195 k = verify_socket(u);
196 if (k < 0 && r == 0)
197 r = k;
198
199 k = verify_executables(u);
200 if (k < 0 && r == 0)
201 r = k;
202
78002a67
ZJS
203 k = verify_documentation(u);
204 if (k < 0 && r == 0)
205 r = k;
206
8b835fcc
ZJS
207 return r;
208}
209
210static int test_units(char **filenames) {
211 _cleanup_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL;
212 Manager *m = NULL;
213 FILE *serial = NULL;
214 FDSet *fdset = NULL;
215
216 _cleanup_free_ char *var;
217
218 char **filename;
219 int r = 0, k;
220
221 Unit *units[strv_length(filenames)];
222 int i, count = 0;
223
224 /* set the path */
225 r = generate_path(&var, filenames);
226 if (r < 0) {
227 log_error("Failed to generate unit load path: %s", strerror(-r));
228 return r;
229 }
230
231 assert_se(set_unit_path(var) >= 0);
232
233 r = manager_new(arg_running_as, true, &m);
234 if (r < 0) {
235 log_error("Failed to initalize manager: %s", strerror(-r));
236 return r;
237 }
238
239 log_debug("Starting manager...");
240
241 r = manager_startup(m, serial, fdset);
242 if (r < 0) {
243 log_error("Failed to start manager: %s", strerror(-r));
244 goto finish;
245 }
246
247 manager_clear_jobs(m);
248
249 log_debug("Loading remaining units from the command line...");
250
251 STRV_FOREACH(filename, filenames) {
252 log_debug("Handling %s...", *filename);
253
254 k = manager_load_unit(m, NULL, *filename, &err, &units[count]);
255 if (k < 0) {
256 log_error("Failed to load %s: %s", *filename, strerror(-r));
257 if (r == 0)
258 r = k;
259 }
260
261 count ++;
262 }
263
264 for (i = 0; i < count; i++) {
265 k = test_unit(units[i]);
266 if (k < 0 && r == 0)
267 r = k;
268 }
269
270finish:
271 manager_free(m);
272
273 return r;
274}
275
276static void help(void) {
277 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
278 "Check if unit files can be correctly loaded.\n\n"
279 " -h --help Show this help\n"
280 " --version Show package version\n"
0e8415f2
ZJS
281 " --system Test system units\n"
282 " --user Test user units\n"
78002a67
ZJS
283 " --no-man Do not check for existence of man pages\n"
284 , program_invocation_short_name);
8b835fcc
ZJS
285}
286
287static int parse_argv(int argc, char *argv[]) {
288 enum {
289 ARG_VERSION = 0x100,
290 ARG_USER,
291 ARG_SYSTEM,
78002a67 292 ARG_NO_MAN,
8b835fcc
ZJS
293 };
294
295 static const struct option options[] = {
296 { "help", no_argument, NULL, 'h' },
297 { "version", no_argument, NULL, ARG_VERSION },
298 { "user", no_argument, NULL, ARG_USER },
299 { "system", no_argument, NULL, ARG_SYSTEM },
300 {}
301 };
302
303 int c;
304
305 assert(argc >= 1);
306 assert(argv);
307
308 opterr = 0;
309
310 while ((c = getopt_long(argc, argv, ":h", options, NULL)) >= 0)
311 switch (c) {
312
313 case 'h':
314 help();
315 return 0;
316
317 case ARG_VERSION:
318 puts(PACKAGE_STRING);
319 puts(SYSTEMD_FEATURES);
320 return 0;
321
322 case ARG_USER:
323 arg_running_as = SYSTEMD_USER;
324 break;
325
326 case ARG_SYSTEM:
327 arg_running_as = SYSTEMD_SYSTEM;
328 break;
329
78002a67
ZJS
330 case ARG_NO_MAN:
331 arg_no_man = true;
332 break;
333
8b835fcc
ZJS
334 case '?':
335 log_error("Unknown option %s.", argv[optind-1]);
336 return -EINVAL;
337
338 case ':':
339 log_error("Missing argument to %s.", argv[optind-1]);
340 return -EINVAL;
341
342 default:
343 assert_not_reached("Unhandled option code.");
344 }
345
346 return 1; /* work to do */
347}
348
349int main(int argc, char *argv[]) {
350 int r;
351
352 log_parse_environment();
353 log_open();
354
355 r = parse_argv(argc, argv);
356 if (r <= 0)
357 goto finish;
358
359 r = test_units(argv + optind);
360
361finish:
362 return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
363}