1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2014 Zbigniew Jędrzejewski-Szmek
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include "alloc-util.h"
24 #include "analyze-verify.h"
25 #include "bus-error.h"
30 #include "path-util.h"
32 #include "unit-name.h"
34 static int prepare_filename(const char *filename
, char **ret
) {
37 _cleanup_free_
char *abspath
= NULL
;
38 _cleanup_free_
char *dir
= NULL
;
39 _cleanup_free_
char *with_instance
= NULL
;
45 r
= path_make_absolute_cwd(filename
, &abspath
);
49 name
= basename(abspath
);
50 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
53 if (unit_name_is_valid(name
, UNIT_NAME_TEMPLATE
)) {
54 r
= unit_name_replace_instance(name
, "i", &with_instance
);
59 dir
= dirname_malloc(abspath
);
64 c
= path_join(NULL
, dir
, with_instance
);
66 c
= path_join(NULL
, dir
, name
);
74 static int generate_path(char **var
, char **filenames
) {
78 _cleanup_strv_free_
char **ans
= NULL
;
81 STRV_FOREACH(filename
, filenames
) {
84 t
= dirname_malloc(*filename
);
88 r
= strv_consume(&ans
, t
);
93 assert_se(strv_uniq(ans
));
95 /* First, prepend our directories. Second, if some path was specified, use that, and
96 * otherwise use the defaults. Any duplicates will be filtered out in path-lookup.c.
97 * Treat explicit empty path to mean that nothing should be appended.
99 old
= getenv("SYSTEMD_UNIT_PATH");
100 if (!streq_ptr(old
, "")) {
104 r
= strv_extend(&ans
, old
);
109 *var
= strv_join(ans
, ":");
116 static int verify_socket(Unit
*u
) {
121 if (u
->type
!= UNIT_SOCKET
)
124 /* Cannot run this without the service being around */
126 /* This makes sure instance is created if necessary. */
127 r
= socket_instantiate_service(SOCKET(u
));
129 log_unit_error_errno(u
, r
, "Socket cannot be started, failed to create instance: %m");
133 /* This checks both type of sockets */
134 if (UNIT_ISSET(SOCKET(u
)->service
)) {
137 service
= SERVICE(UNIT_DEREF(SOCKET(u
)->service
));
138 log_unit_debug(u
, "Using %s", UNIT(service
)->id
);
140 if (UNIT(service
)->load_state
!= UNIT_LOADED
) {
141 log_unit_error(u
, "Service %s not loaded, %s cannot be started.", UNIT(service
)->id
, u
->id
);
149 static int verify_executable(Unit
*u
, ExecCommand
*exec
) {
153 if (access(exec
->path
, X_OK
) < 0)
154 return log_unit_error_errno(u
, errno
, "Command %s is not executable: %m", exec
->path
);
159 static int verify_executables(Unit
*u
) {
166 exec
= u
->type
== UNIT_SOCKET
? SOCKET(u
)->control_command
:
167 u
->type
== UNIT_MOUNT
? MOUNT(u
)->control_command
:
168 u
->type
== UNIT_SWAP
? SWAP(u
)->control_command
: NULL
;
169 k
= verify_executable(u
, exec
);
173 if (u
->type
== UNIT_SERVICE
)
174 for (i
= 0; i
< ELEMENTSOF(SERVICE(u
)->exec_command
); i
++) {
175 k
= verify_executable(u
, SERVICE(u
)->exec_command
[i
]);
180 if (u
->type
== UNIT_SOCKET
)
181 for (i
= 0; i
< ELEMENTSOF(SOCKET(u
)->exec_command
); i
++) {
182 k
= verify_executable(u
, SOCKET(u
)->exec_command
[i
]);
190 static int verify_documentation(Unit
*u
, bool check_man
) {
194 STRV_FOREACH(p
, u
->documentation
) {
195 log_unit_debug(u
, "Found documentation item: %s", *p
);
197 if (check_man
&& startswith(*p
, "man:")) {
198 k
= show_man_page(*p
+ 4, true);
201 log_unit_error_errno(u
, r
, "Can't show %s: %m", *p
);
203 log_unit_error_errno(u
, r
, "man %s command failed with code %d", *p
+ 4, k
);
212 /* Check remote URLs? */
217 static int verify_unit(Unit
*u
, bool check_man
) {
218 _cleanup_(sd_bus_error_free
) sd_bus_error err
= SD_BUS_ERROR_NULL
;
223 if (log_get_max_level() >= LOG_DEBUG
)
224 unit_dump(u
, stdout
, "\t");
226 log_unit_debug(u
, "Creating %s/start job", u
->id
);
227 r
= manager_add_job(u
->manager
, JOB_START
, u
, JOB_REPLACE
, &err
, NULL
);
229 log_unit_error_errno(u
, r
, "Failed to create %s/start: %s", u
->id
, bus_error_message(&err
, r
));
231 k
= verify_socket(u
);
235 k
= verify_executables(u
);
239 k
= verify_documentation(u
, check_man
);
246 int verify_units(char **filenames
, UnitFileScope scope
, bool check_man
, bool run_generators
) {
247 _cleanup_(sd_bus_error_free
) sd_bus_error err
= SD_BUS_ERROR_NULL
;
248 _cleanup_free_
char *var
= NULL
;
255 Unit
*units
[strv_length(filenames
)];
257 const uint8_t flags
= MANAGER_TEST_RUN_ENV_GENERATORS
|
258 run_generators
* MANAGER_TEST_RUN_GENERATORS
;
260 if (strv_isempty(filenames
))
264 r
= generate_path(&var
, filenames
);
266 return log_error_errno(r
, "Failed to generate unit load path: %m");
268 assert_se(set_unit_path(var
) >= 0);
270 r
= manager_new(scope
, flags
, &m
);
272 return log_error_errno(r
, "Failed to initialize manager: %m");
274 log_debug("Starting manager...");
276 r
= manager_startup(m
, serial
, fdset
);
278 log_error_errno(r
, "Failed to start manager: %m");
282 manager_clear_jobs(m
);
284 log_debug("Loading remaining units from the command line...");
286 STRV_FOREACH(filename
, filenames
) {
287 _cleanup_free_
char *prepared
= NULL
;
289 log_debug("Handling %s...", *filename
);
291 k
= prepare_filename(*filename
, &prepared
);
293 log_error_errno(k
, "Failed to prepare filename %s: %m", *filename
);
299 k
= manager_load_unit(m
, NULL
, prepared
, &err
, &units
[count
]);
301 log_error_errno(k
, "Failed to load %s: %m", *filename
);
308 for (i
= 0; i
< count
; i
++) {
309 k
= verify_unit(units
[i
], check_man
);