]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/run-generator/run-generator.c
strv: make iterator in STRV_FOREACH() declaread in the loop
[thirdparty/systemd.git] / src / run-generator / run-generator.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
35a1ff4c 2
ca78ad1d
ZJS
3#include <unistd.h>
4
35a1ff4c
LP
5#include "alloc-util.h"
6#include "escape.h"
7#include "fd-util.h"
8#include "fileio.h"
9#include "generator.h"
35a1ff4c
LP
10#include "mkdir.h"
11#include "proc-cmdline.h"
fe7a6da8 12#include "special.h"
35a1ff4c
LP
13#include "specifier.h"
14#include "strv.h"
15
7a44c7e3 16static const char *arg_dest = NULL;
35a1ff4c
LP
17static char **arg_commands = NULL;
18static char *arg_success_action = NULL;
19static char *arg_failure_action = NULL;
20
21STATIC_DESTRUCTOR_REGISTER(arg_commands, strv_freep);
22STATIC_DESTRUCTOR_REGISTER(arg_success_action, freep);
23STATIC_DESTRUCTOR_REGISTER(arg_failure_action, freep);
24
25static 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
b3f9c17a 42 return free_and_strdup_warn(&arg_success_action, value);
35a1ff4c
LP
43
44 } else if (proc_cmdline_key_streq(key, "systemd.run_failure_action")) {
45
46 if (proc_cmdline_value_missing(key, value))
47 return 0;
48
b3f9c17a 49 return free_and_strdup_warn(&arg_failure_action, value);
35a1ff4c
LP
50 }
51
52 return 0;
53}
54
55static int generate(void) {
56 _cleanup_fclose_ FILE *f = NULL;
57 const char *p;
35a1ff4c
LP
58 int r;
59
60 if (strv_isempty(arg_commands) && !arg_success_action)
61 return 0;
62
63 p = strjoina(arg_dest, "/kernel-command-line.service");
64 f = fopen(p, "wxe");
65 if (!f)
66 return log_error_errno(errno, "Failed to create unit file %s: %m", p);
67
68 fputs("# Automatically generated by systemd-run-generator\n\n"
69 "[Unit]\n"
70 "Description=Command from Kernel Command Line\n"
71 "Documentation=man:systemd-run-generator(8)\n"
72 "SourcePath=/proc/cmdline\n", f);
73
74 if (!streq_ptr(arg_success_action, "none"))
75 fprintf(f, "SuccessAction=%s\n",
76 arg_success_action ?: "exit");
77
78 if (!streq_ptr(arg_failure_action, "none"))
79 fprintf(f, "FailureAction=%s\n",
80 arg_failure_action ?: "exit");
81
82 fputs("\n"
83 "[Service]\n"
84 "Type=oneshot\n"
85 "StandardOutput=journal+console\n", f);
86
87 STRV_FOREACH(c, arg_commands) {
88 _cleanup_free_ char *a = NULL;
89
90 a = specifier_escape(*c);
91 if (!a)
92 return log_oom();
93
94 fprintf(f, "ExecStart=%s\n", a);
95 }
96
97 r = fflush_and_check(f);
98 if (r < 0)
99 return log_error_errno(r, "Failed to write unit file %s: %m", p);
100
fa027117 101 /* Let's create a target we can link "default.target" to */
35a1ff4c
LP
102 p = strjoina(arg_dest, "/kernel-command-line.target");
103 r = write_string_file(
104 p,
105 "# Automatically generated by systemd-run-generator\n\n"
106 "[Unit]\n"
107 "Description=Command from Kernel Command Line\n"
108 "Documentation=man:systemd-run-generator(8)\n"
109 "SourcePath=/proc/cmdline\n"
110 "Requires=kernel-command-line.service\n"
111 "After=kernel-command-line.service\n",
112 WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_NOFOLLOW);
113 if (r < 0)
114 return log_error_errno(r, "Failed to create unit file %s: %m", p);
115
116 /* And now redirect default.target to our new target */
fe7a6da8 117 p = strjoina(arg_dest, "/" SPECIAL_DEFAULT_TARGET);
35a1ff4c
LP
118 if (symlink("kernel-command-line.target", p) < 0)
119 return log_error_errno(errno, "Failed to link unit file kernel-command-line.target → %s: %m", p);
120
121 return 0;
122}
123
7a44c7e3 124static int run(const char *dest, const char *dest_early, const char *dest_late) {
35a1ff4c
LP
125 int r;
126
7a44c7e3 127 assert_se(arg_dest = dest);
35a1ff4c
LP
128
129 r = proc_cmdline_parse(parse, NULL, PROC_CMDLINE_RD_STRICT|PROC_CMDLINE_STRIP_RD_PREFIX);
130 if (r < 0)
131 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
132
133 return generate();
134}
135
7a44c7e3 136DEFINE_MAIN_GENERATOR_FUNCTION(run);