1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Zbigniew Jędrzejewski-Szmek
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.
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.
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/>.
32 SystemdRunningAs arg_running_as = SYSTEMD_SYSTEM;
33 bool arg_no_man = false;
35 static int generate_path(char **var, char **filenames) {
38 _cleanup_strv_free_ char **ans = NULL;
41 STRV_FOREACH(filename, filenames) {
44 t = dirname_malloc(*filename);
48 r = strv_consume(&ans, t);
53 assert_se(strv_uniq(ans));
55 r = strv_extend(&ans, "");
59 *var = strv_join(ans, ":");
66 static int verify_socket(Unit *u) {
71 if (u->type != UNIT_SOCKET)
74 /* Cannot run this without the service being around */
76 /* This makes sure instance is created if necessary. */
77 r = socket_instantiate_service(SOCKET(u));
79 log_error_unit(u->id, "Socket %s cannot be started, failed to create instance.",
84 /* This checks both type of sockets */
85 if (UNIT_ISSET(SOCKET(u)->service)) {
88 service = SERVICE(UNIT_DEREF(SOCKET(u)->service));
89 log_debug_unit(u->id, "%s uses %s", u->id, UNIT(service)->id);
91 if (UNIT(service)->load_state != UNIT_LOADED) {
92 log_error_unit(u->id, "Service %s not loaded, %s cannot be started.",
93 UNIT(service)->id, u->id);
101 static int verify_executable(Unit *u, ExecCommand *exec) {
105 if (access(exec->path, X_OK) < 0) {
106 log_error_unit(u->id, "%s: command %s is not executable: %m",
114 static int verify_executables(Unit *u) {
121 exec = u->type == UNIT_SOCKET ? SOCKET(u)->control_command :
122 u->type == UNIT_MOUNT ? MOUNT(u)->control_command :
123 u->type == UNIT_SWAP ? SWAP(u)->control_command : NULL;
124 k = verify_executable(u, exec);
128 if (u->type == UNIT_SERVICE)
129 for (i = 0; i < ELEMENTSOF(SERVICE(u)->exec_command); i++) {
130 k = verify_executable(u, SERVICE(u)->exec_command[i]);
135 if (u->type == UNIT_SOCKET)
136 for (i = 0; i < ELEMENTSOF(SOCKET(u)->exec_command); i++) {
137 k = verify_executable(u, SOCKET(u)->exec_command[i]);
145 static int verify_documentation(Unit *u) {
152 STRV_FOREACH(p, u->documentation) {
153 log_debug_unit(u->id, "%s: found documentation item %s.", u->id, *p);
154 if (startswith(*p, "man:")) {
155 k = show_man_page(*p + 4, true);
158 log_error_unit(u->id, "%s: can't show %s: %s",
159 u->id, *p, strerror(-r));
161 log_error_unit(u->id, "%s: man %s command failed with code %d",
171 /* Check remote URLs? */
176 static int test_unit(Unit *u) {
177 _cleanup_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL;
183 if (log_get_max_level() >= LOG_DEBUG)
184 unit_dump(u, stdout, "\t");
186 log_debug_unit(u->id, "Creating %s/start job", u->id);
187 r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, false, &err, &j);
188 if (sd_bus_error_is_set(&err))
189 log_error_unit(u->id, "Error: %s: %s",
190 err.name, err.message);
192 log_error_unit(u->id, "Failed to create %s/start: %s",
193 u->id, strerror(-r));
195 k = verify_socket(u);
199 k = verify_executables(u);
203 k = verify_documentation(u);
210 static int test_units(char **filenames) {
211 _cleanup_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL;
216 _cleanup_free_ char *var;
221 Unit *units[strv_length(filenames)];
225 r = generate_path(&var, filenames);
227 log_error("Failed to generate unit load path: %s", strerror(-r));
231 assert_se(set_unit_path(var) >= 0);
233 r = manager_new(arg_running_as, true, &m);
235 log_error("Failed to initalize manager: %s", strerror(-r));
239 log_debug("Starting manager...");
241 r = manager_startup(m, serial, fdset);
243 log_error("Failed to start manager: %s", strerror(-r));
247 manager_clear_jobs(m);
249 log_debug("Loading remaining units from the command line...");
251 STRV_FOREACH(filename, filenames) {
252 log_debug("Handling %s...", *filename);
254 k = manager_load_unit(m, NULL, *filename, &err, &units[count]);
256 log_error("Failed to load %s: %s", *filename, strerror(-r));
264 for (i = 0; i < count; i++) {
265 k = test_unit(units[i]);
276 static void help(void) {
277 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
278 "Check if unit files can be correctly loaded.\n\n"
279 " -h --help Show this help\n"
280 " --version Show package version\n"
281 " --system Test system units\n"
282 " --user Test user units\n"
283 " --no-man Do not check for existence of man pages\n"
284 , program_invocation_short_name);
287 static int parse_argv(int argc, char *argv[]) {
295 static const struct option options[] = {
296 { "help", no_argument, NULL, 'h' },
297 { "version", no_argument, NULL, ARG_VERSION },
298 { "user", no_argument, NULL, ARG_USER },
299 { "system", no_argument, NULL, ARG_SYSTEM },
310 while ((c = getopt_long(argc, argv, ":h", options, NULL)) >= 0)
318 puts(PACKAGE_STRING);
319 puts(SYSTEMD_FEATURES);
323 arg_running_as = SYSTEMD_USER;
327 arg_running_as = SYSTEMD_SYSTEM;
335 log_error("Unknown option %s.", argv[optind-1]);
339 log_error("Missing argument to %s.", argv[optind-1]);
343 assert_not_reached("Unhandled option code.");
346 return 1; /* work to do */
349 int main(int argc, char *argv[]) {
352 log_parse_environment();
355 r = parse_argv(argc, argv);
359 r = test_units(argv + optind);
362 return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;