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