]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/debug-generator/debug-generator.c
sd-boot+bootctl: invert order of entries w/o sort-key
[thirdparty/systemd.git] / src / debug-generator / debug-generator.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <unistd.h>
4
5 #include "alloc-util.h"
6 #include "dropin.h"
7 #include "generator.h"
8 #include "mkdir-label.h"
9 #include "parse-util.h"
10 #include "path-util.h"
11 #include "proc-cmdline.h"
12 #include "special.h"
13 #include "string-util.h"
14 #include "strv.h"
15 #include "unit-file.h"
16 #include "unit-name.h"
17
18 static const char *arg_dest = NULL;
19 static char *arg_default_unit = NULL;
20 static char **arg_mask = NULL;
21 static char **arg_wants = NULL;
22 static char *arg_debug_shell = NULL;
23
24 STATIC_DESTRUCTOR_REGISTER(arg_default_unit, freep);
25 STATIC_DESTRUCTOR_REGISTER(arg_mask, strv_freep);
26 STATIC_DESTRUCTOR_REGISTER(arg_wants, strv_freep);
27 STATIC_DESTRUCTOR_REGISTER(arg_debug_shell, freep);
28
29 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
30 int r;
31
32 assert(key);
33
34 if (streq(key, "systemd.mask")) {
35 char *n;
36
37 if (proc_cmdline_value_missing(key, value))
38 return 0;
39
40 r = unit_name_mangle(value, UNIT_NAME_MANGLE_WARN, &n);
41 if (r < 0)
42 return log_error_errno(r, "Failed to glob unit name: %m");
43
44 r = strv_consume(&arg_mask, n);
45 if (r < 0)
46 return log_oom();
47
48 } else if (streq(key, "systemd.wants")) {
49 char *n;
50
51 if (proc_cmdline_value_missing(key, value))
52 return 0;
53
54 r = unit_name_mangle(value, UNIT_NAME_MANGLE_WARN, &n);
55 if (r < 0)
56 return log_error_errno(r, "Failed to glob unit name: %m");
57
58 r = strv_consume(&arg_wants, n);
59 if (r < 0)
60 return log_oom();
61
62 } else if (proc_cmdline_key_streq(key, "systemd.debug_shell")) {
63 const char *t = NULL;
64
65 r = value ? parse_boolean(value) : 1;
66 if (r < 0)
67 t = skip_dev_prefix(value);
68 else if (r > 0)
69 t = skip_dev_prefix(DEBUGTTY);
70
71 return free_and_strdup_warn(&arg_debug_shell, t);
72
73 } else if (streq(key, "systemd.unit")) {
74
75 if (proc_cmdline_value_missing(key, value))
76 return 0;
77
78 return free_and_strdup_warn(&arg_default_unit, value);
79
80 } else if (!value) {
81 const char *target;
82
83 target = runlevel_to_target(key);
84 if (target)
85 return free_and_strdup_warn(&arg_default_unit, target);
86 }
87
88 return 0;
89 }
90
91 static int generate_mask_symlinks(void) {
92 char **u;
93 int r = 0;
94
95 if (strv_isempty(arg_mask))
96 return 0;
97
98 STRV_FOREACH(u, arg_mask) {
99 _cleanup_free_ char *p = NULL;
100
101 p = path_join(empty_to_root(arg_dest), *u);
102 if (!p)
103 return log_oom();
104
105 if (symlink("/dev/null", p) < 0)
106 r = log_error_errno(errno,
107 "Failed to create mask symlink %s: %m",
108 p);
109 }
110
111 return r;
112 }
113
114 static int generate_wants_symlinks(void) {
115 char **u;
116 int r = 0;
117
118 if (strv_isempty(arg_wants))
119 return 0;
120
121 STRV_FOREACH(u, arg_wants) {
122 _cleanup_free_ char *p = NULL, *f = NULL;
123 const char *target;
124
125 /* This should match what do_queue_default_job() in core/main.c does. */
126 if (arg_default_unit)
127 target = arg_default_unit;
128 else if (in_initrd())
129 target = SPECIAL_INITRD_TARGET;
130 else
131 target = SPECIAL_DEFAULT_TARGET;
132
133 p = strjoin(arg_dest, "/", target, ".wants/", *u);
134 if (!p)
135 return log_oom();
136
137 f = path_join(SYSTEM_DATA_UNIT_DIR, *u);
138 if (!f)
139 return log_oom();
140
141 (void) mkdir_parents_label(p, 0755);
142
143 if (symlink(f, p) < 0)
144 r = log_error_errno(errno,
145 "Failed to create wants symlink %s: %m",
146 p);
147 }
148
149 return r;
150 }
151
152 static void install_debug_shell_dropin(const char *dir) {
153 int r;
154
155 if (streq(arg_debug_shell, skip_dev_prefix(DEBUGTTY)))
156 return;
157
158 r = write_drop_in_format(dir, "debug-shell.service", 50, "tty",
159 "[Unit]\n"
160 "Description=Early root shell on /dev/%s FOR DEBUGGING ONLY\n"
161 "ConditionPathExists=\n"
162 "[Service]\n"
163 "TTYPath=/dev/%s",
164 arg_debug_shell, arg_debug_shell);
165 if (r < 0)
166 log_warning_errno(r, "Failed to write drop-in for debug-shell.service, ignoring: %m");
167 }
168
169 static int run(const char *dest, const char *dest_early, const char *dest_late) {
170 int r, q;
171
172 assert_se(arg_dest = dest_early);
173
174 r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_RD_STRICT | PROC_CMDLINE_STRIP_RD_PREFIX);
175 if (r < 0)
176 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
177
178 if (arg_debug_shell) {
179 r = strv_extend(&arg_wants, "debug-shell.service");
180 if (r < 0)
181 return log_oom();
182
183 install_debug_shell_dropin(arg_dest);
184 }
185
186 r = generate_mask_symlinks();
187 q = generate_wants_symlinks();
188
189 return r < 0 ? r : q;
190 }
191
192 DEFINE_MAIN_GENERATOR_FUNCTION(run);