]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/debug-generator/debug-generator.c
Merge pull request #31648 from neighbourhoodie/review-content
[thirdparty/systemd.git] / src / debug-generator / debug-generator.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
326bb68c 2
ca78ad1d
ZJS
3#include <unistd.h>
4
b5efdb8a 5#include "alloc-util.h"
8595f578 6#include "creds-util.h"
93912e87 7#include "dropin.h"
8595f578
DDM
8#include "errno-util.h"
9#include "fd-util.h"
10#include "fileio-label.h"
afe44c8f 11#include "generator.h"
baa6a42d 12#include "initrd-util.h"
6bedfcbb 13#include "parse-util.h"
657ee2d8 14#include "path-util.h"
4e731273 15#include "proc-cmdline.h"
8595f578 16#include "recurse-dir.h"
7dcc5671 17#include "special.h"
4e731273
LP
18#include "string-util.h"
19#include "strv.h"
da33cba0 20#include "unit-file.h"
4e731273 21#include "unit-name.h"
326bb68c 22
7a44c7e3 23static const char *arg_dest = NULL;
7dcc5671 24static char *arg_default_unit = NULL;
326bb68c 25static char **arg_mask = NULL;
3c5a87a8 26static char **arg_wants = NULL;
7bf52f5d
DDM
27static bool arg_debug_shell = false;
28static char *arg_debug_tty = NULL;
29static char *arg_default_debug_tty = NULL;
326bb68c 30
4197fde5
LP
31STATIC_DESTRUCTOR_REGISTER(arg_default_unit, freep);
32STATIC_DESTRUCTOR_REGISTER(arg_mask, strv_freep);
33STATIC_DESTRUCTOR_REGISTER(arg_wants, strv_freep);
7bf52f5d
DDM
34STATIC_DESTRUCTOR_REGISTER(arg_debug_tty, freep);
35STATIC_DESTRUCTOR_REGISTER(arg_default_debug_tty, freep);
4197fde5 36
96287a49 37static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
326bb68c
LP
38 int r;
39
3c5a87a8
LP
40 assert(key);
41
326bb68c 42 if (streq(key, "systemd.mask")) {
1d84ad94 43 char *n;
326bb68c 44
1d84ad94
LP
45 if (proc_cmdline_value_missing(key, value))
46 return 0;
326bb68c 47
37cbc1d5 48 r = unit_name_mangle(value, UNIT_NAME_MANGLE_WARN, &n);
1d84ad94
LP
49 if (r < 0)
50 return log_error_errno(r, "Failed to glob unit name: %m");
326bb68c 51
1d84ad94
LP
52 r = strv_consume(&arg_mask, n);
53 if (r < 0)
54 return log_oom();
3c5a87a8
LP
55
56 } else if (streq(key, "systemd.wants")) {
1d84ad94 57 char *n;
3c5a87a8 58
1d84ad94
LP
59 if (proc_cmdline_value_missing(key, value))
60 return 0;
3c5a87a8 61
37cbc1d5 62 r = unit_name_mangle(value, UNIT_NAME_MANGLE_WARN, &n);
1d84ad94
LP
63 if (r < 0)
64 return log_error_errno(r, "Failed to glob unit name: %m");
3c5a87a8 65
1d84ad94
LP
66 r = strv_consume(&arg_wants, n);
67 if (r < 0)
68 return log_oom();
3c5a87a8 69
1d84ad94 70 } else if (proc_cmdline_key_streq(key, "systemd.debug_shell")) {
93912e87 71 r = value ? parse_boolean(value) : 1;
7bf52f5d
DDM
72 arg_debug_shell = r != 0;
73 if (r >= 0)
74 return 0;
75
76 return free_and_strdup_warn(&arg_debug_tty, skip_dev_prefix(value));
77
78 } else if (proc_cmdline_key_streq(key, "systemd.default_debug_tty")) {
79 if (proc_cmdline_value_missing(key, value))
80 return 0;
93912e87 81
7bf52f5d 82 return free_and_strdup_warn(&arg_default_debug_tty, skip_dev_prefix(value));
1d84ad94 83
7dcc5671
EV
84 } else if (streq(key, "systemd.unit")) {
85
1d84ad94
LP
86 if (proc_cmdline_value_missing(key, value))
87 return 0;
88
b3f9c17a 89 return free_and_strdup_warn(&arg_default_unit, value);
1d84ad94 90
7dcc5671
EV
91 } else if (!value) {
92 const char *target;
93
94 target = runlevel_to_target(key);
b3f9c17a
YW
95 if (target)
96 return free_and_strdup_warn(&arg_default_unit, target);
326bb68c
LP
97 }
98
99 return 0;
100}
101
102static int generate_mask_symlinks(void) {
326bb68c
LP
103 int r = 0;
104
326bb68c 105 STRV_FOREACH(u, arg_mask) {
3c5a87a8 106 _cleanup_free_ char *p = NULL;
326bb68c 107
657ee2d8 108 p = path_join(empty_to_root(arg_dest), *u);
326bb68c
LP
109 if (!p)
110 return log_oom();
111
1f6b4113 112 if (symlink("/dev/null", p) < 0)
94c156cd
LP
113 r = log_error_errno(errno,
114 "Failed to create mask symlink %s: %m",
115 p);
326bb68c
LP
116 }
117
118 return r;
119}
120
3c5a87a8 121static int generate_wants_symlinks(void) {
3c5a87a8 122 int r = 0;
326bb68c 123
3c5a87a8 124 STRV_FOREACH(u, arg_wants) {
bd6c95c0 125 _cleanup_free_ char *f = NULL;
23e5e79a
ZJS
126 const char *target;
127
128 /* This should match what do_queue_default_job() in core/main.c does. */
129 if (arg_default_unit)
130 target = arg_default_unit;
131 else if (in_initrd())
132 target = SPECIAL_INITRD_TARGET;
133 else
134 target = SPECIAL_DEFAULT_TARGET;
3c5a87a8 135
835cf75a 136 f = path_join(SYSTEM_DATA_UNIT_DIR, *u);
3c5a87a8
LP
137 if (!f)
138 return log_oom();
326bb68c 139
bd6c95c0
DDM
140 r = generator_add_symlink(arg_dest, target, "wants", f);
141 if (r < 0)
142 return r;
326bb68c
LP
143 }
144
3c5a87a8 145 return r;
326bb68c
LP
146}
147
36e8ba9b 148static void install_debug_shell_dropin(void) {
7bf52f5d 149 const char *tty = arg_debug_tty ?: arg_default_debug_tty;
93912e87
JS
150 int r;
151
7bf52f5d 152 if (!tty || path_equal(tty, skip_dev_prefix(DEBUGTTY)))
93912e87
JS
153 return;
154
36e8ba9b 155 r = write_drop_in_format(arg_dest, "debug-shell.service", 50, "tty",
93912e87
JS
156 "[Unit]\n"
157 "Description=Early root shell on /dev/%s FOR DEBUGGING ONLY\n"
158 "ConditionPathExists=\n"
159 "[Service]\n"
160 "TTYPath=/dev/%s",
7bf52f5d 161 tty, tty);
93912e87
JS
162 if (r < 0)
163 log_warning_errno(r, "Failed to write drop-in for debug-shell.service, ignoring: %m");
164}
165
8595f578
DDM
166static int process_unit_credentials(const char *credentials_dir) {
167 int r;
168
169 assert(credentials_dir);
170
171 _cleanup_free_ DirectoryEntries *des = NULL;
172 r = readdir_all_at(AT_FDCWD, credentials_dir, RECURSE_DIR_SORT|RECURSE_DIR_IGNORE_DOT|RECURSE_DIR_ENSURE_TYPE, &des);
173 if (r < 0)
174 return log_error_errno(r, "Failed to enumerate credentials from credentials directory '%s': %m", credentials_dir);
175
176 FOREACH_ARRAY(i, des->entries, des->n_entries) {
177 _cleanup_free_ void *d = NULL;
178 struct dirent *de = *i;
179 const char *unit, *dropin;
180
181 if (de->d_type != DT_REG)
182 continue;
183
184 unit = startswith(de->d_name, "systemd.extra-unit.");
185 dropin = startswith(de->d_name, "systemd.unit-dropin.");
186
187 if (!unit && !dropin)
188 continue;
189
190 if (!unit_name_is_valid(unit ?: dropin, UNIT_NAME_ANY)) {
191 log_warning("Invalid unit name '%s' in credential '%s', ignoring.",
192 unit ?: dropin, de->d_name);
193 continue;
194 }
195
196 r = read_credential_with_decryption(de->d_name, &d, NULL);
197 if (r < 0)
198 continue;
199
200 if (unit) {
201 _cleanup_free_ char *p = NULL;
202
203 p = path_join(arg_dest, unit);
204 if (!p)
205 return log_oom();
206
207 r = write_string_file_atomic_label(p, d);
208 if (r < 0) {
209 log_warning_errno(r, "Failed to write unit file '%s' from credential '%s', ignoring: %m",
210 unit, de->d_name);
211 continue;
212 }
213
214 log_debug("Wrote unit file '%s' from credential '%s'", unit, de->d_name);
215
216 } else {
217 r = write_drop_in(arg_dest, dropin, 50, "credential", d);
218 if (r < 0) {
219 log_warning_errno(r, "Failed to write drop-in for unit '%s' from credential '%s', ignoring: %m",
220 dropin, de->d_name);
221 continue;
222 }
223
224 log_debug("Wrote drop-in for unit '%s' from credential '%s'", dropin, de->d_name);
225 }
226 }
227
228 return 0;
229}
230
7a44c7e3 231static int run(const char *dest, const char *dest_early, const char *dest_late) {
8595f578
DDM
232 const char *credentials_dir;
233 int r = 0;
326bb68c 234
7a44c7e3 235 assert_se(arg_dest = dest_early);
326bb68c 236
a7dd6d04 237 r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_RD_STRICT | PROC_CMDLINE_STRIP_RD_PREFIX);
b5884878 238 if (r < 0)
da927ba9 239 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
326bb68c 240
3c5a87a8
LP
241 if (arg_debug_shell) {
242 r = strv_extend(&arg_wants, "debug-shell.service");
4197fde5
LP
243 if (r < 0)
244 return log_oom();
93912e87 245
36e8ba9b 246 install_debug_shell_dropin();
3c5a87a8
LP
247 }
248
8595f578
DDM
249 if (get_credentials_dir(&credentials_dir) >= 0)
250 RET_GATHER(r, process_unit_credentials(credentials_dir));
251
252 if (get_encrypted_credentials_dir(&credentials_dir) >= 0)
253 RET_GATHER(r, process_unit_credentials(credentials_dir));
326bb68c 254
8595f578
DDM
255 RET_GATHER(r, generate_mask_symlinks());
256 RET_GATHER(r, generate_wants_symlinks());
257
258 return r;
326bb68c 259}
f60947d9 260
7a44c7e3 261DEFINE_MAIN_GENERATOR_FUNCTION(run);