1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include "alloc-util.h"
10 #include "proc-cmdline.h"
11 #include "specifier.h"
14 static const char *arg_dest
= "/tmp";
15 static char **arg_commands
= NULL
;
16 static char *arg_success_action
= NULL
;
17 static char *arg_failure_action
= NULL
;
19 STATIC_DESTRUCTOR_REGISTER(arg_commands
, strv_freep
);
20 STATIC_DESTRUCTOR_REGISTER(arg_success_action
, freep
);
21 STATIC_DESTRUCTOR_REGISTER(arg_failure_action
, freep
);
23 static int parse(const char *key
, const char *value
, void *data
) {
26 if (proc_cmdline_key_streq(key
, "systemd.run")) {
28 if (proc_cmdline_value_missing(key
, value
))
31 r
= strv_extend(&arg_commands
, value
);
35 } else if (proc_cmdline_key_streq(key
, "systemd.run_success_action")) {
37 if (proc_cmdline_value_missing(key
, value
))
40 if (free_and_strdup(&arg_success_action
, value
) < 0)
43 } else if (proc_cmdline_key_streq(key
, "systemd.run_failure_action")) {
45 if (proc_cmdline_value_missing(key
, value
))
48 if (free_and_strdup(&arg_failure_action
, value
) < 0)
55 static int generate(void) {
56 _cleanup_fclose_
FILE *f
= NULL
;
61 if (strv_isempty(arg_commands
) && !arg_success_action
)
64 p
= strjoina(arg_dest
, "/kernel-command-line.service");
67 return log_error_errno(errno
, "Failed to create unit file %s: %m", p
);
69 fputs("# Automatically generated by systemd-run-generator\n\n"
71 "Description=Command from Kernel Command Line\n"
72 "Documentation=man:systemd-run-generator(8)\n"
73 "SourcePath=/proc/cmdline\n", f
);
75 if (!streq_ptr(arg_success_action
, "none"))
76 fprintf(f
, "SuccessAction=%s\n",
77 arg_success_action
?: "exit");
79 if (!streq_ptr(arg_failure_action
, "none"))
80 fprintf(f
, "FailureAction=%s\n",
81 arg_failure_action
?: "exit");
86 "StandardOutput=journal+console\n", f
);
88 STRV_FOREACH(c
, arg_commands
) {
89 _cleanup_free_
char *a
= NULL
;
91 a
= specifier_escape(*c
);
95 fprintf(f
, "ExecStart=%s\n", a
);
98 r
= fflush_and_check(f
);
100 return log_error_errno(r
, "Failed to write unit file %s: %m", p
);
102 /* Let's create a a target we can link "default.target" to */
103 p
= strjoina(arg_dest
, "/kernel-command-line.target");
104 r
= write_string_file(
106 "# Automatically generated by systemd-run-generator\n\n"
108 "Description=Command from Kernel Command Line\n"
109 "Documentation=man:systemd-run-generator(8)\n"
110 "SourcePath=/proc/cmdline\n"
111 "Requires=kernel-command-line.service\n"
112 "After=kernel-command-line.service\n",
113 WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_NOFOLLOW
);
115 return log_error_errno(r
, "Failed to create unit file %s: %m", p
);
117 /* And now redirect default.target to our new target */
118 p
= strjoina(arg_dest
, "/default.target");
119 if (symlink("kernel-command-line.target", p
) < 0)
120 return log_error_errno(errno
, "Failed to link unit file kernel-command-line.target → %s: %m", p
);
125 static int run(int argc
, char *argv
[]) {
128 log_setup_generator();
130 if (argc
> 1 && argc
!= 4) {
131 log_error("This program takes three or no arguments.");
140 r
= proc_cmdline_parse(parse
, NULL
, PROC_CMDLINE_RD_STRICT
|PROC_CMDLINE_STRIP_RD_PREFIX
);
142 log_warning_errno(r
, "Failed to parse kernel command line, ignoring: %m");
147 DEFINE_MAIN_FUNCTION(run
);