]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/analyze/analyze-verify.c
tree-wide: use coccinelle to patch a lot of code to use mfree()
[thirdparty/systemd.git] / src / analyze / analyze-verify.c
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
24 #include "manager.h"
25 #include "bus-util.h"
26 #include "log.h"
27 #include "strv.h"
28 #include "pager.h"
29 #include "analyze-verify.h"
30
31 static int generate_path(char **var, char **filenames) {
32 char **filename;
33
34 _cleanup_strv_free_ char **ans = NULL;
35 int r;
36
37 STRV_FOREACH(filename, filenames) {
38 char *t;
39
40 t = dirname_malloc(*filename);
41 if (!t)
42 return -ENOMEM;
43
44 r = strv_consume(&ans, t);
45 if (r < 0)
46 return r;
47 }
48
49 assert_se(strv_uniq(ans));
50
51 r = strv_extend(&ans, "");
52 if (r < 0)
53 return r;
54
55 *var = strv_join(ans, ":");
56 if (!*var)
57 return -ENOMEM;
58
59 return 0;
60 }
61
62 static int verify_socket(Unit *u) {
63 int r;
64
65 assert(u);
66
67 if (u->type != UNIT_SOCKET)
68 return 0;
69
70 /* Cannot run this without the service being around */
71
72 /* This makes sure instance is created if necessary. */
73 r = socket_instantiate_service(SOCKET(u));
74 if (r < 0) {
75 log_unit_error_errno(u, r, "Socket cannot be started, failed to create instance: %m");
76 return r;
77 }
78
79 /* This checks both type of sockets */
80 if (UNIT_ISSET(SOCKET(u)->service)) {
81 Service *service;
82
83 service = SERVICE(UNIT_DEREF(SOCKET(u)->service));
84 log_unit_debug(u, "Using %s", UNIT(service)->id);
85
86 if (UNIT(service)->load_state != UNIT_LOADED) {
87 log_unit_error(u, "Service %s not loaded, %s cannot be started.", UNIT(service)->id, u->id);
88 return -ENOENT;
89 }
90 }
91
92 return 0;
93 }
94
95 static int verify_executable(Unit *u, ExecCommand *exec) {
96 if (exec == NULL)
97 return 0;
98
99 if (access(exec->path, X_OK) < 0)
100 return log_unit_error_errno(u, errno, "Command %s is not executable: %m", exec->path);
101
102 return 0;
103 }
104
105 static int verify_executables(Unit *u) {
106 ExecCommand *exec;
107 int r = 0, k;
108 unsigned i;
109
110 assert(u);
111
112 exec = u->type == UNIT_SOCKET ? SOCKET(u)->control_command :
113 u->type == UNIT_MOUNT ? MOUNT(u)->control_command :
114 u->type == UNIT_SWAP ? SWAP(u)->control_command : NULL;
115 k = verify_executable(u, exec);
116 if (k < 0 && r == 0)
117 r = k;
118
119 if (u->type == UNIT_SERVICE)
120 for (i = 0; i < ELEMENTSOF(SERVICE(u)->exec_command); i++) {
121 k = verify_executable(u, SERVICE(u)->exec_command[i]);
122 if (k < 0 && r == 0)
123 r = k;
124 }
125
126 if (u->type == UNIT_SOCKET)
127 for (i = 0; i < ELEMENTSOF(SOCKET(u)->exec_command); i++) {
128 k = verify_executable(u, SOCKET(u)->exec_command[i]);
129 if (k < 0 && r == 0)
130 r = k;
131 }
132
133 return r;
134 }
135
136 static int verify_documentation(Unit *u, bool check_man) {
137 char **p;
138 int r = 0, k;
139
140 STRV_FOREACH(p, u->documentation) {
141 log_unit_debug(u, "Found documentation item: %s", *p);
142
143 if (check_man && startswith(*p, "man:")) {
144 k = show_man_page(*p + 4, true);
145 if (k != 0) {
146 if (k < 0)
147 log_unit_error_errno(u, r, "Can't show %s: %m", *p);
148 else {
149 log_unit_error_errno(u, r, "man %s command failed with code %d", *p + 4, k);
150 k = -ENOEXEC;
151 }
152 if (r == 0)
153 r = k;
154 }
155 }
156 }
157
158 /* Check remote URLs? */
159
160 return r;
161 }
162
163 static int verify_unit(Unit *u, bool check_man) {
164 _cleanup_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL;
165 Job *j;
166 int r, k;
167
168 assert(u);
169
170 if (log_get_max_level() >= LOG_DEBUG)
171 unit_dump(u, stdout, "\t");
172
173 log_unit_debug(u, "Creating %s/start job", u->id);
174 r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, false, &err, &j);
175 if (sd_bus_error_is_set(&err))
176 log_unit_error(u, "Error: %s: %s", err.name, err.message);
177 if (r < 0)
178 log_unit_error_errno(u, r, "Failed to create %s/start: %m", u->id);
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
188 k = verify_documentation(u, check_man);
189 if (k < 0 && r == 0)
190 r = k;
191
192 return r;
193 }
194
195 int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man) {
196 _cleanup_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL;
197 Manager *m = NULL;
198 FILE *serial = NULL;
199 FDSet *fdset = NULL;
200
201 _cleanup_free_ char *var = NULL;
202
203 char **filename;
204 int r = 0, k;
205
206 Unit *units[strv_length(filenames)];
207 int i, count = 0;
208
209 if (strv_isempty(filenames))
210 return 0;
211
212 /* set the path */
213 r = generate_path(&var, filenames);
214 if (r < 0)
215 return log_error_errno(r, "Failed to generate unit load path: %m");
216
217 assert_se(set_unit_path(var) >= 0);
218
219 r = manager_new(running_as, true, &m);
220 if (r < 0)
221 return log_error_errno(r, "Failed to initialize manager: %m");
222
223 log_debug("Starting manager...");
224
225 r = manager_startup(m, serial, fdset);
226 if (r < 0) {
227 log_error_errno(r, "Failed to start manager: %m");
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) {
236 char fname[UNIT_NAME_MAX + 2 + 1] = "./";
237
238 log_debug("Handling %s...", *filename);
239
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]);
248 if (k < 0) {
249 log_error_errno(k, "Failed to load %s: %m", *filename);
250 if (r == 0)
251 r = k;
252 } else
253 count ++;
254 }
255
256 for (i = 0; i < count; i++) {
257 k = verify_unit(units[i], check_man);
258 if (k < 0 && r == 0)
259 r = k;
260 }
261
262 finish:
263 manager_free(m);
264
265 return r;
266 }