]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/run-generator/run-generator.c
a149b9c9c298e052e81021e3747356331b1b85bb
[thirdparty/systemd.git] / src / run-generator / run-generator.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <unistd.h>
4
5 #include "alloc-util.h"
6 #include "escape.h"
7 #include "fd-util.h"
8 #include "fileio.h"
9 #include "generator.h"
10 #include "mkdir.h"
11 #include "proc-cmdline.h"
12 #include "special.h"
13 #include "specifier.h"
14 #include "strv.h"
15
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;
20
21 STATIC_DESTRUCTOR_REGISTER(arg_commands, strv_freep);
22 STATIC_DESTRUCTOR_REGISTER(arg_success_action, freep);
23 STATIC_DESTRUCTOR_REGISTER(arg_failure_action, freep);
24
25 static int parse(const char *key, const char *value, void *data) {
26 int r;
27
28 if (proc_cmdline_key_streq(key, "systemd.run")) {
29
30 if (proc_cmdline_value_missing(key, value))
31 return 0;
32
33 r = strv_extend(&arg_commands, value);
34 if (r < 0)
35 return log_oom();
36
37 } else if (proc_cmdline_key_streq(key, "systemd.run_success_action")) {
38
39 if (proc_cmdline_value_missing(key, value))
40 return 0;
41
42 if (free_and_strdup(&arg_success_action, value) < 0)
43 return log_oom();
44
45 } else if (proc_cmdline_key_streq(key, "systemd.run_failure_action")) {
46
47 if (proc_cmdline_value_missing(key, value))
48 return 0;
49
50 if (free_and_strdup(&arg_failure_action, value) < 0)
51 return log_oom();
52 }
53
54 return 0;
55 }
56
57 static int generate(void) {
58 _cleanup_fclose_ FILE *f = NULL;
59 const char *p;
60 char **c;
61 int r;
62
63 if (strv_isempty(arg_commands) && !arg_success_action)
64 return 0;
65
66 p = strjoina(arg_dest, "/kernel-command-line.service");
67 f = fopen(p, "wxe");
68 if (!f)
69 return log_error_errno(errno, "Failed to create unit file %s: %m", p);
70
71 fputs("# Automatically generated by systemd-run-generator\n\n"
72 "[Unit]\n"
73 "Description=Command from Kernel Command Line\n"
74 "Documentation=man:systemd-run-generator(8)\n"
75 "SourcePath=/proc/cmdline\n", f);
76
77 if (!streq_ptr(arg_success_action, "none"))
78 fprintf(f, "SuccessAction=%s\n",
79 arg_success_action ?: "exit");
80
81 if (!streq_ptr(arg_failure_action, "none"))
82 fprintf(f, "FailureAction=%s\n",
83 arg_failure_action ?: "exit");
84
85 fputs("\n"
86 "[Service]\n"
87 "Type=oneshot\n"
88 "StandardOutput=journal+console\n", f);
89
90 STRV_FOREACH(c, arg_commands) {
91 _cleanup_free_ char *a = NULL;
92
93 a = specifier_escape(*c);
94 if (!a)
95 return log_oom();
96
97 fprintf(f, "ExecStart=%s\n", a);
98 }
99
100 r = fflush_and_check(f);
101 if (r < 0)
102 return log_error_errno(r, "Failed to write unit file %s: %m", p);
103
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(
107 p,
108 "# Automatically generated by systemd-run-generator\n\n"
109 "[Unit]\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);
116 if (r < 0)
117 return log_error_errno(r, "Failed to create unit file %s: %m", p);
118
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);
123
124 return 0;
125 }
126
127 static int run(const char *dest, const char *dest_early, const char *dest_late) {
128 int r;
129
130 assert_se(arg_dest = dest);
131
132 r = proc_cmdline_parse(parse, NULL, PROC_CMDLINE_RD_STRICT|PROC_CMDLINE_STRIP_RD_PREFIX);
133 if (r < 0)
134 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
135
136 return generate();
137 }
138
139 DEFINE_MAIN_GENERATOR_FUNCTION(run);