1 /* SPDX-License-Identifier: LGPL-2.1+ */
5 #include "alloc-util.h"
11 #include "proc-cmdline.h"
13 #include "specifier.h"
16 static const char *arg_dest
= NULL
;
17 static char **arg_commands
= NULL
;
18 static char *arg_success_action
= NULL
;
19 static char *arg_failure_action
= NULL
;
21 STATIC_DESTRUCTOR_REGISTER(arg_commands
, strv_freep
);
22 STATIC_DESTRUCTOR_REGISTER(arg_success_action
, freep
);
23 STATIC_DESTRUCTOR_REGISTER(arg_failure_action
, freep
);
25 static int parse(const char *key
, const char *value
, void *data
) {
28 if (proc_cmdline_key_streq(key
, "systemd.run")) {
30 if (proc_cmdline_value_missing(key
, value
))
33 r
= strv_extend(&arg_commands
, value
);
37 } else if (proc_cmdline_key_streq(key
, "systemd.run_success_action")) {
39 if (proc_cmdline_value_missing(key
, value
))
42 if (free_and_strdup(&arg_success_action
, value
) < 0)
45 } else if (proc_cmdline_key_streq(key
, "systemd.run_failure_action")) {
47 if (proc_cmdline_value_missing(key
, value
))
50 if (free_and_strdup(&arg_failure_action
, value
) < 0)
57 static int generate(void) {
58 _cleanup_fclose_
FILE *f
= NULL
;
63 if (strv_isempty(arg_commands
) && !arg_success_action
)
66 p
= strjoina(arg_dest
, "/kernel-command-line.service");
69 return log_error_errno(errno
, "Failed to create unit file %s: %m", p
);
71 fputs("# Automatically generated by systemd-run-generator\n\n"
73 "Description=Command from Kernel Command Line\n"
74 "Documentation=man:systemd-run-generator(8)\n"
75 "SourcePath=/proc/cmdline\n", f
);
77 if (!streq_ptr(arg_success_action
, "none"))
78 fprintf(f
, "SuccessAction=%s\n",
79 arg_success_action
?: "exit");
81 if (!streq_ptr(arg_failure_action
, "none"))
82 fprintf(f
, "FailureAction=%s\n",
83 arg_failure_action
?: "exit");
88 "StandardOutput=journal+console\n", f
);
90 STRV_FOREACH(c
, arg_commands
) {
91 _cleanup_free_
char *a
= NULL
;
93 a
= specifier_escape(*c
);
97 fprintf(f
, "ExecStart=%s\n", a
);
100 r
= fflush_and_check(f
);
102 return log_error_errno(r
, "Failed to write unit file %s: %m", p
);
104 /* Let's create a a target we can link "default.target" to */
105 p
= strjoina(arg_dest
, "/kernel-command-line.target");
106 r
= write_string_file(
108 "# Automatically generated by systemd-run-generator\n\n"
110 "Description=Command from Kernel Command Line\n"
111 "Documentation=man:systemd-run-generator(8)\n"
112 "SourcePath=/proc/cmdline\n"
113 "Requires=kernel-command-line.service\n"
114 "After=kernel-command-line.service\n",
115 WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_NOFOLLOW
);
117 return log_error_errno(r
, "Failed to create unit file %s: %m", p
);
119 /* And now redirect default.target to our new target */
120 p
= strjoina(arg_dest
, "/" SPECIAL_DEFAULT_TARGET
);
121 if (symlink("kernel-command-line.target", p
) < 0)
122 return log_error_errno(errno
, "Failed to link unit file kernel-command-line.target → %s: %m", p
);
127 static int run(const char *dest
, const char *dest_early
, const char *dest_late
) {
130 assert_se(arg_dest
= dest
);
132 r
= proc_cmdline_parse(parse
, NULL
, PROC_CMDLINE_RD_STRICT
|PROC_CMDLINE_STRIP_RD_PREFIX
);
134 log_warning_errno(r
, "Failed to parse kernel command line, ignoring: %m");
139 DEFINE_MAIN_GENERATOR_FUNCTION(run
);