<title><command>systemd-analyze verify <replaceable>FILE</replaceable>...</command></title>
<para>This command will load unit files and print warnings if any errors are detected. Files specified
- on the command line will be loaded, but also any other units referenced by them. The full unit search
+ on the command line will be loaded, but also any other units referenced by them. A unit's name on disk
+ can be overridden by specifying an alias after a colon; see below for an example. The full unit search
path is formed by combining the directories for all command line arguments, and the usual unit load
paths. The variable <varname>$SYSTEMD_UNIT_PATH</varname> is supported, and may be used to replace or
augment the compiled in set of unit load paths; see
Service b@0.service not loaded, b.socket cannot be started.
</programlisting>
</example>
+
+ <example>
+ <title>Aliasing a unit</title>
+
+ <programlisting>$ cat /tmp/source
+[Unit]
+Description=Hostname printer
+
+[Service]
+Type=simple
+ExecStart=/usr/bin/echo %H
+MysteryKey=true
+
+$ systemd-analyze verify /tmp/source
+Failed to prepare filename /tmp/source: Invalid argument
+
+$ systemd-analyze verify /tmp/source:alias.service
+/tmp/systemd-analyze-XXXXXX/alias.service:7: Unknown key name 'MysteryKey' in section 'Service', ignoring.
+ </programlisting>
+ </example>
+
</refsect2>
<refsect2>
#include "copy.h"
#include "def.h"
#include "exit-status.h"
+#include "extract-word.h"
#include "fd-util.h"
#include "fileio.h"
#include "filesystems.h"
#include "parse-util.h"
#include "path-util.h"
#include "pretty-print.h"
+#include "rm-rf.h"
#if HAVE_SECCOMP
# include "seccomp-util.h"
#endif
#include "strxcpyx.h"
#include "terminal-util.h"
#include "time-util.h"
+#include "tmpfile-util.h"
#include "unit-name.h"
#include "util.h"
#include "verb-log-control.h"
return CMP(a->activating, b->activating);
}
+static int process_aliases(char *argv[], char *tempdir, char ***ret) {
+ _cleanup_strv_free_ char **filenames = NULL;
+ char **filename;
+ int r;
+
+ assert(argv);
+ assert(tempdir);
+ assert(ret);
+
+ STRV_FOREACH(filename, strv_skip(argv, 1)) {
+ _cleanup_free_ char *src = NULL, *dst = NULL, *arg = NULL;
+ char *parse_arg;
+
+ arg = strdup(*filename);
+ if (!arg)
+ return -ENOMEM;
+
+ parse_arg = arg;
+ r = extract_first_word((const char **) &parse_arg, &src, ":", 0);
+ if (r < 0)
+ return r;
+
+ if (!parse_arg) {
+ r = strv_extend(&filenames, src);
+ if (r < 0)
+ return -ENOMEM;
+
+ continue;
+ }
+
+ dst = path_join(tempdir, basename(parse_arg));
+ if (!dst)
+ return -ENOMEM;
+
+ r = copy_file(src, dst, 0, 0644, 0, 0, COPY_REFLINK);
+ if (r < 0)
+ return r;
+
+ r = strv_consume(&filenames, TAKE_PTR(dst));
+ if (r < 0)
+ return -ENOMEM;
+ }
+
+ *ret = TAKE_PTR(filenames);
+ return 0;
+}
+
static UnitTimes* unit_times_free_array(UnitTimes *t) {
for (UnitTimes *p = t; p && p->has_data; p++)
free(p->name);
}
static int do_verify(int argc, char *argv[], void *userdata) {
- return verify_units(strv_skip(argv, 1), arg_scope, arg_man, arg_generators, arg_recursive_errors, arg_root);
+ _cleanup_strv_free_ char **filenames = NULL;
+ _cleanup_(rm_rf_physical_and_freep) char *tempdir = NULL;
+ int r;
+
+ r = mkdtemp_malloc("/tmp/systemd-analyze-XXXXXX", &tempdir);
+ if (r < 0)
+ return log_error_errno(r, "Failed to setup working directory: %m");
+
+ r = process_aliases(argv, tempdir, &filenames);
+ if (r < 0)
+ return log_error_errno(r, "Couldn't process aliases: %m");
+
+ return verify_units(filenames, arg_scope, arg_man, arg_generators, arg_recursive_errors, arg_root);
}
static int do_security(int argc, char *argv[], void *userdata) {