]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/analyze/analyze-verify.c
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
[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"
8b835fcc
ZJS
33
34static int generate_path(char **var, char **filenames) {
35 char **filename;
36
37 _cleanup_strv_free_ char **ans = NULL;
38 int r;
39
40 STRV_FOREACH(filename, filenames) {
41 char *t;
42
43 t = dirname_malloc(*filename);
44 if (!t)
45 return -ENOMEM;
46
47 r = strv_consume(&ans, t);
48 if (r < 0)
49 return r;
50 }
51
52 assert_se(strv_uniq(ans));
53
54 r = strv_extend(&ans, "");
55 if (r < 0)
56 return r;
57
58 *var = strv_join(ans, ":");
59 if (!*var)
60 return -ENOMEM;
61
62 return 0;
63}
64
65static int verify_socket(Unit *u) {
66 int r;
67
68 assert(u);
69
70 if (u->type != UNIT_SOCKET)
71 return 0;
72
73 /* Cannot run this without the service being around */
74
75 /* This makes sure instance is created if necessary. */
76 r = socket_instantiate_service(SOCKET(u));
77 if (r < 0) {
f2341e0a 78 log_unit_error_errno(u, r, "Socket cannot be started, failed to create instance: %m");
8b835fcc
ZJS
79 return r;
80 }
81
82 /* This checks both type of sockets */
83 if (UNIT_ISSET(SOCKET(u)->service)) {
84 Service *service;
85
86 service = SERVICE(UNIT_DEREF(SOCKET(u)->service));
f2341e0a 87 log_unit_debug(u, "Using %s", UNIT(service)->id);
8b835fcc
ZJS
88
89 if (UNIT(service)->load_state != UNIT_LOADED) {
f2341e0a 90 log_unit_error(u, "Service %s not loaded, %s cannot be started.", UNIT(service)->id, u->id);
8b835fcc
ZJS
91 return -ENOENT;
92 }
93 }
94
95 return 0;
96}
97
98static int verify_executable(Unit *u, ExecCommand *exec) {
99 if (exec == NULL)
100 return 0;
101
f2341e0a
LP
102 if (access(exec->path, X_OK) < 0)
103 return log_unit_error_errno(u, errno, "Command %s is not executable: %m", exec->path);
8b835fcc
ZJS
104
105 return 0;
106}
107
108static int verify_executables(Unit *u) {
109 ExecCommand *exec;
110 int r = 0, k;
111 unsigned i;
112
113 assert(u);
114
115 exec = u->type == UNIT_SOCKET ? SOCKET(u)->control_command :
116 u->type == UNIT_MOUNT ? MOUNT(u)->control_command :
117 u->type == UNIT_SWAP ? SWAP(u)->control_command : NULL;
118 k = verify_executable(u, exec);
119 if (k < 0 && r == 0)
120 r = k;
121
122 if (u->type == UNIT_SERVICE)
123 for (i = 0; i < ELEMENTSOF(SERVICE(u)->exec_command); i++) {
124 k = verify_executable(u, SERVICE(u)->exec_command[i]);
125 if (k < 0 && r == 0)
126 r = k;
127 }
128
129 if (u->type == UNIT_SOCKET)
130 for (i = 0; i < ELEMENTSOF(SOCKET(u)->exec_command); i++) {
131 k = verify_executable(u, SOCKET(u)->exec_command[i]);
132 if (k < 0 && r == 0)
133 r = k;
134 }
135
136 return r;
137}
138
1d3bc017 139static int verify_documentation(Unit *u, bool check_man) {
78002a67
ZJS
140 char **p;
141 int r = 0, k;
142
78002a67 143 STRV_FOREACH(p, u->documentation) {
f2341e0a
LP
144 log_unit_debug(u, "Found documentation item: %s", *p);
145
1d3bc017 146 if (check_man && startswith(*p, "man:")) {
78002a67
ZJS
147 k = show_man_page(*p + 4, true);
148 if (k != 0) {
149 if (k < 0)
f2341e0a 150 log_unit_error_errno(u, r, "Can't show %s: %m", *p);
78002a67 151 else {
f2341e0a 152 log_unit_error_errno(u, r, "man %s command failed with code %d", *p + 4, k);
78002a67
ZJS
153 k = -ENOEXEC;
154 }
155 if (r == 0)
156 r = k;
157 }
158 }
159 }
160
161 /* Check remote URLs? */
162
163 return r;
164}
165
1d3bc017 166static int verify_unit(Unit *u, bool check_man) {
4afd3348 167 _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
8b835fcc
ZJS
168 int r, k;
169
170 assert(u);
171
172 if (log_get_max_level() >= LOG_DEBUG)
173 unit_dump(u, stdout, "\t");
174
f2341e0a 175 log_unit_debug(u, "Creating %s/start job", u->id);
4bd29fe5 176 r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, &err, NULL);
8b835fcc 177 if (r < 0)
4bd29fe5 178 log_unit_error_errno(u, r, "Failed to create %s/start: %s", u->id, bus_error_message(&err, r));
8b835fcc
ZJS
179
180 k = verify_socket(u);
181 if (k < 0 && r == 0)
182 r = k;
183
184 k = verify_executables(u);
185 if (k < 0 && r == 0)
186 r = k;
187
1d3bc017 188 k = verify_documentation(u, check_man);
78002a67
ZJS
189 if (k < 0 && r == 0)
190 r = k;
191
8b835fcc
ZJS
192 return r;
193}
194
b2c23da8 195int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man) {
4afd3348 196 _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
8b835fcc
ZJS
197 Manager *m = NULL;
198 FILE *serial = NULL;
199 FDSet *fdset = NULL;
200
1d3bc017 201 _cleanup_free_ char *var = NULL;
8b835fcc
ZJS
202
203 char **filename;
204 int r = 0, k;
205
206 Unit *units[strv_length(filenames)];
207 int i, count = 0;
208
1d3bc017
ZJS
209 if (strv_isempty(filenames))
210 return 0;
211
8b835fcc
ZJS
212 /* set the path */
213 r = generate_path(&var, filenames);
23bbb0de
MS
214 if (r < 0)
215 return log_error_errno(r, "Failed to generate unit load path: %m");
8b835fcc
ZJS
216
217 assert_se(set_unit_path(var) >= 0);
218
1d3bc017 219 r = manager_new(running_as, true, &m);
23bbb0de 220 if (r < 0)
ff9b60f3 221 return log_error_errno(r, "Failed to initialize manager: %m");
8b835fcc
ZJS
222
223 log_debug("Starting manager...");
224
225 r = manager_startup(m, serial, fdset);
226 if (r < 0) {
da927ba9 227 log_error_errno(r, "Failed to start manager: %m");
8b835fcc
ZJS
228 goto finish;
229 }
230
231 manager_clear_jobs(m);
232
233 log_debug("Loading remaining units from the command line...");
234
235 STRV_FOREACH(filename, filenames) {
1d3bc017
ZJS
236 char fname[UNIT_NAME_MAX + 2 + 1] = "./";
237
8b835fcc
ZJS
238 log_debug("Handling %s...", *filename);
239
1d3bc017
ZJS
240 /* manager_load_unit does not like pure basenames, so prepend
241 * the local directory, but only for valid names. manager_load_unit
242 * will print the error for other ones. */
243 if (!strchr(*filename, '/') && strlen(*filename) <= UNIT_NAME_MAX) {
244 strncat(fname + 2, *filename, UNIT_NAME_MAX);
245 k = manager_load_unit(m, NULL, fname, &err, &units[count]);
246 } else
247 k = manager_load_unit(m, NULL, *filename, &err, &units[count]);
8b835fcc 248 if (k < 0) {
da927ba9 249 log_error_errno(k, "Failed to load %s: %m", *filename);
8b835fcc
ZJS
250 if (r == 0)
251 r = k;
1d3bc017
ZJS
252 } else
253 count ++;
8b835fcc
ZJS
254 }
255
256 for (i = 0; i < count; i++) {
1d3bc017 257 k = verify_unit(units[i], check_man);
8b835fcc
ZJS
258 if (k < 0 && r == 0)
259 r = k;
260 }
261
262finish:
263 manager_free(m);
264
265 return r;
266}