Branch data Line data Source code
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 "specifier.h"
13 : : #include "strv.h"
14 : :
15 : : static const char *arg_dest = NULL;
16 : : static char **arg_commands = NULL;
17 : : static char *arg_success_action = NULL;
18 : : static char *arg_failure_action = NULL;
19 : :
20 : 0 : STATIC_DESTRUCTOR_REGISTER(arg_commands, strv_freep);
21 : 0 : STATIC_DESTRUCTOR_REGISTER(arg_success_action, freep);
22 : 0 : STATIC_DESTRUCTOR_REGISTER(arg_failure_action, freep);
23 : :
24 : 0 : static int parse(const char *key, const char *value, void *data) {
25 : : int r;
26 : :
27 [ # # ]: 0 : if (proc_cmdline_key_streq(key, "systemd.run")) {
28 : :
29 [ # # ]: 0 : if (proc_cmdline_value_missing(key, value))
30 : 0 : return 0;
31 : :
32 : 0 : r = strv_extend(&arg_commands, value);
33 [ # # ]: 0 : if (r < 0)
34 : 0 : return log_oom();
35 : :
36 [ # # ]: 0 : } else if (proc_cmdline_key_streq(key, "systemd.run_success_action")) {
37 : :
38 [ # # ]: 0 : if (proc_cmdline_value_missing(key, value))
39 : 0 : return 0;
40 : :
41 [ # # ]: 0 : if (free_and_strdup(&arg_success_action, value) < 0)
42 : 0 : return log_oom();
43 : :
44 [ # # ]: 0 : } else if (proc_cmdline_key_streq(key, "systemd.run_failure_action")) {
45 : :
46 [ # # ]: 0 : if (proc_cmdline_value_missing(key, value))
47 : 0 : return 0;
48 : :
49 [ # # ]: 0 : if (free_and_strdup(&arg_failure_action, value) < 0)
50 : 0 : return log_oom();
51 : : }
52 : :
53 : 0 : return 0;
54 : : }
55 : :
56 : 0 : static int generate(void) {
57 : 0 : _cleanup_fclose_ FILE *f = NULL;
58 : : const char *p;
59 : : char **c;
60 : : int r;
61 : :
62 [ # # # # ]: 0 : if (strv_isempty(arg_commands) && !arg_success_action)
63 : 0 : return 0;
64 : :
65 [ # # # # : 0 : p = strjoina(arg_dest, "/kernel-command-line.service");
# # # # #
# # # ]
66 : 0 : f = fopen(p, "wxe");
67 [ # # ]: 0 : if (!f)
68 [ # # ]: 0 : return log_error_errno(errno, "Failed to create unit file %s: %m", p);
69 : :
70 : 0 : fputs("# Automatically generated by systemd-run-generator\n\n"
71 : : "[Unit]\n"
72 : : "Description=Command from Kernel Command Line\n"
73 : : "Documentation=man:systemd-run-generator(8)\n"
74 : : "SourcePath=/proc/cmdline\n", f);
75 : :
76 [ # # ]: 0 : if (!streq_ptr(arg_success_action, "none"))
77 : 0 : fprintf(f, "SuccessAction=%s\n",
78 [ # # ]: 0 : arg_success_action ?: "exit");
79 : :
80 [ # # ]: 0 : if (!streq_ptr(arg_failure_action, "none"))
81 : 0 : fprintf(f, "FailureAction=%s\n",
82 [ # # ]: 0 : arg_failure_action ?: "exit");
83 : :
84 : 0 : fputs("\n"
85 : : "[Service]\n"
86 : : "Type=oneshot\n"
87 : : "StandardOutput=journal+console\n", f);
88 : :
89 [ # # # # ]: 0 : STRV_FOREACH(c, arg_commands) {
90 [ # # ]: 0 : _cleanup_free_ char *a = NULL;
91 : :
92 : 0 : a = specifier_escape(*c);
93 [ # # ]: 0 : if (!a)
94 : 0 : return log_oom();
95 : :
96 : 0 : fprintf(f, "ExecStart=%s\n", a);
97 : : }
98 : :
99 : 0 : r = fflush_and_check(f);
100 [ # # ]: 0 : if (r < 0)
101 [ # # ]: 0 : return log_error_errno(r, "Failed to write unit file %s: %m", p);
102 : :
103 : : /* Let's create a a target we can link "default.target" to */
104 [ # # # # : 0 : p = strjoina(arg_dest, "/kernel-command-line.target");
# # # # #
# # # ]
105 : 0 : r = write_string_file(
106 : : p,
107 : : "# Automatically generated by systemd-run-generator\n\n"
108 : : "[Unit]\n"
109 : : "Description=Command from Kernel Command Line\n"
110 : : "Documentation=man:systemd-run-generator(8)\n"
111 : : "SourcePath=/proc/cmdline\n"
112 : : "Requires=kernel-command-line.service\n"
113 : : "After=kernel-command-line.service\n",
114 : : WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_NOFOLLOW);
115 [ # # ]: 0 : if (r < 0)
116 [ # # ]: 0 : return log_error_errno(r, "Failed to create unit file %s: %m", p);
117 : :
118 : : /* And now redirect default.target to our new target */
119 [ # # # # : 0 : p = strjoina(arg_dest, "/default.target");
# # # # #
# # # ]
120 [ # # ]: 0 : if (symlink("kernel-command-line.target", p) < 0)
121 [ # # ]: 0 : return log_error_errno(errno, "Failed to link unit file kernel-command-line.target → %s: %m", p);
122 : :
123 : 0 : return 0;
124 : : }
125 : :
126 : 0 : static int run(const char *dest, const char *dest_early, const char *dest_late) {
127 : : int r;
128 : :
129 [ # # ]: 0 : assert_se(arg_dest = dest);
130 : :
131 : 0 : r = proc_cmdline_parse(parse, NULL, PROC_CMDLINE_RD_STRICT|PROC_CMDLINE_STRIP_RD_PREFIX);
132 [ # # ]: 0 : if (r < 0)
133 [ # # ]: 0 : log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
134 : :
135 : 0 : return generate();
136 : : }
137 : :
138 [ # # # # : 0 : DEFINE_MAIN_GENERATOR_FUNCTION(run);
# # # # #
# # # ]
|