chiark / gitweb /
bfc71e3f38ce5ed24699924c5985df4c49e73561
[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
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(u->id, "Socket %s cannot be started, failed to create instance.",
76                                u->id);
77                 return r;
78         }
79
80         /* This checks both type of sockets */
81         if (UNIT_ISSET(SOCKET(u)->service)) {
82                 Service *service;
83
84                 service = SERVICE(UNIT_DEREF(SOCKET(u)->service));
85                 log_unit_debug(u->id, "%s uses %s", u->id, UNIT(service)->id);
86
87                 if (UNIT(service)->load_state != UNIT_LOADED) {
88                         log_unit_error(u->id, "Service %s not loaded, %s cannot be started.",
89                                        UNIT(service)->id, u->id);
90                         return -ENOENT;
91                 }
92         }
93
94         return 0;
95 }
96
97 static int verify_executable(Unit *u, ExecCommand *exec) {
98         if (exec == NULL)
99                 return 0;
100
101         if (access(exec->path, X_OK) < 0) {
102                 log_unit_error(u->id, "%s: command %s is not executable: %m",
103                                u->id, exec->path);
104                 return -errno;
105         }
106
107         return 0;
108 }
109
110 static int verify_executables(Unit *u) {
111         ExecCommand *exec;
112         int r = 0, k;
113         unsigned i;
114
115         assert(u);
116
117         exec =  u->type == UNIT_SOCKET ? SOCKET(u)->control_command :
118                 u->type == UNIT_MOUNT ? MOUNT(u)->control_command :
119                 u->type == UNIT_SWAP ? SWAP(u)->control_command : NULL;
120         k = verify_executable(u, exec);
121         if (k < 0 && r == 0)
122                 r = k;
123
124         if (u->type == UNIT_SERVICE)
125                 for (i = 0; i < ELEMENTSOF(SERVICE(u)->exec_command); i++) {
126                         k = verify_executable(u, SERVICE(u)->exec_command[i]);
127                         if (k < 0 && r == 0)
128                                 r = k;
129                 }
130
131         if (u->type == UNIT_SOCKET)
132                 for (i = 0; i < ELEMENTSOF(SOCKET(u)->exec_command); i++) {
133                         k = verify_executable(u, SOCKET(u)->exec_command[i]);
134                         if (k < 0 && r == 0)
135                                 r = k;
136                 }
137
138         return r;
139 }
140
141 static int verify_documentation(Unit *u, bool check_man) {
142         char **p;
143         int r = 0, k;
144
145         STRV_FOREACH(p, u->documentation) {
146                 log_unit_debug(u->id, "%s: found documentation item %s.", u->id, *p);
147                 if (check_man && startswith(*p, "man:")) {
148                         k = show_man_page(*p + 4, true);
149                         if (k != 0) {
150                                 if (k < 0)
151                                         log_unit_error(u->id, "%s: can't show %s: %s",
152                                                        u->id, *p, strerror(-r));
153                                 else {
154                                         log_unit_error(u->id, "%s: man %s command failed with code %d",
155                                                        u->id, *p + 4, k);
156                                         k = -ENOEXEC;
157                                 }
158                                 if (r == 0)
159                                         r = k;
160                         }
161                 }
162         }
163
164         /* Check remote URLs? */
165
166         return r;
167 }
168
169 static int verify_unit(Unit *u, bool check_man) {
170         _cleanup_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL;
171         Job *j;
172         int r, k;
173
174         assert(u);
175
176         if (log_get_max_level() >= LOG_DEBUG)
177                 unit_dump(u, stdout, "\t");
178
179         log_unit_debug(u->id, "Creating %s/start job", u->id);
180         r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, false, &err, &j);
181         if (sd_bus_error_is_set(&err))
182                 log_unit_error(u->id, "Error: %s: %s",
183                                err.name, err.message);
184         if (r < 0)
185                 log_unit_error(u->id, "Failed to create %s/start: %s",
186                                u->id, strerror(-r));
187
188         k = verify_socket(u);
189         if (k < 0 && r == 0)
190                 r = k;
191
192         k = verify_executables(u);
193         if (k < 0 && r == 0)
194                 r = k;
195
196         k = verify_documentation(u, check_man);
197         if (k < 0 && r == 0)
198                 r = k;
199
200         return r;
201 }
202
203 int verify_units(char **filenames, SystemdRunningAs running_as, bool check_man) {
204         _cleanup_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL;
205         Manager *m = NULL;
206         FILE *serial = NULL;
207         FDSet *fdset = NULL;
208
209         _cleanup_free_ char *var = NULL;
210
211         char **filename;
212         int r = 0, k;
213
214         Unit *units[strv_length(filenames)];
215         int i, count = 0;
216
217         if (strv_isempty(filenames))
218                 return 0;
219
220         /* set the path */
221         r = generate_path(&var, filenames);
222         if (r < 0)
223                 return log_error_errno(r, "Failed to generate unit load path: %m");
224
225         assert_se(set_unit_path(var) >= 0);
226
227         r = manager_new(running_as, true, &m);
228         if (r < 0)
229                 return log_error_errno(r, "Failed to initalize manager: %m");
230
231         log_debug("Starting manager...");
232
233         r = manager_startup(m, serial, fdset);
234         if (r < 0) {
235                 log_error_errno(r, "Failed to start manager: %m");
236                 goto finish;
237         }
238
239         manager_clear_jobs(m);
240
241         log_debug("Loading remaining units from the command line...");
242
243         STRV_FOREACH(filename, filenames) {
244                 char fname[UNIT_NAME_MAX + 2 + 1] = "./";
245
246                 log_debug("Handling %s...", *filename);
247
248                 /* manager_load_unit does not like pure basenames, so prepend
249                  * the local directory, but only for valid names. manager_load_unit
250                  * will print the error for other ones. */
251                 if (!strchr(*filename, '/') && strlen(*filename) <= UNIT_NAME_MAX) {
252                         strncat(fname + 2, *filename, UNIT_NAME_MAX);
253                         k = manager_load_unit(m, NULL, fname, &err, &units[count]);
254                 } else
255                         k = manager_load_unit(m, NULL, *filename, &err, &units[count]);
256                 if (k < 0) {
257                         log_error_errno(k, "Failed to load %s: %m", *filename);
258                         if (r == 0)
259                                 r = k;
260                 } else
261                         count ++;
262         }
263
264         for (i = 0; i < count; i++) {
265                 k = verify_unit(units[i], check_man);
266                 if (k < 0 && r == 0)
267                         r = k;
268         }
269
270 finish:
271         manager_free(m);
272
273         return r;
274 }