]>
Commit | Line | Data |
---|---|---|
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 | |
34 | static 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 | ||
65 | static 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 | ||
98 | static 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 | ||
108 | static 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 | 139 | static 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 | 166 | static 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 | 195 | int 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 | ||
262 | finish: | |
263 | manager_free(m); | |
264 | ||
265 | return r; | |
266 | } |