chiark / gitweb /
bus-proxyd: explicitly address messages to unique and well-known name
[elogind.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 #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"
30 #include "pager.h"
31 #include "analyze-verify.h"
32
33 static int generate_path(char **var, char **filenames) {
34         char **filename;
35
36         _cleanup_strv_free_ char **ans = NULL;
37         int r;
38
39         STRV_FOREACH(filename, filenames) {
40                 char *t;
41
42                 t = dirname_malloc(*filename);
43                 if (!t)
44                         return -ENOMEM;
45
46                 r = strv_consume(&ans, t);
47                 if (r < 0)
48                         return r;
49         }
50
51         assert_se(strv_uniq(ans));
52
53         r = strv_extend(&ans, "");
54         if (r < 0)
55                 return r;
56
57         *var = strv_join(ans, ":");
58         if (!*var)
59                 return -ENOMEM;
60
61         return 0;
62 }
63
64 static int verify_socket(Unit *u) {
65         int r;
66
67         assert(u);
68
69         if (u->type != UNIT_SOCKET)
70                 return 0;
71
72         /* Cannot run this without the service being around */
73
74         /* This makes sure instance is created if necessary. */
75         r = socket_instantiate_service(SOCKET(u));
76         if (r < 0) {
77                 log_error_unit(u->id, "Socket %s cannot be started, failed to create instance.",
78                                u->id);
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));
87                 log_debug_unit(u->id, "%s uses %s", u->id, UNIT(service)->id);
88
89                 if (UNIT(service)->load_state != UNIT_LOADED) {
90                         log_error_unit(u->id, "Service %s not loaded, %s cannot be started.",
91                                        UNIT(service)->id, u->id);
92                         return -ENOENT;
93                 }
94         }
95
96         return 0;
97 }
98
99 static int verify_executable(Unit *u, ExecCommand *exec) {
100         if (exec == NULL)
101                 return 0;
102
103         if (access(exec->path, X_OK) < 0) {
104                 log_error_unit(u->id, "%s: command %s is not executable: %m",
105                                u->id, exec->path);
106                 return -errno;
107         }
108
109         return 0;
110 }
111
112 static int verify_executables(Unit *u) {
113         ExecCommand *exec;
114         int r = 0, k;
115         unsigned i;
116
117         assert(u);
118
119         exec =  u->type == UNIT_SOCKET ? SOCKET(u)->control_command :
120                 u->type == UNIT_MOUNT ? MOUNT(u)->control_command :
121                 u->type == UNIT_SWAP ? SWAP(u)->control_command : NULL;
122         k = verify_executable(u, exec);
123         if (k < 0 && r == 0)
124                 r = k;
125
126         if (u->type == UNIT_SERVICE)
127                 for (i = 0; i < ELEMENTSOF(SERVICE(u)->exec_command); i++) {
128                         k = verify_executable(u, SERVICE(u)->exec_command[i]);
129                         if (k < 0 && r == 0)
130                                 r = k;
131                 }
132
133         if (u->type == UNIT_SOCKET)
134                 for (i = 0; i < ELEMENTSOF(SOCKET(u)->exec_command); i++) {
135                         k = verify_executable(u, SOCKET(u)->exec_command[i]);
136                         if (k < 0 && r == 0)
137                                 r = k;
138                 }
139
140         return r;
141 }
142
143 static int verify_documentation(Unit *u, bool check_man) {
144         char **p;
145         int r = 0, k;
146
147         STRV_FOREACH(p, u->documentation) {
148                 log_debug_unit(u->id, "%s: found documentation item %s.", u->id, *p);
149                 if (check_man && startswith(*p, "man:")) {
150                         k = show_man_page(*p + 4, true);
151                         if (k != 0) {
152                                 if (k < 0)
153                                         log_error_unit(u->id, "%s: can't show %s: %s",
154                                                        u->id, *p, strerror(-r));
155                                 else {
156                                         log_error_unit(u->id, "%s: man %s command failed with code %d",
157                                                        u->id, *p + 4, k);
158                                         k = -ENOEXEC;
159                                 }
160                                 if (r == 0)
161                                         r = k;
162                         }
163                 }
164         }
165
166         /* Check remote URLs? */
167
168         return r;
169 }
170
171 static int verify_unit(Unit *u, bool check_man) {
172         _cleanup_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL;
173         Job *j;
174         int r, k;
175
176         assert(u);
177
178         if (log_get_max_level() >= LOG_DEBUG)
179                 unit_dump(u, stdout, "\t");
180
181         log_debug_unit(u->id, "Creating %s/start job", u->id);
182         r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, false, &err, &j);
183         if (sd_bus_error_is_set(&err))
184                 log_error_unit(u->id, "Error: %s: %s",
185                                err.name, err.message);
186         if (r < 0)
187                 log_error_unit(u->id, "Failed to create %s/start: %s",
188                                u->id, strerror(-r));
189
190         k = verify_socket(u);
191         if (k < 0 && r == 0)
192                 r = k;
193
194         k = verify_executables(u);
195         if (k < 0 && r == 0)
196                 r = k;
197
198         k = verify_documentation(u, check_man);
199         if (k < 0 && r == 0)
200                 r = k;
201
202         return r;
203 }
204
205 int verify_units(char **filenames, SystemdRunningAs running_as, bool check_man) {
206         _cleanup_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL;
207         Manager *m = NULL;
208         FILE *serial = NULL;
209         FDSet *fdset = NULL;
210
211         _cleanup_free_ char *var = NULL;
212
213         char **filename;
214         int r = 0, k;
215
216         Unit *units[strv_length(filenames)];
217         int i, count = 0;
218
219         if (strv_isempty(filenames))
220                 return 0;
221
222         /* set the path */
223         r = generate_path(&var, filenames);
224         if (r < 0) {
225                 log_error("Failed to generate unit load path: %s", strerror(-r));
226                 return r;
227         }
228
229         assert_se(set_unit_path(var) >= 0);
230
231         r = manager_new(running_as, true, &m);
232         if (r < 0) {
233                 log_error("Failed to initalize manager: %s", strerror(-r));
234                 return r;
235         }
236
237         log_debug("Starting manager...");
238
239         r = manager_startup(m, serial, fdset);
240         if (r < 0) {
241                 log_error("Failed to start manager: %s", strerror(-r));
242                 goto finish;
243         }
244
245         manager_clear_jobs(m);
246
247         log_debug("Loading remaining units from the command line...");
248
249         STRV_FOREACH(filename, filenames) {
250                 char fname[UNIT_NAME_MAX + 2 + 1] = "./";
251
252                 log_debug("Handling %s...", *filename);
253
254                 /* manager_load_unit does not like pure basenames, so prepend
255                  * the local directory, but only for valid names. manager_load_unit
256                  * will print the error for other ones. */
257                 if (!strchr(*filename, '/') && strlen(*filename) <= UNIT_NAME_MAX) {
258                         strncat(fname + 2, *filename, UNIT_NAME_MAX);
259                         k = manager_load_unit(m, NULL, fname, &err, &units[count]);
260                 } else
261                         k = manager_load_unit(m, NULL, *filename, &err, &units[count]);
262                 if (k < 0) {
263                         log_error("Failed to load %s: %s", *filename, strerror(-k));
264                         if (r == 0)
265                                 r = k;
266                 } else
267                         count ++;
268         }
269
270         for (i = 0; i < count; i++) {
271                 k = verify_unit(units[i], check_man);
272                 if (k < 0 && r == 0)
273                         r = k;
274         }
275
276 finish:
277         manager_free(m);
278
279         return r;
280 }