Bug Summary

File:build-scan/../src/shared/install.c
Warning:line 2914, column 9
Value stored to 'ps' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name install.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I src/shared/libsystemd-shared-239.a.p -I src/shared -I ../src/shared -I src/basic -I ../src/basic -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -I . -I .. -I /usr/include/blkid -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility default -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/shared/install.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <dirent.h>
4#include <errno(*__errno_location ()).h>
5#include <fcntl.h>
6#include <fnmatch.h>
7#include <limits.h>
8#include <stddef.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/stat.h>
13#include <unistd.h>
14
15#include "alloc-util.h"
16#include "conf-files.h"
17#include "conf-parser.h"
18#include "dirent-util.h"
19#include "extract-word.h"
20#include "fd-util.h"
21#include "fileio.h"
22#include "fs-util.h"
23#include "hashmap.h"
24#include "install-printf.h"
25#include "install.h"
26#include "locale-util.h"
27#include "log.h"
28#include "macro.h"
29#include "mkdir.h"
30#include "path-lookup.h"
31#include "path-util.h"
32#include "rm-rf.h"
33#include "set.h"
34#include "special.h"
35#include "stat-util.h"
36#include "string-table.h"
37#include "string-util.h"
38#include "strv.h"
39#include "unit-name.h"
40
41#define UNIT_FILE_FOLLOW_SYMLINK_MAX64 64
42
43typedef enum SearchFlags {
44 SEARCH_LOAD = 1 << 0,
45 SEARCH_FOLLOW_CONFIG_SYMLINKS = 1 << 1,
46 SEARCH_DROPIN = 1 << 2,
47} SearchFlags;
48
49typedef struct {
50 OrderedHashmap *will_process;
51 OrderedHashmap *have_processed;
52} InstallContext;
53
54typedef enum {
55 PRESET_UNKNOWN,
56 PRESET_ENABLE,
57 PRESET_DISABLE,
58} PresetAction;
59
60typedef struct {
61 char *pattern;
62 PresetAction action;
63 char **instances;
64} PresetRule;
65
66typedef struct {
67 PresetRule *rules;
68 size_t n_rules;
69} Presets;
70
71static inline bool_Bool unit_file_install_info_has_rules(UnitFileInstallInfo *i) {
72 assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("i"), "../src/shared/install.c", 72, __PRETTY_FUNCTION__
); } while (0)
;
73
74 return !strv_isempty(i->aliases) ||
75 !strv_isempty(i->wanted_by) ||
76 !strv_isempty(i->required_by);
77}
78
79static inline bool_Bool unit_file_install_info_has_also(UnitFileInstallInfo *i) {
80 assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("i"), "../src/shared/install.c", 80, __PRETTY_FUNCTION__
); } while (0)
;
81
82 return !strv_isempty(i->also);
83}
84
85static inline void presets_freep(Presets *p) {
86 size_t i;
87
88 if (!p)
89 return;
90
91 for (i = 0; i < p->n_rules; i++) {
92 free(p->rules[i].pattern);
93 strv_free(p->rules[i].instances);
94 }
95
96 free(p->rules);
97 p->n_rules = 0;
98}
99
100bool_Bool unit_type_may_alias(UnitType type) {
101 return IN_SET(type,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){UNIT_SERVICE, UNIT_SOCKET, UNIT_TARGET, UNIT_DEVICE
, UNIT_TIMER, UNIT_PATH})/sizeof(int)]; switch(type) { case UNIT_SERVICE
: case UNIT_SOCKET: case UNIT_TARGET: case UNIT_DEVICE: case UNIT_TIMER
: case UNIT_PATH: _found = 1; break; default: break; } _found
; })
102 UNIT_SERVICE,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){UNIT_SERVICE, UNIT_SOCKET, UNIT_TARGET, UNIT_DEVICE
, UNIT_TIMER, UNIT_PATH})/sizeof(int)]; switch(type) { case UNIT_SERVICE
: case UNIT_SOCKET: case UNIT_TARGET: case UNIT_DEVICE: case UNIT_TIMER
: case UNIT_PATH: _found = 1; break; default: break; } _found
; })
103 UNIT_SOCKET,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){UNIT_SERVICE, UNIT_SOCKET, UNIT_TARGET, UNIT_DEVICE
, UNIT_TIMER, UNIT_PATH})/sizeof(int)]; switch(type) { case UNIT_SERVICE
: case UNIT_SOCKET: case UNIT_TARGET: case UNIT_DEVICE: case UNIT_TIMER
: case UNIT_PATH: _found = 1; break; default: break; } _found
; })
104 UNIT_TARGET,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){UNIT_SERVICE, UNIT_SOCKET, UNIT_TARGET, UNIT_DEVICE
, UNIT_TIMER, UNIT_PATH})/sizeof(int)]; switch(type) { case UNIT_SERVICE
: case UNIT_SOCKET: case UNIT_TARGET: case UNIT_DEVICE: case UNIT_TIMER
: case UNIT_PATH: _found = 1; break; default: break; } _found
; })
105 UNIT_DEVICE,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){UNIT_SERVICE, UNIT_SOCKET, UNIT_TARGET, UNIT_DEVICE
, UNIT_TIMER, UNIT_PATH})/sizeof(int)]; switch(type) { case UNIT_SERVICE
: case UNIT_SOCKET: case UNIT_TARGET: case UNIT_DEVICE: case UNIT_TIMER
: case UNIT_PATH: _found = 1; break; default: break; } _found
; })
106 UNIT_TIMER,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){UNIT_SERVICE, UNIT_SOCKET, UNIT_TARGET, UNIT_DEVICE
, UNIT_TIMER, UNIT_PATH})/sizeof(int)]; switch(type) { case UNIT_SERVICE
: case UNIT_SOCKET: case UNIT_TARGET: case UNIT_DEVICE: case UNIT_TIMER
: case UNIT_PATH: _found = 1; break; default: break; } _found
; })
107 UNIT_PATH)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){UNIT_SERVICE, UNIT_SOCKET, UNIT_TARGET, UNIT_DEVICE
, UNIT_TIMER, UNIT_PATH})/sizeof(int)]; switch(type) { case UNIT_SERVICE
: case UNIT_SOCKET: case UNIT_TARGET: case UNIT_DEVICE: case UNIT_TIMER
: case UNIT_PATH: _found = 1; break; default: break; } _found
; })
;
108}
109
110bool_Bool unit_type_may_template(UnitType type) {
111 return IN_SET(type,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){UNIT_SERVICE, UNIT_SOCKET, UNIT_TARGET, UNIT_TIMER
, UNIT_PATH})/sizeof(int)]; switch(type) { case UNIT_SERVICE:
case UNIT_SOCKET: case UNIT_TARGET: case UNIT_TIMER: case UNIT_PATH
: _found = 1; break; default: break; } _found; })
112 UNIT_SERVICE,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){UNIT_SERVICE, UNIT_SOCKET, UNIT_TARGET, UNIT_TIMER
, UNIT_PATH})/sizeof(int)]; switch(type) { case UNIT_SERVICE:
case UNIT_SOCKET: case UNIT_TARGET: case UNIT_TIMER: case UNIT_PATH
: _found = 1; break; default: break; } _found; })
113 UNIT_SOCKET,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){UNIT_SERVICE, UNIT_SOCKET, UNIT_TARGET, UNIT_TIMER
, UNIT_PATH})/sizeof(int)]; switch(type) { case UNIT_SERVICE:
case UNIT_SOCKET: case UNIT_TARGET: case UNIT_TIMER: case UNIT_PATH
: _found = 1; break; default: break; } _found; })
114 UNIT_TARGET,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){UNIT_SERVICE, UNIT_SOCKET, UNIT_TARGET, UNIT_TIMER
, UNIT_PATH})/sizeof(int)]; switch(type) { case UNIT_SERVICE:
case UNIT_SOCKET: case UNIT_TARGET: case UNIT_TIMER: case UNIT_PATH
: _found = 1; break; default: break; } _found; })
115 UNIT_TIMER,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){UNIT_SERVICE, UNIT_SOCKET, UNIT_TARGET, UNIT_TIMER
, UNIT_PATH})/sizeof(int)]; switch(type) { case UNIT_SERVICE:
case UNIT_SOCKET: case UNIT_TARGET: case UNIT_TIMER: case UNIT_PATH
: _found = 1; break; default: break; } _found; })
116 UNIT_PATH)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){UNIT_SERVICE, UNIT_SOCKET, UNIT_TARGET, UNIT_TIMER
, UNIT_PATH})/sizeof(int)]; switch(type) { case UNIT_SERVICE:
case UNIT_SOCKET: case UNIT_TARGET: case UNIT_TIMER: case UNIT_PATH
: _found = 1; break; default: break; } _found; })
;
117}
118
119static const char *unit_file_type_table[_UNIT_FILE_TYPE_MAX] = {
120 [UNIT_FILE_TYPE_REGULAR] = "regular",
121 [UNIT_FILE_TYPE_SYMLINK] = "symlink",
122 [UNIT_FILE_TYPE_MASKED] = "masked",
123};
124
125DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type, UnitFileType)static const char *unit_file_type_to_string(UnitFileType i) {
if (i < 0 || i >= (UnitFileType) __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(unit_file_type_table),
typeof(&*(unit_file_type_table))), sizeof(unit_file_type_table
)/sizeof((unit_file_type_table)[0]), ((void)0)))) return ((void
*)0); return unit_file_type_table[i]; }
;
126
127static int in_search_path(const LookupPaths *p, const char *path) {
128 _cleanup_free___attribute__((cleanup(freep))) char *parent = NULL((void*)0);
129 char **i;
130
131 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/shared/install.c", 131,
__PRETTY_FUNCTION__); } while (0)
;
132
133 parent = dirname_malloc(path);
134 if (!parent)
135 return -ENOMEM12;
136
137 STRV_FOREACH(i, p->search_path)for ((i) = (p->search_path); (i) && *(i); (i)++)
138 if (path_equal(parent, *i))
139 return true1;
140
141 return false0;
142}
143
144static const char* skip_root(const LookupPaths *p, const char *path) {
145 char *e;
146
147 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/shared/install.c", 147, __PRETTY_FUNCTION__
); } while (0)
;
148 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/shared/install.c", 148,
__PRETTY_FUNCTION__); } while (0)
;
149
150 if (!p->root_dir)
151 return path;
152
153 e = path_startswith(path, p->root_dir);
154 if (!e)
155 return NULL((void*)0);
156
157 /* Make sure the returned path starts with a slash */
158 if (e[0] != '/') {
159 if (e == path || e[-1] != '/')
160 return NULL((void*)0);
161
162 e--;
163 }
164
165 return e;
166}
167
168static int path_is_generator(const LookupPaths *p, const char *path) {
169 _cleanup_free___attribute__((cleanup(freep))) char *parent = NULL((void*)0);
170
171 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/shared/install.c", 171, __PRETTY_FUNCTION__
); } while (0)
;
172 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/shared/install.c", 172,
__PRETTY_FUNCTION__); } while (0)
;
173
174 parent = dirname_malloc(path);
175 if (!parent)
176 return -ENOMEM12;
177
178 return path_equal_ptr(parent, p->generator) ||
179 path_equal_ptr(parent, p->generator_early) ||
180 path_equal_ptr(parent, p->generator_late);
181}
182
183static int path_is_transient(const LookupPaths *p, const char *path) {
184 _cleanup_free___attribute__((cleanup(freep))) char *parent = NULL((void*)0);
185
186 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/shared/install.c", 186, __PRETTY_FUNCTION__
); } while (0)
;
187 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/shared/install.c", 187,
__PRETTY_FUNCTION__); } while (0)
;
188
189 parent = dirname_malloc(path);
190 if (!parent)
191 return -ENOMEM12;
192
193 return path_equal_ptr(parent, p->transient);
194}
195
196static int path_is_control(const LookupPaths *p, const char *path) {
197 _cleanup_free___attribute__((cleanup(freep))) char *parent = NULL((void*)0);
198
199 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/shared/install.c", 199, __PRETTY_FUNCTION__
); } while (0)
;
200 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/shared/install.c", 200,
__PRETTY_FUNCTION__); } while (0)
;
201
202 parent = dirname_malloc(path);
203 if (!parent)
204 return -ENOMEM12;
205
206 return path_equal_ptr(parent, p->persistent_control) ||
207 path_equal_ptr(parent, p->runtime_control);
208}
209
210static int path_is_config(const LookupPaths *p, const char *path, bool_Bool check_parent) {
211 _cleanup_free___attribute__((cleanup(freep))) char *parent = NULL((void*)0);
212
213 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/shared/install.c", 213, __PRETTY_FUNCTION__
); } while (0)
;
214 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/shared/install.c", 214,
__PRETTY_FUNCTION__); } while (0)
;
215
216 /* Note that we do *not* have generic checks for /etc or /run in place, since with
217 * them we couldn't discern configuration from transient or generated units */
218
219 if (check_parent) {
220 parent = dirname_malloc(path);
221 if (!parent)
222 return -ENOMEM12;
223
224 path = parent;
225 }
226
227 return path_equal_ptr(path, p->persistent_config) ||
228 path_equal_ptr(path, p->runtime_config);
229}
230
231static int path_is_runtime(const LookupPaths *p, const char *path, bool_Bool check_parent) {
232 _cleanup_free___attribute__((cleanup(freep))) char *parent = NULL((void*)0);
233 const char *rpath;
234
235 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/shared/install.c", 235, __PRETTY_FUNCTION__
); } while (0)
;
236 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/shared/install.c", 236,
__PRETTY_FUNCTION__); } while (0)
;
237
238 /* Everything in /run is considered runtime. On top of that we also add
239 * explicit checks for the various runtime directories, as safety net. */
240
241 rpath = skip_root(p, path);
242 if (rpath && path_startswith(rpath, "/run"))
243 return true1;
244
245 if (check_parent) {
246 parent = dirname_malloc(path);
247 if (!parent)
248 return -ENOMEM12;
249
250 path = parent;
251 }
252
253 return path_equal_ptr(path, p->runtime_config) ||
254 path_equal_ptr(path, p->generator) ||
255 path_equal_ptr(path, p->generator_early) ||
256 path_equal_ptr(path, p->generator_late) ||
257 path_equal_ptr(path, p->transient) ||
258 path_equal_ptr(path, p->runtime_control);
259}
260
261static int path_is_vendor(const LookupPaths *p, const char *path) {
262 const char *rpath;
263
264 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/shared/install.c", 264, __PRETTY_FUNCTION__
); } while (0)
;
265 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/shared/install.c", 265,
__PRETTY_FUNCTION__); } while (0)
;
266
267 rpath = skip_root(p, path);
268 if (!rpath)
269 return 0;
270
271 if (path_startswith(rpath, "/usr"))
272 return true1;
273
274#if HAVE_SPLIT_USR0
275 if (path_startswith(rpath, "/lib"))
276 return true1;
277#endif
278
279 return path_equal(rpath, SYSTEM_DATA_UNIT_PATH"/usr/lib/systemd/system");
280}
281
282int unit_file_changes_add(
283 UnitFileChange **changes,
284 size_t *n_changes,
285 UnitFileChangeType type,
286 const char *path,
287 const char *source) {
288
289 _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0), *s = NULL((void*)0);
290 UnitFileChange *c;
291
292 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/shared/install.c", 292,
__PRETTY_FUNCTION__); } while (0)
;
293 assert(!changes == !n_changes)do { if ((__builtin_expect(!!(!(!changes == !n_changes)),0)))
log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!changes == !n_changes"
), "../src/shared/install.c", 293, __PRETTY_FUNCTION__); } while
(0)
;
294
295 if (!changes)
296 return 0;
297
298 c = reallocarray(*changes, *n_changes + 1, sizeof(UnitFileChange));
299 if (!c)
300 return -ENOMEM12;
301 *changes = c;
302
303 p = strdup(path);
304 if (source)
305 s = strdup(source);
306
307 if (!p || (source && !s))
308 return -ENOMEM12;
309
310 path_simplify(p, false0);
311 if (s)
312 path_simplify(s, false0);
313
314 c[*n_changes] = (UnitFileChange) { type, p, s };
315 p = s = NULL((void*)0);
316 (*n_changes) ++;
317 return 0;
318}
319
320void unit_file_changes_free(UnitFileChange *changes, size_t n_changes) {
321 size_t i;
322
323 assert(changes || n_changes == 0)do { if ((__builtin_expect(!!(!(changes || n_changes == 0)),0
))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("changes || n_changes == 0"
), "../src/shared/install.c", 323, __PRETTY_FUNCTION__); } while
(0)
;
324
325 for (i = 0; i < n_changes; i++) {
326 free(changes[i].path);
327 free(changes[i].source);
328 }
329
330 free(changes);
331}
332
333void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *changes, size_t n_changes, bool_Bool quiet) {
334 size_t i;
335 bool_Bool logged = false0;
336
337 assert(changes || n_changes == 0)do { if ((__builtin_expect(!!(!(changes || n_changes == 0)),0
))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("changes || n_changes == 0"
), "../src/shared/install.c", 337, __PRETTY_FUNCTION__); } while
(0)
;
338 /* If verb is not specified, errors are not allowed! */
339 assert(verb || r >= 0)do { if ((__builtin_expect(!!(!(verb || r >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("verb || r >= 0"), "../src/shared/install.c"
, 339, __PRETTY_FUNCTION__); } while (0)
;
340
341 for (i = 0; i < n_changes; i++) {
342 assert(verb || changes[i].type >= 0)do { if ((__builtin_expect(!!(!(verb || changes[i].type >=
0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("verb || changes[i].type >= 0"
), "../src/shared/install.c", 342, __PRETTY_FUNCTION__); } while
(0)
;
343
344 switch(changes[i].type) {
345 case UNIT_FILE_SYMLINK:
346 if (!quiet)
347 log_info("Created symlink %s %s %s.",({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 350, __func__, "Created symlink %s %s %s."
, changes[i].path, special_glyph(ARROW), changes[i].source) :
-abs(_e); })
348 changes[i].path,({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 350, __func__, "Created symlink %s %s %s."
, changes[i].path, special_glyph(ARROW), changes[i].source) :
-abs(_e); })
349 special_glyph(ARROW),({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 350, __func__, "Created symlink %s %s %s."
, changes[i].path, special_glyph(ARROW), changes[i].source) :
-abs(_e); })
350 changes[i].source)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 350, __func__, "Created symlink %s %s %s."
, changes[i].path, special_glyph(ARROW), changes[i].source) :
-abs(_e); })
;
351 break;
352 case UNIT_FILE_UNLINK:
353 if (!quiet)
354 log_info("Removed %s.", changes[i].path)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 354, __func__, "Removed %s.", changes
[i].path) : -abs(_e); })
;
355 break;
356 case UNIT_FILE_IS_MASKED:
357 if (!quiet)
358 log_info("Unit %s is masked, ignoring.", changes[i].path)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 358, __func__, "Unit %s is masked, ignoring."
, changes[i].path) : -abs(_e); })
;
359 break;
360 case UNIT_FILE_IS_DANGLING:
361 if (!quiet)
362 log_info("Unit %s is an alias to a unit that is not present, ignoring.",({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 363, __func__, "Unit %s is an alias to a unit that is not present, ignoring."
, changes[i].path) : -abs(_e); })
363 changes[i].path)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 363, __func__, "Unit %s is an alias to a unit that is not present, ignoring."
, changes[i].path) : -abs(_e); })
;
364 break;
365 case -EEXIST17:
366 if (changes[i].source)
367 log_error_errno(changes[i].type,({ int _level = ((3)), _e = ((changes[i].type)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 369, __func__, "Failed to %s unit, file %s already exists and is a symlink to %s."
, verb, changes[i].path, changes[i].source) : -abs(_e); })
368 "Failed to %s unit, file %s already exists and is a symlink to %s.",({ int _level = ((3)), _e = ((changes[i].type)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 369, __func__, "Failed to %s unit, file %s already exists and is a symlink to %s."
, verb, changes[i].path, changes[i].source) : -abs(_e); })
369 verb, changes[i].path, changes[i].source)({ int _level = ((3)), _e = ((changes[i].type)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 369, __func__, "Failed to %s unit, file %s already exists and is a symlink to %s."
, verb, changes[i].path, changes[i].source) : -abs(_e); })
;
370 else
371 log_error_errno(changes[i].type,({ int _level = ((3)), _e = ((changes[i].type)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 373, __func__, "Failed to %s unit, file %s already exists."
, verb, changes[i].path) : -abs(_e); })
372 "Failed to %s unit, file %s already exists.",({ int _level = ((3)), _e = ((changes[i].type)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 373, __func__, "Failed to %s unit, file %s already exists."
, verb, changes[i].path) : -abs(_e); })
373 verb, changes[i].path)({ int _level = ((3)), _e = ((changes[i].type)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 373, __func__, "Failed to %s unit, file %s already exists."
, verb, changes[i].path) : -abs(_e); })
;
374 logged = true1;
375 break;
376 case -ERFKILL132:
377 log_error_errno(changes[i].type, "Failed to %s unit, unit %s is masked.",({ int _level = ((3)), _e = ((changes[i].type)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 378, __func__, "Failed to %s unit, unit %s is masked."
, verb, changes[i].path) : -abs(_e); })
378 verb, changes[i].path)({ int _level = ((3)), _e = ((changes[i].type)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 378, __func__, "Failed to %s unit, unit %s is masked."
, verb, changes[i].path) : -abs(_e); })
;
379 logged = true1;
380 break;
381 case -EADDRNOTAVAIL99:
382 log_error_errno(changes[i].type, "Failed to %s unit, unit %s is transient or generated.",({ int _level = ((3)), _e = ((changes[i].type)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 383, __func__, "Failed to %s unit, unit %s is transient or generated."
, verb, changes[i].path) : -abs(_e); })
383 verb, changes[i].path)({ int _level = ((3)), _e = ((changes[i].type)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 383, __func__, "Failed to %s unit, unit %s is transient or generated."
, verb, changes[i].path) : -abs(_e); })
;
384 logged = true1;
385 break;
386 case -ELOOP40:
387 log_error_errno(changes[i].type, "Failed to %s unit, refusing to operate on linked unit file %s",({ int _level = ((3)), _e = ((changes[i].type)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 388, __func__, "Failed to %s unit, refusing to operate on linked unit file %s"
, verb, changes[i].path) : -abs(_e); })
388 verb, changes[i].path)({ int _level = ((3)), _e = ((changes[i].type)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 388, __func__, "Failed to %s unit, refusing to operate on linked unit file %s"
, verb, changes[i].path) : -abs(_e); })
;
389 logged = true1;
390 break;
391
392 case -ENOENT2:
393 log_error_errno(changes[i].type, "Failed to %s unit, unit %s does not exist.", verb, changes[i].path)({ int _level = ((3)), _e = ((changes[i].type)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 393, __func__, "Failed to %s unit, unit %s does not exist."
, verb, changes[i].path) : -abs(_e); })
;
394 logged = true1;
395 break;
396
397 default:
398 assert(changes[i].type < 0)do { if ((__builtin_expect(!!(!(changes[i].type < 0)),0)))
log_assert_failed_realm(LOG_REALM_SYSTEMD, ("changes[i].type < 0"
), "../src/shared/install.c", 398, __PRETTY_FUNCTION__); } while
(0)
;
399 log_error_errno(changes[i].type, "Failed to %s unit, file %s: %m.",({ int _level = ((3)), _e = ((changes[i].type)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 400, __func__, "Failed to %s unit, file %s: %m."
, verb, changes[i].path) : -abs(_e); })
400 verb, changes[i].path)({ int _level = ((3)), _e = ((changes[i].type)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 400, __func__, "Failed to %s unit, file %s: %m."
, verb, changes[i].path) : -abs(_e); })
;
401 logged = true1;
402 }
403 }
404
405 if (r < 0 && !logged)
406 log_error_errno(r, "Failed to %s: %m.", verb)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 406, __func__, "Failed to %s: %m."
, verb) : -abs(_e); })
;
407}
408
409/**
410 * Checks if two paths or symlinks from wd are the same, when root is the root of the filesystem.
411 * wc should be the full path in the host file system.
412 */
413static bool_Bool chroot_symlinks_same(const char *root, const char *wd, const char *a, const char *b) {
414 assert(path_is_absolute(wd))do { if ((__builtin_expect(!!(!(path_is_absolute(wd))),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path_is_absolute(wd)"), "../src/shared/install.c"
, 414, __PRETTY_FUNCTION__); } while (0)
;
415
416 /* This will give incorrect results if the paths are relative and go outside
417 * of the chroot. False negatives are possible. */
418
419 if (!root)
420 root = "/";
421
422 a = strjoina(path_is_absolute(a) ? root : wd, "/", a)({ const char *_appendees_[] = { path_is_absolute(a) ? root :
wd, "/", a }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_;
for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr(
!__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _len_ += strlen
(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1);
for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr(
!__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
423 b = strjoina(path_is_absolute(b) ? root : wd, "/", b)({ const char *_appendees_[] = { path_is_absolute(b) ? root :
wd, "/", b }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_;
for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr(
!__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _len_ += strlen
(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1);
for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr(
!__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
424 return path_equal_or_files_same(a, b, 0);
425}
426
427static int create_symlink(
428 const LookupPaths *paths,
429 const char *old_path,
430 const char *new_path,
431 bool_Bool force,
432 UnitFileChange **changes,
433 size_t *n_changes) {
434
435 _cleanup_free___attribute__((cleanup(freep))) char *dest = NULL((void*)0), *dirname = NULL((void*)0);
436 const char *rp;
437 int r;
438
439 assert(old_path)do { if ((__builtin_expect(!!(!(old_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("old_path"), "../src/shared/install.c", 439
, __PRETTY_FUNCTION__); } while (0)
;
440 assert(new_path)do { if ((__builtin_expect(!!(!(new_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("new_path"), "../src/shared/install.c", 440
, __PRETTY_FUNCTION__); } while (0)
;
441
442 rp = skip_root(paths, old_path);
443 if (rp)
444 old_path = rp;
445
446 /* Actually create a symlink, and remember that we did. Is
447 * smart enough to check if there's already a valid symlink in
448 * place.
449 *
450 * Returns 1 if a symlink was created or already exists and points to
451 * the right place, or negative on error.
452 */
453
454 mkdir_parents_label(new_path, 0755);
455
456 if (symlink(old_path, new_path) >= 0) {
457 unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
458 return 1;
459 }
460
461 if (errno(*__errno_location ()) != EEXIST17) {
462 unit_file_changes_add(changes, n_changes, -errno(*__errno_location ()), new_path, NULL((void*)0));
463 return -errno(*__errno_location ());
464 }
465
466 r = readlink_malloc(new_path, &dest);
467 if (r < 0) {
468 /* translate EINVAL (non-symlink exists) to EEXIST */
469 if (r == -EINVAL22)
470 r = -EEXIST17;
471
472 unit_file_changes_add(changes, n_changes, r, new_path, NULL((void*)0));
473 return r;
474 }
475
476 dirname = dirname_malloc(new_path);
477 if (!dirname)
478 return -ENOMEM12;
479
480 if (chroot_symlinks_same(paths->root_dir, dirname, dest, old_path))
481 return 1;
482
483 if (!force) {
484 unit_file_changes_add(changes, n_changes, -EEXIST17, new_path, dest);
485 return -EEXIST17;
486 }
487
488 r = symlink_atomic(old_path, new_path);
489 if (r < 0) {
490 unit_file_changes_add(changes, n_changes, r, new_path, NULL((void*)0));
491 return r;
492 }
493
494 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL((void*)0));
495 unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
496
497 return 1;
498}
499
500static int mark_symlink_for_removal(
501 Set **remove_symlinks_to,
502 const char *p) {
503
504 char *n;
505 int r;
506
507 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/shared/install.c", 507, __PRETTY_FUNCTION__
); } while (0)
;
508
509 r = set_ensure_allocated(remove_symlinks_to, &path_hash_ops)internal_set_ensure_allocated(remove_symlinks_to, &path_hash_ops
)
;
510 if (r < 0)
511 return r;
512
513 n = strdup(p);
514 if (!n)
515 return -ENOMEM12;
516
517 path_simplify(n, false0);
518
519 r = set_consume(*remove_symlinks_to, n);
520 if (r == -EEXIST17)
521 return 0;
522 if (r < 0)
523 return r;
524
525 return 1;
526}
527
528static int remove_marked_symlinks_fd(
529 Set *remove_symlinks_to,
530 int fd,
531 const char *path,
532 const char *config_path,
533 const LookupPaths *lp,
534 bool_Bool dry_run,
535 bool_Bool *restart,
536 UnitFileChange **changes,
537 size_t *n_changes) {
538
539 _cleanup_closedir___attribute__((cleanup(closedirp))) DIR *d = NULL((void*)0);
540 struct dirent *de;
541 int r = 0;
542
543 assert(remove_symlinks_to)do { if ((__builtin_expect(!!(!(remove_symlinks_to)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("remove_symlinks_to"), "../src/shared/install.c"
, 543, __PRETTY_FUNCTION__); } while (0)
;
544 assert(fd >= 0)do { if ((__builtin_expect(!!(!(fd >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fd >= 0"), "../src/shared/install.c"
, 544, __PRETTY_FUNCTION__); } while (0)
;
545 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/shared/install.c", 545,
__PRETTY_FUNCTION__); } while (0)
;
546 assert(config_path)do { if ((__builtin_expect(!!(!(config_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("config_path"), "../src/shared/install.c"
, 546, __PRETTY_FUNCTION__); } while (0)
;
547 assert(lp)do { if ((__builtin_expect(!!(!(lp)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("lp"), "../src/shared/install.c", 547, __PRETTY_FUNCTION__
); } while (0)
;
548 assert(restart)do { if ((__builtin_expect(!!(!(restart)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("restart"), "../src/shared/install.c", 548
, __PRETTY_FUNCTION__); } while (0)
;
549
550 d = fdopendir(fd);
551 if (!d) {
552 safe_close(fd);
553 return -errno(*__errno_location ());
554 }
555
556 rewinddir(d);
557
558 FOREACH_DIRENT(de, d, return -errno)for ((*__errno_location ()) = 0, de = readdir(d);; (*__errno_location
()) = 0, de = readdir(d)) if (!de) { if ((*__errno_location (
)) > 0) { return -(*__errno_location ()); } break; } else if
(hidden_or_backup_file((de)->d_name)) continue; else
{
559
560 dirent_ensure_type(d, de);
561
562 if (de->d_type == DT_DIRDT_DIR) {
563 _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0);
564 int nfd, q;
565
566 nfd = openat(fd, de->d_name, O_RDONLY00|O_NONBLOCK04000|O_DIRECTORY0200000|O_CLOEXEC02000000|O_NOFOLLOW0400000);
567 if (nfd < 0) {
568 if (errno(*__errno_location ()) == ENOENT2)
569 continue;
570
571 if (r == 0)
572 r = -errno(*__errno_location ());
573 continue;
574 }
575
576 p = path_make_absolute(de->d_name, path);
577 if (!p) {
578 safe_close(nfd);
579 return -ENOMEM12;
580 }
581
582 /* This will close nfd, regardless whether it succeeds or not */
583 q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, lp, dry_run, restart, changes, n_changes);
584 if (q < 0 && r == 0)
585 r = q;
586
587 } else if (de->d_type == DT_LNKDT_LNK) {
588 _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0), *dest = NULL((void*)0);
589 const char *rp;
590 bool_Bool found;
591 int q;
592
593 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
594 continue;
595
596 p = path_make_absolute(de->d_name, path);
597 if (!p)
598 return -ENOMEM12;
599 path_simplify(p, false0);
600
601 q = readlink_malloc(p, &dest);
602 if (q == -ENOENT2)
603 continue;
604 if (q < 0) {
605 if (r == 0)
606 r = q;
607 continue;
608 }
609
610 /* We remove all links pointing to a file or path that is marked, as well as all files sharing
611 * the same name as a file that is marked. */
612
613 found = set_contains(remove_symlinks_to, dest) ||
614 set_contains(remove_symlinks_to, basename(dest)) ||
615 set_contains(remove_symlinks_to, de->d_name);
616
617 if (!found)
618 continue;
619
620 if (!dry_run) {
621 if (unlinkat(fd, de->d_name, 0) < 0 && errno(*__errno_location ()) != ENOENT2) {
622 if (r == 0)
623 r = -errno(*__errno_location ());
624 unit_file_changes_add(changes, n_changes, -errno(*__errno_location ()), p, NULL((void*)0));
625 continue;
626 }
627
628 (void) rmdir_parents(p, config_path);
629 }
630
631 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL((void*)0));
632
633 /* Now, remember the full path (but with the root prefix removed) of
634 * the symlink we just removed, and remove any symlinks to it, too. */
635
636 rp = skip_root(lp, p);
637 q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: p);
638 if (q < 0)
639 return q;
640 if (q > 0 && !dry_run)
641 *restart = true1;
642 }
643 }
644
645 return r;
646}
647
648static int remove_marked_symlinks(
649 Set *remove_symlinks_to,
650 const char *config_path,
651 const LookupPaths *lp,
652 bool_Bool dry_run,
653 UnitFileChange **changes,
654 size_t *n_changes) {
655
656 _cleanup_close___attribute__((cleanup(closep))) int fd = -1;
657 bool_Bool restart;
658 int r = 0;
659
660 assert(config_path)do { if ((__builtin_expect(!!(!(config_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("config_path"), "../src/shared/install.c"
, 660, __PRETTY_FUNCTION__); } while (0)
;
661 assert(lp)do { if ((__builtin_expect(!!(!(lp)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("lp"), "../src/shared/install.c", 661, __PRETTY_FUNCTION__
); } while (0)
;
662
663 if (set_size(remove_symlinks_to) <= 0)
664 return 0;
665
666 fd = open(config_path, O_RDONLY00|O_NONBLOCK04000|O_DIRECTORY0200000|O_CLOEXEC02000000);
667 if (fd < 0)
668 return errno(*__errno_location ()) == ENOENT2 ? 0 : -errno(*__errno_location ());
669
670 do {
671 int q, cfd;
672 restart = false0;
673
674 cfd = fcntl(fd, F_DUPFD_CLOEXEC1030, 3);
675 if (cfd < 0)
676 return -errno(*__errno_location ());
677
678 /* This takes possession of cfd and closes it */
679 q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, lp, dry_run, &restart, changes, n_changes);
680 if (r == 0)
681 r = q;
682 } while (restart);
683
684 return r;
685}
686
687static bool_Bool is_symlink_with_known_name(const UnitFileInstallInfo *i, const char *name) {
688 int r;
689
690 if (streq(name, i->name)(strcmp((name),(i->name)) == 0))
691 return true1;
692
693 if (strv_contains(i->aliases, name)(!!strv_find((i->aliases), (name))))
694 return true1;
695
696 /* Look for template symlink matching DefaultInstance */
697 if (i->default_instance && unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE)) {
698 _cleanup_free___attribute__((cleanup(freep))) char *s = NULL((void*)0);
699
700 r = unit_name_replace_instance(i->name, i->default_instance, &s);
701 if (r < 0) {
702 if (r != -EINVAL22)
703 return r;
704
705 } else if (streq(name, s)(strcmp((name),(s)) == 0))
706 return true1;
707 }
708
709 return false0;
710}
711
712static int find_symlinks_fd(
713 const char *root_dir,
714 UnitFileInstallInfo *i,
715 bool_Bool match_aliases,
716 int fd,
717 const char *path,
718 const char *config_path,
719 bool_Bool *same_name_link) {
720
721 _cleanup_closedir___attribute__((cleanup(closedirp))) DIR *d = NULL((void*)0);
722 struct dirent *de;
723 int r = 0;
724
725 assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("i"), "../src/shared/install.c", 725, __PRETTY_FUNCTION__
); } while (0)
;
726 assert(fd >= 0)do { if ((__builtin_expect(!!(!(fd >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fd >= 0"), "../src/shared/install.c"
, 726, __PRETTY_FUNCTION__); } while (0)
;
727 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/shared/install.c", 727,
__PRETTY_FUNCTION__); } while (0)
;
728 assert(config_path)do { if ((__builtin_expect(!!(!(config_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("config_path"), "../src/shared/install.c"
, 728, __PRETTY_FUNCTION__); } while (0)
;
729 assert(same_name_link)do { if ((__builtin_expect(!!(!(same_name_link)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("same_name_link"), "../src/shared/install.c"
, 729, __PRETTY_FUNCTION__); } while (0)
;
730
731 d = fdopendir(fd);
732 if (!d) {
733 safe_close(fd);
734 return -errno(*__errno_location ());
735 }
736
737 FOREACH_DIRENT(de, d, return -errno)for ((*__errno_location ()) = 0, de = readdir(d);; (*__errno_location
()) = 0, de = readdir(d)) if (!de) { if ((*__errno_location (
)) > 0) { return -(*__errno_location ()); } break; } else if
(hidden_or_backup_file((de)->d_name)) continue; else
{
738
739 dirent_ensure_type(d, de);
740
741 if (de->d_type == DT_DIRDT_DIR) {
742 _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0);
743 int nfd, q;
744
745 nfd = openat(fd, de->d_name, O_RDONLY00|O_NONBLOCK04000|O_DIRECTORY0200000|O_CLOEXEC02000000|O_NOFOLLOW0400000);
746 if (nfd < 0) {
747 if (errno(*__errno_location ()) == ENOENT2)
748 continue;
749
750 if (r == 0)
751 r = -errno(*__errno_location ());
752 continue;
753 }
754
755 p = path_make_absolute(de->d_name, path);
756 if (!p) {
757 safe_close(nfd);
758 return -ENOMEM12;
759 }
760
761 /* This will close nfd, regardless whether it succeeds or not */
762 q = find_symlinks_fd(root_dir, i, match_aliases, nfd,
763 p, config_path, same_name_link);
764 if (q > 0)
765 return 1;
766 if (r == 0)
767 r = q;
768
769 } else if (de->d_type == DT_LNKDT_LNK) {
770 _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0), *dest = NULL((void*)0);
771 bool_Bool found_path, found_dest, b = false0;
772 int q;
773
774 /* Acquire symlink name */
775 p = path_make_absolute(de->d_name, path);
776 if (!p)
777 return -ENOMEM12;
778
779 /* Acquire symlink destination */
780 q = readlink_malloc(p, &dest);
781 if (q == -ENOENT2)
782 continue;
783 if (q < 0) {
784 if (r == 0)
785 r = q;
786 continue;
787 }
788
789 /* Make absolute */
790 if (!path_is_absolute(dest)) {
791 char *x;
792
793 x = prefix_root(root_dir, dest);
794 if (!x)
795 return -ENOMEM12;
796
797 free(dest);
798 dest = x;
799 }
800
801 /* Check if the symlink itself matches what we
802 * are looking for */
803 if (path_is_absolute(i->name))
804 found_path = path_equal(p, i->name);
805 else
806 found_path = streq(de->d_name, i->name)(strcmp((de->d_name),(i->name)) == 0);
807
808 /* Check if what the symlink points to
809 * matches what we are looking for */
810 if (path_is_absolute(i->name))
811 found_dest = path_equal(dest, i->name);
812 else
813 found_dest = streq(basename(dest), i->name)(strcmp((basename(dest)),(i->name)) == 0);
814
815 if (found_path && found_dest) {
816 _cleanup_free___attribute__((cleanup(freep))) char *t = NULL((void*)0);
817
818 /* Filter out same name links in the main
819 * config path */
820 t = path_make_absolute(i->name, config_path);
821 if (!t)
822 return -ENOMEM12;
823
824 b = path_equal(t, p);
825 }
826
827 if (b)
828 *same_name_link = true1;
829 else if (found_path || found_dest) {
830 if (!match_aliases)
831 return 1;
832
833 /* Check if symlink name is in the set of names used by [Install] */
834 q = is_symlink_with_known_name(i, de->d_name);
835 if (q < 0)
836 return q;
837 if (q > 0)
838 return 1;
839 }
840 }
841 }
842
843 return r;
844}
845
846static int find_symlinks(
847 const char *root_dir,
848 UnitFileInstallInfo *i,
849 bool_Bool match_name,
850 const char *config_path,
851 bool_Bool *same_name_link) {
852
853 int fd;
854
855 assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("i"), "../src/shared/install.c", 855, __PRETTY_FUNCTION__
); } while (0)
;
856 assert(config_path)do { if ((__builtin_expect(!!(!(config_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("config_path"), "../src/shared/install.c"
, 856, __PRETTY_FUNCTION__); } while (0)
;
857 assert(same_name_link)do { if ((__builtin_expect(!!(!(same_name_link)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("same_name_link"), "../src/shared/install.c"
, 857, __PRETTY_FUNCTION__); } while (0)
;
858
859 fd = open(config_path, O_RDONLY00|O_NONBLOCK04000|O_DIRECTORY0200000|O_CLOEXEC02000000);
860 if (fd < 0) {
861 if (IN_SET(errno, ENOENT, ENOTDIR, EACCES)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){2, 20, 13})/sizeof(int)]; switch((*__errno_location
())) { case 2: case 20: case 13: _found = 1; break; default:
break; } _found; })
)
862 return 0;
863 return -errno(*__errno_location ());
864 }
865
866 /* This takes possession of fd and closes it */
867 return find_symlinks_fd(root_dir, i, match_name, fd,
868 config_path, config_path, same_name_link);
869}
870
871static int find_symlinks_in_scope(
872 UnitFileScope scope,
873 const LookupPaths *paths,
874 UnitFileInstallInfo *i,
875 bool_Bool match_name,
876 UnitFileState *state) {
877
878 bool_Bool same_name_link_runtime = false0, same_name_link_config = false0;
879 bool_Bool enabled_in_runtime = false0, enabled_at_all = false0;
880 char **p;
881 int r;
882
883 assert(paths)do { if ((__builtin_expect(!!(!(paths)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("paths"), "../src/shared/install.c", 883
, __PRETTY_FUNCTION__); } while (0)
;
884 assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("i"), "../src/shared/install.c", 884, __PRETTY_FUNCTION__
); } while (0)
;
885
886 STRV_FOREACH(p, paths->search_path)for ((p) = (paths->search_path); (p) && *(p); (p)++
)
{
887 bool_Bool same_name_link = false0;
888
889 r = find_symlinks(paths->root_dir, i, match_name, *p, &same_name_link);
890 if (r < 0)
891 return r;
892 if (r > 0) {
893 /* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
894
895 if (path_equal_ptr(*p, paths->persistent_config)) {
896 /* This is the best outcome, let's return it immediately. */
897 *state = UNIT_FILE_ENABLED;
898 return 1;
899 }
900
901 /* look for global enablement of user units */
902 if (scope == UNIT_FILE_USER && path_is_user_config_dir(*p)) {
903 *state = UNIT_FILE_ENABLED;
904 return 1;
905 }
906
907 r = path_is_runtime(paths, *p, false0);
908 if (r < 0)
909 return r;
910 if (r > 0)
911 enabled_in_runtime = true1;
912 else
913 enabled_at_all = true1;
914
915 } else if (same_name_link) {
916 if (path_equal_ptr(*p, paths->persistent_config))
917 same_name_link_config = true1;
918 else {
919 r = path_is_runtime(paths, *p, false0);
920 if (r < 0)
921 return r;
922 if (r > 0)
923 same_name_link_runtime = true1;
924 }
925 }
926 }
927
928 if (enabled_in_runtime) {
929 *state = UNIT_FILE_ENABLED_RUNTIME;
930 return 1;
931 }
932
933 /* Here's a special rule: if the unit we are looking for is an instance, and it symlinked in the search path
934 * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only
935 * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate
936 * something, and hence are a much stronger concept. */
937 if (enabled_at_all && unit_name_is_valid(i->name, UNIT_NAME_INSTANCE)) {
938 *state = UNIT_FILE_STATIC;
939 return 1;
940 }
941
942 /* Hmm, we didn't find it, but maybe we found the same name
943 * link? */
944 if (same_name_link_config) {
945 *state = UNIT_FILE_LINKED;
946 return 1;
947 }
948 if (same_name_link_runtime) {
949 *state = UNIT_FILE_LINKED_RUNTIME;
950 return 1;
951 }
952
953 return 0;
954}
955
956static void install_info_free(UnitFileInstallInfo *i) {
957
958 if (!i)
959 return;
960
961 free(i->name);
962 free(i->path);
963 strv_free(i->aliases);
964 strv_free(i->wanted_by);
965 strv_free(i->required_by);
966 strv_free(i->also);
967 free(i->default_instance);
968 free(i->symlink_target);
969 free(i);
970}
971
972static void install_context_done(InstallContext *c) {
973 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/shared/install.c", 973, __PRETTY_FUNCTION__
); } while (0)
;
974
975 c->will_process = ordered_hashmap_free_with_destructor(c->will_process, install_info_free)({ ({ void *_item; while ((_item = ordered_hashmap_steal_first
(c->will_process))) install_info_free(_item); }); ordered_hashmap_free
(c->will_process); })
;
976 c->have_processed = ordered_hashmap_free_with_destructor(c->have_processed, install_info_free)({ ({ void *_item; while ((_item = ordered_hashmap_steal_first
(c->have_processed))) install_info_free(_item); }); ordered_hashmap_free
(c->have_processed); })
;
977}
978
979static UnitFileInstallInfo *install_info_find(InstallContext *c, const char *name) {
980 UnitFileInstallInfo *i;
981
982 i = ordered_hashmap_get(c->have_processed, name);
983 if (i)
984 return i;
985
986 return ordered_hashmap_get(c->will_process, name);
987}
988
989static int install_info_may_process(
990 UnitFileInstallInfo *i,
991 const LookupPaths *paths,
992 UnitFileChange **changes,
993 size_t *n_changes) {
994 assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("i"), "../src/shared/install.c", 994, __PRETTY_FUNCTION__
); } while (0)
;
995 assert(paths)do { if ((__builtin_expect(!!(!(paths)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("paths"), "../src/shared/install.c", 995
, __PRETTY_FUNCTION__); } while (0)
;
996
997 /* Checks whether the loaded unit file is one we should process, or is masked,
998 * transient or generated and thus not subject to enable/disable operations. */
999
1000 if (i->type == UNIT_FILE_TYPE_MASKED) {
1001 unit_file_changes_add(changes, n_changes, -ERFKILL132, i->path, NULL((void*)0));
1002 return -ERFKILL132;
1003 }
1004 if (path_is_generator(paths, i->path) ||
1005 path_is_transient(paths, i->path)) {
1006 unit_file_changes_add(changes, n_changes, -EADDRNOTAVAIL99, i->path, NULL((void*)0));
1007 return -EADDRNOTAVAIL99;
1008 }
1009
1010 return 0;
1011}
1012
1013/**
1014 * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
1015 * hashmap, or retrieves the existing one if already present.
1016 *
1017 * Returns negative on error, 0 if the unit was already known, 1 otherwise.
1018 */
1019static int install_info_add(
1020 InstallContext *c,
1021 const char *name,
1022 const char *path,
1023 bool_Bool auxiliary,
1024 UnitFileInstallInfo **ret) {
1025
1026 UnitFileInstallInfo *i = NULL((void*)0);
1027 int r;
1028
1029 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/shared/install.c", 1029, __PRETTY_FUNCTION__
); } while (0)
;
1030 assert(name || path)do { if ((__builtin_expect(!!(!(name || path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name || path"), "../src/shared/install.c"
, 1030, __PRETTY_FUNCTION__); } while (0)
;
1031
1032 if (!name)
1033 name = basename(path);
1034
1035 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
1036 return -EINVAL22;
1037
1038 i = install_info_find(c, name);
1039 if (i) {
1040 i->auxiliary = i->auxiliary && auxiliary;
1041
1042 if (ret)
1043 *ret = i;
1044 return 0;
1045 }
1046
1047 r = ordered_hashmap_ensure_allocated(&c->will_process, &string_hash_ops)internal_ordered_hashmap_ensure_allocated(&c->will_process
, &string_hash_ops )
;
1048 if (r < 0)
1049 return r;
1050
1051 i = new0(UnitFileInstallInfo, 1)((UnitFileInstallInfo*) calloc((1), sizeof(UnitFileInstallInfo
)))
;
1052 if (!i)
1053 return -ENOMEM12;
1054 i->type = _UNIT_FILE_TYPE_INVALID;
1055 i->auxiliary = auxiliary;
1056
1057 i->name = strdup(name);
1058 if (!i->name) {
1059 r = -ENOMEM12;
1060 goto fail;
1061 }
1062
1063 if (path) {
1064 i->path = strdup(path);
1065 if (!i->path) {
1066 r = -ENOMEM12;
1067 goto fail;
1068 }
1069 }
1070
1071 r = ordered_hashmap_put(c->will_process, i->name, i);
1072 if (r < 0)
1073 goto fail;
1074
1075 if (ret)
1076 *ret = i;
1077
1078 return 1;
1079
1080fail:
1081 install_info_free(i);
1082 return r;
1083}
1084
1085static int config_parse_alias(
1086 const char *unit,
1087 const char *filename,
1088 unsigned line,
1089 const char *section,
1090 unsigned section_line,
1091 const char *lvalue,
1092 int ltype,
1093 const char *rvalue,
1094 void *data,
1095 void *userdata) {
1096
1097 UnitType type;
1098
1099 assert(unit)do { if ((__builtin_expect(!!(!(unit)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("unit"), "../src/shared/install.c", 1099
, __PRETTY_FUNCTION__); } while (0)
;
1100 assert(filename)do { if ((__builtin_expect(!!(!(filename)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("filename"), "../src/shared/install.c", 1100
, __PRETTY_FUNCTION__); } while (0)
;
1101 assert(lvalue)do { if ((__builtin_expect(!!(!(lvalue)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("lvalue"), "../src/shared/install.c", 1101
, __PRETTY_FUNCTION__); } while (0)
;
1102 assert(rvalue)do { if ((__builtin_expect(!!(!(rvalue)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("rvalue"), "../src/shared/install.c", 1102
, __PRETTY_FUNCTION__); } while (0)
;
1103
1104 type = unit_name_to_type(unit);
1105 if (!unit_type_may_alias(type))
1106 return log_syntax(unit, LOG_WARNING, filename, line, 0,({ int _level = (4), _e = (0); (log_get_max_level_realm(LOG_REALM_SYSTEMD
) >= ((_level) & 0x07)) ? log_syntax_internal(unit, _level
, filename, line, _e, "../src/shared/install.c", 1108, __func__
, "Alias= is not allowed for %s units, ignoring.", unit_type_to_string
(type)) : -abs(_e); })
1107 "Alias= is not allowed for %s units, ignoring.",({ int _level = (4), _e = (0); (log_get_max_level_realm(LOG_REALM_SYSTEMD
) >= ((_level) & 0x07)) ? log_syntax_internal(unit, _level
, filename, line, _e, "../src/shared/install.c", 1108, __func__
, "Alias= is not allowed for %s units, ignoring.", unit_type_to_string
(type)) : -abs(_e); })
1108 unit_type_to_string(type))({ int _level = (4), _e = (0); (log_get_max_level_realm(LOG_REALM_SYSTEMD
) >= ((_level) & 0x07)) ? log_syntax_internal(unit, _level
, filename, line, _e, "../src/shared/install.c", 1108, __func__
, "Alias= is not allowed for %s units, ignoring.", unit_type_to_string
(type)) : -abs(_e); })
;
1109
1110 return config_parse_strv(unit, filename, line, section, section_line,
1111 lvalue, ltype, rvalue, data, userdata);
1112}
1113
1114static int config_parse_also(
1115 const char *unit,
1116 const char *filename,
1117 unsigned line,
1118 const char *section,
1119 unsigned section_line,
1120 const char *lvalue,
1121 int ltype,
1122 const char *rvalue,
1123 void *data,
1124 void *userdata) {
1125
1126 UnitFileInstallInfo *info = userdata, *alsoinfo = NULL((void*)0);
1127 InstallContext *c = data;
1128 int r;
1129
1130 assert(unit)do { if ((__builtin_expect(!!(!(unit)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("unit"), "../src/shared/install.c", 1130
, __PRETTY_FUNCTION__); } while (0)
;
1131 assert(filename)do { if ((__builtin_expect(!!(!(filename)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("filename"), "../src/shared/install.c", 1131
, __PRETTY_FUNCTION__); } while (0)
;
1132 assert(lvalue)do { if ((__builtin_expect(!!(!(lvalue)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("lvalue"), "../src/shared/install.c", 1132
, __PRETTY_FUNCTION__); } while (0)
;
1133 assert(rvalue)do { if ((__builtin_expect(!!(!(rvalue)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("rvalue"), "../src/shared/install.c", 1133
, __PRETTY_FUNCTION__); } while (0)
;
1134
1135 for (;;) {
1136 _cleanup_free___attribute__((cleanup(freep))) char *word = NULL((void*)0), *printed = NULL((void*)0);
1137
1138 r = extract_first_word(&rvalue, &word, NULL((void*)0), 0);
1139 if (r < 0)
1140 return r;
1141 if (r == 0)
1142 break;
1143
1144 r = install_full_printf(info, word, &printed);
1145 if (r < 0)
1146 return r;
1147
1148 if (!unit_name_is_valid(printed, UNIT_NAME_ANY))
1149 return -EINVAL22;
1150
1151 r = install_info_add(c, printed, NULL((void*)0), true1, &alsoinfo);
1152 if (r < 0)
1153 return r;
1154
1155 r = strv_push(&info->also, printed);
1156 if (r < 0)
1157 return r;
1158
1159 printed = NULL((void*)0);
1160 }
1161
1162 return 0;
1163}
1164
1165static int config_parse_default_instance(
1166 const char *unit,
1167 const char *filename,
1168 unsigned line,
1169 const char *section,
1170 unsigned section_line,
1171 const char *lvalue,
1172 int ltype,
1173 const char *rvalue,
1174 void *data,
1175 void *userdata) {
1176
1177 UnitFileInstallInfo *i = data;
1178 _cleanup_free___attribute__((cleanup(freep))) char *printed = NULL((void*)0);
1179 int r;
1180
1181 assert(unit)do { if ((__builtin_expect(!!(!(unit)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("unit"), "../src/shared/install.c", 1181
, __PRETTY_FUNCTION__); } while (0)
;
1182 assert(filename)do { if ((__builtin_expect(!!(!(filename)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("filename"), "../src/shared/install.c", 1182
, __PRETTY_FUNCTION__); } while (0)
;
1183 assert(lvalue)do { if ((__builtin_expect(!!(!(lvalue)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("lvalue"), "../src/shared/install.c", 1183
, __PRETTY_FUNCTION__); } while (0)
;
1184 assert(rvalue)do { if ((__builtin_expect(!!(!(rvalue)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("rvalue"), "../src/shared/install.c", 1184
, __PRETTY_FUNCTION__); } while (0)
;
1185
1186 if (unit_name_is_valid(unit, UNIT_NAME_INSTANCE))
1187 /* When enabling an instance, we might be using a template unit file,
1188 * but we should ignore DefaultInstance silently. */
1189 return 0;
1190 if (!unit_name_is_valid(unit, UNIT_NAME_TEMPLATE))
1191 return log_syntax(unit, LOG_WARNING, filename, line, 0,({ int _level = (4), _e = (0); (log_get_max_level_realm(LOG_REALM_SYSTEMD
) >= ((_level) & 0x07)) ? log_syntax_internal(unit, _level
, filename, line, _e, "../src/shared/install.c", 1192, __func__
, "DefaultInstance= only makes sense for template units, ignoring."
) : -abs(_e); })
1192 "DefaultInstance= only makes sense for template units, ignoring.")({ int _level = (4), _e = (0); (log_get_max_level_realm(LOG_REALM_SYSTEMD
) >= ((_level) & 0x07)) ? log_syntax_internal(unit, _level
, filename, line, _e, "../src/shared/install.c", 1192, __func__
, "DefaultInstance= only makes sense for template units, ignoring."
) : -abs(_e); })
;
1193
1194 r = install_full_printf(i, rvalue, &printed);
1195 if (r < 0)
1196 return r;
1197
1198 if (!unit_instance_is_valid(printed))
1199 return -EINVAL22;
1200
1201 return free_and_replace(i->default_instance, printed)({ free(i->default_instance); (i->default_instance) = (
printed); (printed) = ((void*)0); 0; })
;
1202}
1203
1204static int unit_file_load(
1205 InstallContext *c,
1206 UnitFileInstallInfo *info,
1207 const char *path,
1208 const char *root_dir,
1209 SearchFlags flags) {
1210
1211 const ConfigTableItem items[] = {
1212 { "Install", "Alias", config_parse_alias, 0, &info->aliases },
1213 { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
1214 { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
1215 { "Install", "DefaultInstance", config_parse_default_instance, 0, info },
1216 { "Install", "Also", config_parse_also, 0, c },
1217 {}
1218 };
1219
1220 UnitType type;
1221 _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0);
1222 _cleanup_close___attribute__((cleanup(closep))) int fd = -1;
1223 struct stat st;
1224 int r;
1225
1226 assert(info)do { if ((__builtin_expect(!!(!(info)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("info"), "../src/shared/install.c", 1226
, __PRETTY_FUNCTION__); } while (0)
;
1227 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/shared/install.c", 1227
, __PRETTY_FUNCTION__); } while (0)
;
1228
1229 if (!(flags & SEARCH_DROPIN)) {
1230 /* Loading or checking for the main unit file… */
1231
1232 type = unit_name_to_type(info->name);
1233 if (type < 0)
1234 return -EINVAL22;
1235 if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE|UNIT_NAME_INSTANCE) && !unit_type_may_template(type)) {
1236 log_error("Unit type %s cannot be templated.", unit_type_to_string(type))({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 1236, __func__, "Unit type %s cannot be templated."
, unit_type_to_string(type)) : -abs(_e); })
;
1237 return -EINVAL22;
1238 }
1239
1240 if (!(flags & SEARCH_LOAD)) {
1241 r = lstat(path, &st);
1242 if (r < 0)
1243 return -errno(*__errno_location ());
1244
1245 if (null_or_empty(&st))
1246 info->type = UNIT_FILE_TYPE_MASKED;
1247 else if (S_ISREG(st.st_mode)((((st.st_mode)) & 0170000) == (0100000)))
1248 info->type = UNIT_FILE_TYPE_REGULAR;
1249 else if (S_ISLNK(st.st_mode)((((st.st_mode)) & 0170000) == (0120000)))
1250 return -ELOOP40;
1251 else if (S_ISDIR(st.st_mode)((((st.st_mode)) & 0170000) == (0040000)))
1252 return -EISDIR21;
1253 else
1254 return -ENOTTY25;
1255
1256 return 0;
1257 }
1258
1259 fd = open(path, O_RDONLY00|O_CLOEXEC02000000|O_NOCTTY0400|O_NOFOLLOW0400000);
1260 if (fd < 0)
1261 return -errno(*__errno_location ());
1262 } else {
1263 /* Operating on a drop-in file. If we aren't supposed to load the unit file drop-ins don't matter, let's hence shortcut this. */
1264
1265 if (!(flags & SEARCH_LOAD))
1266 return 0;
1267
1268 fd = chase_symlinks_and_open(path, root_dir, 0, O_RDONLY00|O_CLOEXEC02000000|O_NOCTTY0400, NULL((void*)0));
1269 if (fd < 0)
1270 return fd;
1271 }
1272
1273 if (fstat(fd, &st) < 0)
1274 return -errno(*__errno_location ());
1275
1276 if (null_or_empty(&st)) {
1277 if ((flags & SEARCH_DROPIN) == 0)
1278 info->type = UNIT_FILE_TYPE_MASKED;
1279
1280 return 0;
1281 }
1282
1283 r = stat_verify_regular(&st);
1284 if (r < 0)
1285 return r;
1286
1287 f = fdopen(fd, "re");
1288 if (!f)
1289 return -errno(*__errno_location ());
1290 fd = -1;
1291
1292 /* c is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */
1293 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/shared/install.c", 1293, __PRETTY_FUNCTION__
); } while (0)
;
1294
1295 r = config_parse(info->name, path, f,
1296 NULL((void*)0),
1297 config_item_table_lookup, items,
1298 CONFIG_PARSE_RELAXED|CONFIG_PARSE_ALLOW_INCLUDE, info);
1299 if (r < 0)
1300 return log_debug_errno(r, "Failed to parse %s: %m", info->name)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 1300, __func__, "Failed to parse %s: %m"
, info->name) : -abs(_e); })
;
1301
1302 if ((flags & SEARCH_DROPIN) == 0)
1303 info->type = UNIT_FILE_TYPE_REGULAR;
1304
1305 return
1306 (int) strv_length(info->aliases) +
1307 (int) strv_length(info->wanted_by) +
1308 (int) strv_length(info->required_by);
1309}
1310
1311static int unit_file_load_or_readlink(
1312 InstallContext *c,
1313 UnitFileInstallInfo *info,
1314 const char *path,
1315 const char *root_dir,
1316 SearchFlags flags) {
1317
1318 _cleanup_free___attribute__((cleanup(freep))) char *target = NULL((void*)0);
1319 int r;
1320
1321 r = unit_file_load(c, info, path, root_dir, flags);
1322 if (r != -ELOOP40 || (flags & SEARCH_DROPIN))
1323 return r;
1324
1325 /* This is a symlink, let's read it. */
1326
1327 r = readlink_malloc(path, &target);
1328 if (r < 0)
1329 return r;
1330
1331 if (path_equal(target, "/dev/null"))
1332 info->type = UNIT_FILE_TYPE_MASKED;
1333 else {
1334 const char *bn;
1335 UnitType a, b;
1336
1337 bn = basename(target);
1338
1339 if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN)) {
1340
1341 if (!unit_name_is_valid(bn, UNIT_NAME_PLAIN))
1342 return -EINVAL22;
1343
1344 } else if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
1345
1346 if (!unit_name_is_valid(bn, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
1347 return -EINVAL22;
1348
1349 } else if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE)) {
1350
1351 if (!unit_name_is_valid(bn, UNIT_NAME_TEMPLATE))
1352 return -EINVAL22;
1353 } else
1354 return -EINVAL22;
1355
1356 /* Enforce that the symlink destination does not
1357 * change the unit file type. */
1358
1359 a = unit_name_to_type(info->name);
1360 b = unit_name_to_type(bn);
1361 if (a < 0 || b < 0 || a != b)
1362 return -EINVAL22;
1363
1364 if (path_is_absolute(target))
1365 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1366 info->symlink_target = prefix_root(root_dir, target);
1367 else
1368 /* This is a relative path, take it relative to the dir the symlink is located in. */
1369 info->symlink_target = file_in_same_dir(path, target);
1370 if (!info->symlink_target)
1371 return -ENOMEM12;
1372
1373 info->type = UNIT_FILE_TYPE_SYMLINK;
1374 }
1375
1376 return 0;
1377}
1378
1379static int unit_file_search(
1380 InstallContext *c,
1381 UnitFileInstallInfo *info,
1382 const LookupPaths *paths,
1383 SearchFlags flags) {
1384
1385 const char *dropin_dir_name = NULL((void*)0), *dropin_template_dir_name = NULL((void*)0);
1386 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **dirs = NULL((void*)0), **files = NULL((void*)0);
1387 _cleanup_free___attribute__((cleanup(freep))) char *template = NULL((void*)0);
1388 bool_Bool found_unit = false0;
1389 int r, result;
1390 char **p;
1391
1392 assert(info)do { if ((__builtin_expect(!!(!(info)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("info"), "../src/shared/install.c", 1392
, __PRETTY_FUNCTION__); } while (0)
;
1393 assert(paths)do { if ((__builtin_expect(!!(!(paths)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("paths"), "../src/shared/install.c", 1393
, __PRETTY_FUNCTION__); } while (0)
;
1394
1395 /* Was this unit already loaded? */
1396 if (info->type != _UNIT_FILE_TYPE_INVALID)
1397 return 0;
1398
1399 if (info->path)
1400 return unit_file_load_or_readlink(c, info, info->path, paths->root_dir, flags);
1401
1402 assert(info->name)do { if ((__builtin_expect(!!(!(info->name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("info->name"), "../src/shared/install.c"
, 1402, __PRETTY_FUNCTION__); } while (0)
;
1403
1404 if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
1405 r = unit_name_template(info->name, &template);
1406 if (r < 0)
1407 return r;
1408 }
1409
1410 STRV_FOREACH(p, paths->search_path)for ((p) = (paths->search_path); (p) && *(p); (p)++
)
{
1411 _cleanup_free___attribute__((cleanup(freep))) char *path = NULL((void*)0);
1412
1413 path = strjoin(*p, "/", info->name)strjoin_real((*p), "/", info->name, ((void*)0));
1414 if (!path)
1415 return -ENOMEM12;
1416
1417 r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
1418 if (r >= 0) {
1419 info->path = TAKE_PTR(path)({ typeof(path) _ptr_ = (path); (path) = ((void*)0); _ptr_; }
)
;
1420 result = r;
1421 found_unit = true1;
1422 break;
1423 } else if (!IN_SET(r, -ENOENT, -ENOTDIR, -EACCES)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){-2, -20, -13})/sizeof(int)]; switch(r) {
case -2: case -20: case -13: _found = 1; break; default: break
; } _found; })
)
1424 return r;
1425 }
1426
1427 if (!found_unit && template) {
1428
1429 /* Unit file doesn't exist, however instance
1430 * enablement was requested. We will check if it is
1431 * possible to load template unit file. */
1432
1433 STRV_FOREACH(p, paths->search_path)for ((p) = (paths->search_path); (p) && *(p); (p)++
)
{
1434 _cleanup_free___attribute__((cleanup(freep))) char *path = NULL((void*)0);
1435
1436 path = strjoin(*p, "/", template)strjoin_real((*p), "/", template, ((void*)0));
1437 if (!path)
1438 return -ENOMEM12;
1439
1440 r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
1441 if (r >= 0) {
1442 info->path = TAKE_PTR(path)({ typeof(path) _ptr_ = (path); (path) = ((void*)0); _ptr_; }
)
;
1443 result = r;
1444 found_unit = true1;
1445 break;
1446 } else if (!IN_SET(r, -ENOENT, -ENOTDIR, -EACCES)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){-2, -20, -13})/sizeof(int)]; switch(r) {
case -2: case -20: case -13: _found = 1; break; default: break
; } _found; })
)
1447 return r;
1448 }
1449 }
1450
1451 if (!found_unit) {
1452 log_debug("Cannot find unit %s%s%s.", info->name, template ? " or " : "", strempty(template))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 1452, __func__, "Cannot find unit %s%s%s."
, info->name, template ? " or " : "", strempty(template)) :
-abs(_e); })
;
1453 return -ENOENT2;
1454 }
1455
1456 if (info->type == UNIT_FILE_TYPE_MASKED)
1457 return result;
1458
1459 /* Search for drop-in directories */
1460
1461 dropin_dir_name = strjoina(info->name, ".d")({ const char *_appendees_[] = { info->name, ".d" }; char *
_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ <
__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
1462 STRV_FOREACH(p, paths->search_path)for ((p) = (paths->search_path); (p) && *(p); (p)++
)
{
1463 char *path;
1464
1465 path = path_join(NULL((void*)0), *p, dropin_dir_name);
1466 if (!path)
1467 return -ENOMEM12;
1468
1469 r = strv_consume(&dirs, path);
1470 if (r < 0)
1471 return r;
1472 }
1473
1474 if (template) {
1475 dropin_template_dir_name = strjoina(template, ".d")({ const char *_appendees_[] = { template, ".d" }; char *_d_,
*_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
1476 STRV_FOREACH(p, paths->search_path)for ((p) = (paths->search_path); (p) && *(p); (p)++
)
{
1477 char *path;
1478
1479 path = path_join(NULL((void*)0), *p, dropin_template_dir_name);
1480 if (!path)
1481 return -ENOMEM12;
1482
1483 r = strv_consume(&dirs, path);
1484 if (r < 0)
1485 return r;
1486 }
1487 }
1488
1489 /* Load drop-in conf files */
1490
1491 r = conf_files_list_strv(&files, ".conf", NULL((void*)0), 0, (const char**) dirs);
1492 if (r < 0)
1493 return log_debug_errno(r, "Failed to get list of conf files: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 1493, __func__, "Failed to get list of conf files: %m"
) : -abs(_e); })
;
1494
1495 STRV_FOREACH(p, files)for ((p) = (files); (p) && *(p); (p)++) {
1496 r = unit_file_load_or_readlink(c, info, *p, paths->root_dir, flags | SEARCH_DROPIN);
1497 if (r < 0)
1498 return log_debug_errno(r, "Failed to load conf file %s: %m", *p)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 1498, __func__, "Failed to load conf file %s: %m"
, *p) : -abs(_e); })
;
1499 }
1500
1501 return result;
1502}
1503
1504static int install_info_follow(
1505 InstallContext *c,
1506 UnitFileInstallInfo *i,
1507 const char *root_dir,
1508 SearchFlags flags,
1509 bool_Bool ignore_different_name) {
1510
1511 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/shared/install.c", 1511, __PRETTY_FUNCTION__
); } while (0)
;
1512 assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("i"), "../src/shared/install.c", 1512, __PRETTY_FUNCTION__
); } while (0)
;
1513
1514 if (i->type != UNIT_FILE_TYPE_SYMLINK)
1515 return -EINVAL22;
1516 if (!i->symlink_target)
1517 return -EINVAL22;
1518
1519 /* If the basename doesn't match, the caller should add a
1520 * complete new entry for this. */
1521
1522 if (!ignore_different_name && !streq(basename(i->symlink_target), i->name)(strcmp((basename(i->symlink_target)),(i->name)) == 0))
1523 return -EXDEV18;
1524
1525 free_and_replace(i->path, i->symlink_target)({ free(i->path); (i->path) = (i->symlink_target); (
i->symlink_target) = ((void*)0); 0; })
;
1526 i->type = _UNIT_FILE_TYPE_INVALID;
1527
1528 return unit_file_load_or_readlink(c, i, i->path, root_dir, flags);
1529}
1530
1531/**
1532 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1533 * target, maybe more than once. Propagate the instance name if present.
1534 */
1535static int install_info_traverse(
1536 UnitFileScope scope,
1537 InstallContext *c,
1538 const LookupPaths *paths,
1539 UnitFileInstallInfo *start,
1540 SearchFlags flags,
1541 UnitFileInstallInfo **ret) {
1542
1543 UnitFileInstallInfo *i;
1544 unsigned k = 0;
1545 int r;
1546
1547 assert(paths)do { if ((__builtin_expect(!!(!(paths)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("paths"), "../src/shared/install.c", 1547
, __PRETTY_FUNCTION__); } while (0)
;
1548 assert(start)do { if ((__builtin_expect(!!(!(start)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("start"), "../src/shared/install.c", 1548
, __PRETTY_FUNCTION__); } while (0)
;
1549 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/shared/install.c", 1549, __PRETTY_FUNCTION__
); } while (0)
;
1550
1551 r = unit_file_search(c, start, paths, flags);
1552 if (r < 0)
1553 return r;
1554
1555 i = start;
1556 while (i->type == UNIT_FILE_TYPE_SYMLINK) {
1557 /* Follow the symlink */
1558
1559 if (++k > UNIT_FILE_FOLLOW_SYMLINK_MAX64)
1560 return -ELOOP40;
1561
1562 if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS)) {
1563 r = path_is_config(paths, i->path, true1);
1564 if (r < 0)
1565 return r;
1566 if (r > 0)
1567 return -ELOOP40;
1568 }
1569
1570 r = install_info_follow(c, i, paths->root_dir, flags, false0);
1571 if (r == -EXDEV18) {
1572 _cleanup_free___attribute__((cleanup(freep))) char *buffer = NULL((void*)0);
1573 const char *bn;
1574
1575 /* Target has a different name, create a new
1576 * install info object for that, and continue
1577 * with that. */
1578
1579 bn = basename(i->symlink_target);
1580
1581 if (unit_name_is_valid(i->name, UNIT_NAME_INSTANCE) &&
1582 unit_name_is_valid(bn, UNIT_NAME_TEMPLATE)) {
1583
1584 _cleanup_free___attribute__((cleanup(freep))) char *instance = NULL((void*)0);
1585
1586 r = unit_name_to_instance(i->name, &instance);
1587 if (r < 0)
1588 return r;
1589
1590 r = unit_name_replace_instance(bn, instance, &buffer);
1591 if (r < 0)
1592 return r;
1593
1594 if (streq(buffer, i->name)(strcmp((buffer),(i->name)) == 0)) {
1595
1596 /* We filled in the instance, and the target stayed the same? If so, then let's
1597 * honour the link as it is. */
1598
1599 r = install_info_follow(c, i, paths->root_dir, flags, true1);
1600 if (r < 0)
1601 return r;
1602
1603 continue;
1604 }
1605
1606 bn = buffer;
1607 }
1608
1609 r = install_info_add(c, bn, NULL((void*)0), false0, &i);
1610 if (r < 0)
1611 return r;
1612
1613 /* Try again, with the new target we found. */
1614 r = unit_file_search(c, i, paths, flags);
1615 if (r == -ENOENT2)
1616 /* Translate error code to highlight this specific case */
1617 return -ENOLINK67;
1618 }
1619
1620 if (r < 0)
1621 return r;
1622 }
1623
1624 if (ret)
1625 *ret = i;
1626
1627 return 0;
1628}
1629
1630/**
1631 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1632 * or the name (otherwise). root_dir is prepended to the path.
1633 */
1634static int install_info_add_auto(
1635 InstallContext *c,
1636 const LookupPaths *paths,
1637 const char *name_or_path,
1638 UnitFileInstallInfo **ret) {
1639
1640 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/shared/install.c", 1640, __PRETTY_FUNCTION__
); } while (0)
;
1641 assert(name_or_path)do { if ((__builtin_expect(!!(!(name_or_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name_or_path"), "../src/shared/install.c"
, 1641, __PRETTY_FUNCTION__); } while (0)
;
1642
1643 if (path_is_absolute(name_or_path)) {
1644 const char *pp;
1645
1646 pp = prefix_roota(paths->root_dir, name_or_path)({ const char* _path = (name_or_path), *_root = (paths->root_dir
), *_ret; char *_p, *_n; size_t _l; while (_path[0] == '/' &&
_path[1] == '/') _path ++; if (empty_or_root(_root)) _ret = _path
; else { _l = strlen(_root) + 1 + strlen(_path) + 1; _n = __builtin_alloca
(_l); _p = stpcpy(_n, _root); while (_p > _n && _p
[-1] == '/') _p--; if (_path[0] != '/') *(_p++) = '/'; strcpy
(_p, _path); _ret = _n; } _ret; })
;
1647
1648 return install_info_add(c, NULL((void*)0), pp, false0, ret);
1649 } else
1650 return install_info_add(c, name_or_path, NULL((void*)0), false0, ret);
1651}
1652
1653static int install_info_discover(
1654 UnitFileScope scope,
1655 InstallContext *c,
1656 const LookupPaths *paths,
1657 const char *name,
1658 SearchFlags flags,
1659 UnitFileInstallInfo **ret,
1660 UnitFileChange **changes,
1661 size_t *n_changes) {
1662
1663 UnitFileInstallInfo *i;
1664 int r;
1665
1666 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/shared/install.c", 1666, __PRETTY_FUNCTION__
); } while (0)
;
1667 assert(paths)do { if ((__builtin_expect(!!(!(paths)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("paths"), "../src/shared/install.c", 1667
, __PRETTY_FUNCTION__); } while (0)
;
1668 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/shared/install.c", 1668
, __PRETTY_FUNCTION__); } while (0)
;
1669
1670 r = install_info_add_auto(c, paths, name, &i);
1671 if (r >= 0)
1672 r = install_info_traverse(scope, c, paths, i, flags, ret);
1673
1674 if (r < 0)
1675 unit_file_changes_add(changes, n_changes, r, name, NULL((void*)0));
1676 return r;
1677}
1678
1679static int install_info_discover_and_check(
1680 UnitFileScope scope,
1681 InstallContext *c,
1682 const LookupPaths *paths,
1683 const char *name,
1684 SearchFlags flags,
1685 UnitFileInstallInfo **ret,
1686 UnitFileChange **changes,
1687 size_t *n_changes) {
1688
1689 int r;
1690
1691 r = install_info_discover(scope, c, paths, name, flags, ret, changes, n_changes);
1692 if (r < 0)
1693 return r;
1694
1695 return install_info_may_process(ret ? *ret : NULL((void*)0), paths, changes, n_changes);
1696}
1697
1698static int install_info_symlink_alias(
1699 UnitFileInstallInfo *i,
1700 const LookupPaths *paths,
1701 const char *config_path,
1702 bool_Bool force,
1703 UnitFileChange **changes,
1704 size_t *n_changes) {
1705
1706 char **s;
1707 int r = 0, q;
1708
1709 assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("i"), "../src/shared/install.c", 1709, __PRETTY_FUNCTION__
); } while (0)
;
1710 assert(paths)do { if ((__builtin_expect(!!(!(paths)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("paths"), "../src/shared/install.c", 1710
, __PRETTY_FUNCTION__); } while (0)
;
1711 assert(config_path)do { if ((__builtin_expect(!!(!(config_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("config_path"), "../src/shared/install.c"
, 1711, __PRETTY_FUNCTION__); } while (0)
;
1712
1713 STRV_FOREACH(s, i->aliases)for ((s) = (i->aliases); (s) && *(s); (s)++) {
1714 _cleanup_free___attribute__((cleanup(freep))) char *alias_path = NULL((void*)0), *dst = NULL((void*)0);
1715
1716 q = install_full_printf(i, *s, &dst);
1717 if (q < 0)
1718 return q;
1719
1720 alias_path = path_make_absolute(dst, config_path);
1721 if (!alias_path)
1722 return -ENOMEM12;
1723
1724 q = create_symlink(paths, i->path, alias_path, force, changes, n_changes);
1725 if (r == 0)
1726 r = q;
1727 }
1728
1729 return r;
1730}
1731
1732static int install_info_symlink_wants(
1733 UnitFileInstallInfo *i,
1734 const LookupPaths *paths,
1735 const char *config_path,
1736 char **list,
1737 const char *suffix,
1738 UnitFileChange **changes,
1739 size_t *n_changes) {
1740
1741 _cleanup_free___attribute__((cleanup(freep))) char *buf = NULL((void*)0);
1742 const char *n;
1743 char **s;
1744 int r = 0, q;
1745
1746 assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("i"), "../src/shared/install.c", 1746, __PRETTY_FUNCTION__
); } while (0)
;
1747 assert(paths)do { if ((__builtin_expect(!!(!(paths)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("paths"), "../src/shared/install.c", 1747
, __PRETTY_FUNCTION__); } while (0)
;
1748 assert(config_path)do { if ((__builtin_expect(!!(!(config_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("config_path"), "../src/shared/install.c"
, 1748, __PRETTY_FUNCTION__); } while (0)
;
1749
1750 if (strv_isempty(list))
1751 return 0;
1752
1753 if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE) && i->default_instance) {
1754 UnitFileInstallInfo instance = {
1755 .type = _UNIT_FILE_TYPE_INVALID,
1756 };
1757 _cleanup_free___attribute__((cleanup(freep))) char *path = NULL((void*)0);
1758
1759 r = unit_name_replace_instance(i->name, i->default_instance, &buf);
1760 if (r < 0)
1761 return r;
1762
1763 instance.name = buf;
1764 r = unit_file_search(NULL((void*)0), &instance, paths, SEARCH_FOLLOW_CONFIG_SYMLINKS);
1765 if (r < 0)
1766 return r;
1767
1768 path = TAKE_PTR(instance.path)({ typeof(instance.path) _ptr_ = (instance.path); (instance.path
) = ((void*)0); _ptr_; })
;
1769
1770 if (instance.type == UNIT_FILE_TYPE_MASKED) {
1771 unit_file_changes_add(changes, n_changes, -ERFKILL132, path, NULL((void*)0));
1772 return -ERFKILL132;
1773 }
1774
1775 n = buf;
1776 } else
1777 n = i->name;
1778
1779 STRV_FOREACH(s, list)for ((s) = (list); (s) && *(s); (s)++) {
1780 _cleanup_free___attribute__((cleanup(freep))) char *path = NULL((void*)0), *dst = NULL((void*)0);
1781
1782 q = install_full_printf(i, *s, &dst);
1783 if (q < 0)
1784 return q;
1785
1786 if (!unit_name_is_valid(dst, UNIT_NAME_ANY)) {
1787 r = -EINVAL22;
1788 continue;
1789 }
1790
1791 path = strjoin(config_path, "/", dst, suffix, n)strjoin_real((config_path), "/", dst, suffix, n, ((void*)0));
1792 if (!path)
1793 return -ENOMEM12;
1794
1795 q = create_symlink(paths, i->path, path, true1, changes, n_changes);
1796 if (r == 0)
1797 r = q;
1798 }
1799
1800 return r;
1801}
1802
1803static int install_info_symlink_link(
1804 UnitFileInstallInfo *i,
1805 const LookupPaths *paths,
1806 const char *config_path,
1807 bool_Bool force,
1808 UnitFileChange **changes,
1809 size_t *n_changes) {
1810
1811 _cleanup_free___attribute__((cleanup(freep))) char *path = NULL((void*)0);
1812 int r;
1813
1814 assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("i"), "../src/shared/install.c", 1814, __PRETTY_FUNCTION__
); } while (0)
;
1815 assert(paths)do { if ((__builtin_expect(!!(!(paths)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("paths"), "../src/shared/install.c", 1815
, __PRETTY_FUNCTION__); } while (0)
;
1816 assert(config_path)do { if ((__builtin_expect(!!(!(config_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("config_path"), "../src/shared/install.c"
, 1816, __PRETTY_FUNCTION__); } while (0)
;
1817 assert(i->path)do { if ((__builtin_expect(!!(!(i->path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("i->path"), "../src/shared/install.c"
, 1817, __PRETTY_FUNCTION__); } while (0)
;
1818
1819 r = in_search_path(paths, i->path);
1820 if (r < 0)
1821 return r;
1822 if (r > 0)
1823 return 0;
1824
1825 path = strjoin(config_path, "/", i->name)strjoin_real((config_path), "/", i->name, ((void*)0));
1826 if (!path)
1827 return -ENOMEM12;
1828
1829 return create_symlink(paths, i->path, path, force, changes, n_changes);
1830}
1831
1832static int install_info_apply(
1833 UnitFileInstallInfo *i,
1834 const LookupPaths *paths,
1835 const char *config_path,
1836 bool_Bool force,
1837 UnitFileChange **changes,
1838 size_t *n_changes) {
1839
1840 int r, q;
1841
1842 assert(i)do { if ((__builtin_expect(!!(!(i)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("i"), "../src/shared/install.c", 1842, __PRETTY_FUNCTION__
); } while (0)
;
1843 assert(paths)do { if ((__builtin_expect(!!(!(paths)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("paths"), "../src/shared/install.c", 1843
, __PRETTY_FUNCTION__); } while (0)
;
1844 assert(config_path)do { if ((__builtin_expect(!!(!(config_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("config_path"), "../src/shared/install.c"
, 1844, __PRETTY_FUNCTION__); } while (0)
;
1845
1846 if (i->type != UNIT_FILE_TYPE_REGULAR)
1847 return 0;
1848
1849 r = install_info_symlink_alias(i, paths, config_path, force, changes, n_changes);
1850
1851 q = install_info_symlink_wants(i, paths, config_path, i->wanted_by, ".wants/", changes, n_changes);
1852 if (r == 0)
1853 r = q;
1854
1855 q = install_info_symlink_wants(i, paths, config_path, i->required_by, ".requires/", changes, n_changes);
1856 if (r == 0)
1857 r = q;
1858
1859 q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
1860 /* Do not count links to the unit file towards the "carries_install_info" count */
1861 if (r == 0 && q < 0)
1862 r = q;
1863
1864 return r;
1865}
1866
1867static int install_context_apply(
1868 UnitFileScope scope,
1869 InstallContext *c,
1870 const LookupPaths *paths,
1871 const char *config_path,
1872 bool_Bool force,
1873 SearchFlags flags,
1874 UnitFileChange **changes,
1875 size_t *n_changes) {
1876
1877 UnitFileInstallInfo *i;
1878 int r;
1879
1880 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/shared/install.c", 1880, __PRETTY_FUNCTION__
); } while (0)
;
1881 assert(paths)do { if ((__builtin_expect(!!(!(paths)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("paths"), "../src/shared/install.c", 1881
, __PRETTY_FUNCTION__); } while (0)
;
1882 assert(config_path)do { if ((__builtin_expect(!!(!(config_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("config_path"), "../src/shared/install.c"
, 1882, __PRETTY_FUNCTION__); } while (0)
;
1883
1884 if (ordered_hashmap_isempty(c->will_process))
1885 return 0;
1886
1887 r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops)internal_ordered_hashmap_ensure_allocated(&c->have_processed
, &string_hash_ops )
;
1888 if (r < 0)
1889 return r;
1890
1891 r = 0;
1892 while ((i = ordered_hashmap_first(c->will_process))) {
1893 int q;
1894
1895 q = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name);
1896 if (q < 0)
1897 return q;
1898
1899 r = install_info_traverse(scope, c, paths, i, flags, NULL((void*)0));
1900 if (r < 0) {
1901 unit_file_changes_add(changes, n_changes, r, i->name, NULL((void*)0));
1902 return r;
1903 }
1904
1905 /* We can attempt to process a masked unit when a different unit
1906 * that we were processing specifies it in Also=. */
1907 if (i->type == UNIT_FILE_TYPE_MASKED) {
1908 unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_MASKED, i->path, NULL((void*)0));
1909 if (r >= 0)
1910 /* Assume that something *could* have been enabled here,
1911 * avoid "empty [Install] section" warning. */
1912 r += 1;
1913 continue;
1914 }
1915
1916 if (i->type != UNIT_FILE_TYPE_REGULAR)
1917 continue;
1918
1919 q = install_info_apply(i, paths, config_path, force, changes, n_changes);
1920 if (r >= 0) {
1921 if (q < 0)
1922 r = q;
1923 else
1924 r += q;
1925 }
1926 }
1927
1928 return r;
1929}
1930
1931static int install_context_mark_for_removal(
1932 UnitFileScope scope,
1933 InstallContext *c,
1934 const LookupPaths *paths,
1935 Set **remove_symlinks_to,
1936 UnitFileChange **changes,
1937 size_t *n_changes) {
1938
1939 UnitFileInstallInfo *i;
1940 int r;
1941
1942 assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("c"), "../src/shared/install.c", 1942, __PRETTY_FUNCTION__
); } while (0)
;
1943 assert(paths)do { if ((__builtin_expect(!!(!(paths)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("paths"), "../src/shared/install.c", 1943
, __PRETTY_FUNCTION__); } while (0)
;
1944
1945 /* Marks all items for removal */
1946
1947 if (ordered_hashmap_isempty(c->will_process))
1948 return 0;
1949
1950 r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops)internal_ordered_hashmap_ensure_allocated(&c->have_processed
, &string_hash_ops )
;
1951 if (r < 0)
1952 return r;
1953
1954 while ((i = ordered_hashmap_first(c->will_process))) {
1955
1956 r = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name);
1957 if (r < 0)
1958 return r;
1959
1960 r = install_info_traverse(scope, c, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL((void*)0));
1961 if (r == -ENOLINK67) {
1962 log_debug_errno(r, "Name %s leads to a dangling symlink, removing name.", i->name)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 1962, __func__, "Name %s leads to a dangling symlink, removing name."
, i->name) : -abs(_e); })
;
1963 unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_DANGLING, i->path ?: i->name, NULL((void*)0));
1964 } else if (r == -ENOENT2) {
1965
1966 if (i->auxiliary) /* some unit specified in Also= or similar is missing */
1967 log_debug_errno(r, "Auxiliary unit of %s not found, removing name.", i->name)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 1967, __func__, "Auxiliary unit of %s not found, removing name."
, i->name) : -abs(_e); })
;
1968 else {
1969 log_debug_errno(r, "Unit %s not found, removing name.", i->name)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 1969, __func__, "Unit %s not found, removing name."
, i->name) : -abs(_e); })
;
1970 unit_file_changes_add(changes, n_changes, r, i->path ?: i->name, NULL((void*)0));
1971 }
1972
1973 } else if (r < 0) {
1974 log_debug_errno(r, "Failed to find unit %s, removing name: %m", i->name)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 1974, __func__, "Failed to find unit %s, removing name: %m"
, i->name) : -abs(_e); })
;
1975 unit_file_changes_add(changes, n_changes, r, i->path ?: i->name, NULL((void*)0));
1976 } else if (i->type == UNIT_FILE_TYPE_MASKED) {
1977 log_debug("Unit file %s is masked, ignoring.", i->name)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 1977, __func__, "Unit file %s is masked, ignoring."
, i->name) : -abs(_e); })
;
1978 unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_MASKED, i->path ?: i->name, NULL((void*)0));
1979 continue;
1980 } else if (i->type != UNIT_FILE_TYPE_REGULAR) {
1981 log_debug("Unit %s has type %s, ignoring.", i->name, unit_file_type_to_string(i->type) ?: "invalid")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 1981, __func__, "Unit %s has type %s, ignoring."
, i->name, unit_file_type_to_string(i->type) ?: "invalid"
) : -abs(_e); })
;
1982 continue;
1983 }
1984
1985 r = mark_symlink_for_removal(remove_symlinks_to, i->name);
1986 if (r < 0)
1987 return r;
1988 }
1989
1990 return 0;
1991}
1992
1993int unit_file_mask(
1994 UnitFileScope scope,
1995 UnitFileFlags flags,
1996 const char *root_dir,
1997 char **files,
1998 UnitFileChange **changes,
1999 size_t *n_changes) {
2000
2001 _cleanup_(lookup_paths_free)__attribute__((cleanup(lookup_paths_free))) LookupPaths paths = {};
2002 const char *config_path;
2003 char **i;
2004 int r;
2005
2006 assert(scope >= 0)do { if ((__builtin_expect(!!(!(scope >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("scope >= 0"), "../src/shared/install.c"
, 2006, __PRETTY_FUNCTION__); } while (0)
;
2007 assert(scope < _UNIT_FILE_SCOPE_MAX)do { if ((__builtin_expect(!!(!(scope < _UNIT_FILE_SCOPE_MAX
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("scope < _UNIT_FILE_SCOPE_MAX"
), "../src/shared/install.c", 2007, __PRETTY_FUNCTION__); } while
(0)
;
2008
2009 r = lookup_paths_init(&paths, scope, 0, root_dir);
2010 if (r < 0)
2011 return r;
2012
2013 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
2014 if (!config_path)
2015 return -ENXIO6;
2016
2017 STRV_FOREACH(i, files)for ((i) = (files); (i) && *(i); (i)++) {
2018 _cleanup_free___attribute__((cleanup(freep))) char *path = NULL((void*)0);
2019 int q;
2020
2021 if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) {
2022 if (r == 0)
2023 r = -EINVAL22;
2024 continue;
2025 }
2026
2027 path = path_make_absolute(*i, config_path);
2028 if (!path)
2029 return -ENOMEM12;
2030
2031 q = create_symlink(&paths, "/dev/null", path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
2032 if (q < 0 && r >= 0)
2033 r = q;
2034 }
2035
2036 return r;
2037}
2038
2039int unit_file_unmask(
2040 UnitFileScope scope,
2041 UnitFileFlags flags,
2042 const char *root_dir,
2043 char **files,
2044 UnitFileChange **changes,
2045 size_t *n_changes) {
2046
2047 _cleanup_(lookup_paths_free)__attribute__((cleanup(lookup_paths_free))) LookupPaths paths = {};
2048 _cleanup_set_free_free___attribute__((cleanup(set_free_freep))) Set *remove_symlinks_to = NULL((void*)0);
2049 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **todo = NULL((void*)0);
2050 size_t n_todo = 0, n_allocated = 0;
2051 const char *config_path;
2052 char **i;
2053 bool_Bool dry_run = !!(flags & UNIT_FILE_DRY_RUN);
2054 int r, q;
2055
2056 assert(scope >= 0)do { if ((__builtin_expect(!!(!(scope >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("scope >= 0"), "../src/shared/install.c"
, 2056, __PRETTY_FUNCTION__); } while (0)
;
2057 assert(scope < _UNIT_FILE_SCOPE_MAX)do { if ((__builtin_expect(!!(!(scope < _UNIT_FILE_SCOPE_MAX
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("scope < _UNIT_FILE_SCOPE_MAX"
), "../src/shared/install.c", 2057, __PRETTY_FUNCTION__); } while
(0)
;
2058
2059 r = lookup_paths_init(&paths, scope, 0, root_dir);
2060 if (r < 0)
2061 return r;
2062
2063 STRV_FOREACH(i, files)for ((i) = (files); (i) && *(i); (i)++) {
2064 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
2065 return -EINVAL22;
2066
2067 FOREACH_STRING(config_path, paths.runtime_config, paths.persistent_config)for (char **_l = ({ char **_ll = ((char**) ((const char*[]) {
paths.runtime_config, paths.persistent_config, ((void*)0) })
); config_path = _ll ? _ll[0] : ((void*)0); _ll; }); _l &&
*_l; config_path = ({ _l ++; _l[0]; }))
{
2068 _cleanup_free___attribute__((cleanup(freep))) char *path = NULL((void*)0);
2069
2070 path = path_make_absolute(*i, config_path);
2071 if (!path)
2072 return -ENOMEM12;
2073
2074 r = null_or_empty_path(path);
2075 if (r == -ENOENT2)
2076 continue;
2077 if (r < 0)
2078 return r;
2079 if (r == 0)
2080 continue;
2081
2082 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2)greedy_realloc0((void**) &(todo), &(n_allocated), (n_todo
+ 2), sizeof((todo)[0]))
)
2083 return -ENOMEM12;
2084
2085 todo[n_todo] = strdup(*i);
2086 if (!todo[n_todo])
2087 return -ENOMEM12;
2088
2089 n_todo++;
2090 }
2091 }
2092
2093 strv_uniq(todo);
2094
2095 r = 0;
2096 FOREACH_STRING(config_path, paths.runtime_config, paths.persistent_config)for (char **_l = ({ char **_ll = ((char**) ((const char*[]) {
paths.runtime_config, paths.persistent_config, ((void*)0) })
); config_path = _ll ? _ll[0] : ((void*)0); _ll; }); _l &&
*_l; config_path = ({ _l ++; _l[0]; }))
{
2097 STRV_FOREACH(i, todo)for ((i) = (todo); (i) && *(i); (i)++) {
2098 _cleanup_free___attribute__((cleanup(freep))) char *path = NULL((void*)0);
2099 const char *rp;
2100
2101 path = path_make_absolute(*i, config_path);
2102 if (!path)
2103 return -ENOMEM12;
2104
2105 if (!dry_run && unlink(path) < 0) {
2106 if (errno(*__errno_location ()) != ENOENT2) {
2107 if (r >= 0)
2108 r = -errno(*__errno_location ());
2109 unit_file_changes_add(changes, n_changes, -errno(*__errno_location ()), path, NULL((void*)0));
2110 }
2111
2112 continue;
2113 }
2114
2115 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL((void*)0));
2116
2117 rp = skip_root(&paths, path);
2118 q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: path);
2119 if (q < 0)
2120 return q;
2121 }
2122
2123 q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, dry_run, changes, n_changes);
2124 if (r >= 0)
2125 r = q;
2126 }
2127
2128 return r;
2129}
2130
2131int unit_file_link(
2132 UnitFileScope scope,
2133 UnitFileFlags flags,
2134 const char *root_dir,
2135 char **files,
2136 UnitFileChange **changes,
2137 size_t *n_changes) {
2138
2139 _cleanup_(lookup_paths_free)__attribute__((cleanup(lookup_paths_free))) LookupPaths paths = {};
2140 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **todo = NULL((void*)0);
2141 size_t n_todo = 0, n_allocated = 0;
2142 const char *config_path;
2143 char **i;
2144 int r, q;
2145
2146 assert(scope >= 0)do { if ((__builtin_expect(!!(!(scope >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("scope >= 0"), "../src/shared/install.c"
, 2146, __PRETTY_FUNCTION__); } while (0)
;
2147 assert(scope < _UNIT_FILE_SCOPE_MAX)do { if ((__builtin_expect(!!(!(scope < _UNIT_FILE_SCOPE_MAX
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("scope < _UNIT_FILE_SCOPE_MAX"
), "../src/shared/install.c", 2147, __PRETTY_FUNCTION__); } while
(0)
;
2148
2149 r = lookup_paths_init(&paths, scope, 0, root_dir);
2150 if (r < 0)
2151 return r;
2152
2153 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
2154 if (!config_path)
2155 return -ENXIO6;
2156
2157 STRV_FOREACH(i, files)for ((i) = (files); (i) && *(i); (i)++) {
2158 _cleanup_free___attribute__((cleanup(freep))) char *full = NULL((void*)0);
2159 struct stat st;
2160 char *fn;
2161
2162 if (!path_is_absolute(*i))
2163 return -EINVAL22;
2164
2165 fn = basename(*i);
2166 if (!unit_name_is_valid(fn, UNIT_NAME_ANY))
2167 return -EINVAL22;
2168
2169 full = prefix_root(paths.root_dir, *i);
2170 if (!full)
2171 return -ENOMEM12;
2172
2173 if (lstat(full, &st) < 0)
2174 return -errno(*__errno_location ());
2175 r = stat_verify_regular(&st);
2176 if (r < 0)
2177 return r;
2178
2179 q = in_search_path(&paths, *i);
2180 if (q < 0)
2181 return q;
2182 if (q > 0)
2183 continue;
2184
2185 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2)greedy_realloc0((void**) &(todo), &(n_allocated), (n_todo
+ 2), sizeof((todo)[0]))
)
2186 return -ENOMEM12;
2187
2188 todo[n_todo] = strdup(*i);
2189 if (!todo[n_todo])
2190 return -ENOMEM12;
2191
2192 n_todo++;
2193 }
2194
2195 strv_uniq(todo);
2196
2197 r = 0;
2198 STRV_FOREACH(i, todo)for ((i) = (todo); (i) && *(i); (i)++) {
2199 _cleanup_free___attribute__((cleanup(freep))) char *new_path = NULL((void*)0);
2200
2201 new_path = path_make_absolute(basename(*i), config_path);
2202 if (!new_path)
2203 return -ENOMEM12;
2204
2205 q = create_symlink(&paths, *i, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
2206 if (q < 0 && r >= 0)
2207 r = q;
2208 }
2209
2210 return r;
2211}
2212
2213static int path_shall_revert(const LookupPaths *paths, const char *path) {
2214 int r;
2215
2216 assert(paths)do { if ((__builtin_expect(!!(!(paths)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("paths"), "../src/shared/install.c", 2216
, __PRETTY_FUNCTION__); } while (0)
;
2217 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/shared/install.c", 2217
, __PRETTY_FUNCTION__); } while (0)
;
2218
2219 /* Checks whether the path is one where the drop-in directories shall be removed. */
2220
2221 r = path_is_config(paths, path, true1);
2222 if (r != 0)
2223 return r;
2224
2225 r = path_is_control(paths, path);
2226 if (r != 0)
2227 return r;
2228
2229 return path_is_transient(paths, path);
2230}
2231
2232int unit_file_revert(
2233 UnitFileScope scope,
2234 const char *root_dir,
2235 char **files,
2236 UnitFileChange **changes,
2237 size_t *n_changes) {
2238
2239 _cleanup_set_free_free___attribute__((cleanup(set_free_freep))) Set *remove_symlinks_to = NULL((void*)0);
2240 _cleanup_(lookup_paths_free)__attribute__((cleanup(lookup_paths_free))) LookupPaths paths = {};
2241 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **todo = NULL((void*)0);
2242 size_t n_todo = 0, n_allocated = 0;
2243 char **i;
2244 int r, q;
2245
2246 /* Puts a unit file back into vendor state. This means:
2247 *
2248 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2249 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2250 *
2251 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2252 * "config", but not in "transient" or "control" or even "generated").
2253 *
2254 * We remove all that in both the runtime and the persistent directories, if that applies.
2255 */
2256
2257 r = lookup_paths_init(&paths, scope, 0, root_dir);
2258 if (r < 0)
2259 return r;
2260
2261 STRV_FOREACH(i, files)for ((i) = (files); (i) && *(i); (i)++) {
2262 bool_Bool has_vendor = false0;
2263 char **p;
2264
2265 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
2266 return -EINVAL22;
2267
2268 STRV_FOREACH(p, paths.search_path)for ((p) = (paths.search_path); (p) && *(p); (p)++) {
2269 _cleanup_free___attribute__((cleanup(freep))) char *path = NULL((void*)0), *dropin = NULL((void*)0);
2270 struct stat st;
2271
2272 path = path_make_absolute(*i, *p);
2273 if (!path)
2274 return -ENOMEM12;
2275
2276 r = lstat(path, &st);
2277 if (r < 0) {
2278 if (errno(*__errno_location ()) != ENOENT2)
2279 return -errno(*__errno_location ());
2280 } else if (S_ISREG(st.st_mode)((((st.st_mode)) & 0170000) == (0100000))) {
2281 /* Check if there's a vendor version */
2282 r = path_is_vendor(&paths, path);
2283 if (r < 0)
2284 return r;
2285 if (r > 0)
2286 has_vendor = true1;
2287 }
2288
2289 dropin = strappend(path, ".d");
2290 if (!dropin)
2291 return -ENOMEM12;
2292
2293 r = lstat(dropin, &st);
2294 if (r < 0) {
2295 if (errno(*__errno_location ()) != ENOENT2)
2296 return -errno(*__errno_location ());
2297 } else if (S_ISDIR(st.st_mode)((((st.st_mode)) & 0170000) == (0040000))) {
2298 /* Remove the drop-ins */
2299 r = path_shall_revert(&paths, dropin);
2300 if (r < 0)
2301 return r;
2302 if (r > 0) {
2303 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2)greedy_realloc0((void**) &(todo), &(n_allocated), (n_todo
+ 2), sizeof((todo)[0]))
)
2304 return -ENOMEM12;
2305
2306 todo[n_todo++] = TAKE_PTR(dropin)({ typeof(dropin) _ptr_ = (dropin); (dropin) = ((void*)0); _ptr_
; })
;
2307 }
2308 }
2309 }
2310
2311 if (!has_vendor)
2312 continue;
2313
2314 /* OK, there's a vendor version, hence drop all configuration versions */
2315 STRV_FOREACH(p, paths.search_path)for ((p) = (paths.search_path); (p) && *(p); (p)++) {
2316 _cleanup_free___attribute__((cleanup(freep))) char *path = NULL((void*)0);
2317 struct stat st;
2318
2319 path = path_make_absolute(*i, *p);
2320 if (!path)
2321 return -ENOMEM12;
2322
2323 r = lstat(path, &st);
2324 if (r < 0) {
2325 if (errno(*__errno_location ()) != ENOENT2)
2326 return -errno(*__errno_location ());
2327 } else if (S_ISREG(st.st_mode)((((st.st_mode)) & 0170000) == (0100000)) || S_ISLNK(st.st_mode)((((st.st_mode)) & 0170000) == (0120000))) {
2328 r = path_is_config(&paths, path, true1);
2329 if (r < 0)
2330 return r;
2331 if (r > 0) {
2332 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2)greedy_realloc0((void**) &(todo), &(n_allocated), (n_todo
+ 2), sizeof((todo)[0]))
)
2333 return -ENOMEM12;
2334
2335 todo[n_todo++] = TAKE_PTR(path)({ typeof(path) _ptr_ = (path); (path) = ((void*)0); _ptr_; }
)
;
2336 }
2337 }
2338 }
2339 }
2340
2341 strv_uniq(todo);
2342
2343 r = 0;
2344 STRV_FOREACH(i, todo)for ((i) = (todo); (i) && *(i); (i)++) {
2345 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **fs = NULL((void*)0);
2346 const char *rp;
2347 char **j;
2348
2349 (void) get_files_in_directory(*i, &fs);
2350
2351 q = rm_rf(*i, REMOVE_ROOT|REMOVE_PHYSICAL);
2352 if (q < 0 && q != -ENOENT2 && r >= 0) {
2353 r = q;
2354 continue;
2355 }
2356
2357 STRV_FOREACH(j, fs)for ((j) = (fs); (j) && *(j); (j)++) {
2358 _cleanup_free___attribute__((cleanup(freep))) char *t = NULL((void*)0);
2359
2360 t = strjoin(*i, "/", *j)strjoin_real((*i), "/", *j, ((void*)0));
2361 if (!t)
2362 return -ENOMEM12;
2363
2364 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, t, NULL((void*)0));
2365 }
2366
2367 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, *i, NULL((void*)0));
2368
2369 rp = skip_root(&paths, *i);
2370 q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: *i);
2371 if (q < 0)
2372 return q;
2373 }
2374
2375 q = remove_marked_symlinks(remove_symlinks_to, paths.runtime_config, &paths, false0, changes, n_changes);
2376 if (r >= 0)
2377 r = q;
2378
2379 q = remove_marked_symlinks(remove_symlinks_to, paths.persistent_config, &paths, false0, changes, n_changes);
2380 if (r >= 0)
2381 r = q;
2382
2383 return r;
2384}
2385
2386int unit_file_add_dependency(
2387 UnitFileScope scope,
2388 UnitFileFlags flags,
2389 const char *root_dir,
2390 char **files,
2391 const char *target,
2392 UnitDependency dep,
2393 UnitFileChange **changes,
2394 size_t *n_changes) {
2395
2396 _cleanup_(lookup_paths_free)__attribute__((cleanup(lookup_paths_free))) LookupPaths paths = {};
2397 _cleanup_(install_context_done)__attribute__((cleanup(install_context_done))) InstallContext c = {};
2398 UnitFileInstallInfo *i, *target_info;
2399 const char *config_path;
2400 char **f;
2401 int r;
2402
2403 assert(scope >= 0)do { if ((__builtin_expect(!!(!(scope >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("scope >= 0"), "../src/shared/install.c"
, 2403, __PRETTY_FUNCTION__); } while (0)
;
2404 assert(scope < _UNIT_FILE_SCOPE_MAX)do { if ((__builtin_expect(!!(!(scope < _UNIT_FILE_SCOPE_MAX
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("scope < _UNIT_FILE_SCOPE_MAX"
), "../src/shared/install.c", 2404, __PRETTY_FUNCTION__); } while
(0)
;
2405 assert(target)do { if ((__builtin_expect(!!(!(target)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("target"), "../src/shared/install.c", 2405
, __PRETTY_FUNCTION__); } while (0)
;
2406
2407 if (!IN_SET(dep, UNIT_WANTS, UNIT_REQUIRES)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){UNIT_WANTS, UNIT_REQUIRES})/sizeof(int)]
; switch(dep) { case UNIT_WANTS: case UNIT_REQUIRES: _found =
1; break; default: break; } _found; })
)
2408 return -EINVAL22;
2409
2410 if (!unit_name_is_valid(target, UNIT_NAME_ANY))
2411 return -EINVAL22;
2412
2413 r = lookup_paths_init(&paths, scope, 0, root_dir);
2414 if (r < 0)
2415 return r;
2416
2417 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
2418 if (!config_path)
2419 return -ENXIO6;
2420
2421 r = install_info_discover_and_check(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2422 &target_info, changes, n_changes);
2423 if (r < 0)
2424 return r;
2425
2426 assert(target_info->type == UNIT_FILE_TYPE_REGULAR)do { if ((__builtin_expect(!!(!(target_info->type == UNIT_FILE_TYPE_REGULAR
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("target_info->type == UNIT_FILE_TYPE_REGULAR"
), "../src/shared/install.c", 2426, __PRETTY_FUNCTION__); } while
(0)
;
2427
2428 STRV_FOREACH(f, files)for ((f) = (files); (f) && *(f); (f)++) {
2429 char ***l;
2430
2431 r = install_info_discover_and_check(scope, &c, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2432 &i, changes, n_changes);
2433 if (r < 0)
2434 return r;
2435
2436 assert(i->type == UNIT_FILE_TYPE_REGULAR)do { if ((__builtin_expect(!!(!(i->type == UNIT_FILE_TYPE_REGULAR
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("i->type == UNIT_FILE_TYPE_REGULAR"
), "../src/shared/install.c", 2436, __PRETTY_FUNCTION__); } while
(0)
;
2437
2438 /* We didn't actually load anything from the unit
2439 * file, but instead just add in our new symlink to
2440 * create. */
2441
2442 if (dep == UNIT_WANTS)
2443 l = &i->wanted_by;
2444 else
2445 l = &i->required_by;
2446
2447 strv_free(*l);
2448 *l = strv_new(target_info->name, NULL((void*)0));
2449 if (!*l)
2450 return -ENOMEM12;
2451 }
2452
2453 return install_context_apply(scope, &c, &paths, config_path, !!(flags & UNIT_FILE_FORCE), SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes);
2454}
2455
2456int unit_file_enable(
2457 UnitFileScope scope,
2458 UnitFileFlags flags,
2459 const char *root_dir,
2460 char **files,
2461 UnitFileChange **changes,
2462 size_t *n_changes) {
2463
2464 _cleanup_(lookup_paths_free)__attribute__((cleanup(lookup_paths_free))) LookupPaths paths = {};
2465 _cleanup_(install_context_done)__attribute__((cleanup(install_context_done))) InstallContext c = {};
2466 const char *config_path;
2467 UnitFileInstallInfo *i;
2468 char **f;
2469 int r;
2470
2471 assert(scope >= 0)do { if ((__builtin_expect(!!(!(scope >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("scope >= 0"), "../src/shared/install.c"
, 2471, __PRETTY_FUNCTION__); } while (0)
;
2472 assert(scope < _UNIT_FILE_SCOPE_MAX)do { if ((__builtin_expect(!!(!(scope < _UNIT_FILE_SCOPE_MAX
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("scope < _UNIT_FILE_SCOPE_MAX"
), "../src/shared/install.c", 2472, __PRETTY_FUNCTION__); } while
(0)
;
2473
2474 r = lookup_paths_init(&paths, scope, 0, root_dir);
2475 if (r < 0)
2476 return r;
2477
2478 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
2479 if (!config_path)
2480 return -ENXIO6;
2481
2482 STRV_FOREACH(f, files)for ((f) = (files); (f) && *(f); (f)++) {
2483 r = install_info_discover_and_check(scope, &c, &paths, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
2484 &i, changes, n_changes);
2485 if (r < 0)
2486 return r;
2487
2488 assert(i->type == UNIT_FILE_TYPE_REGULAR)do { if ((__builtin_expect(!!(!(i->type == UNIT_FILE_TYPE_REGULAR
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("i->type == UNIT_FILE_TYPE_REGULAR"
), "../src/shared/install.c", 2488, __PRETTY_FUNCTION__); } while
(0)
;
2489 }
2490
2491 /* This will return the number of symlink rules that were
2492 supposed to be created, not the ones actually created. This
2493 is useful to determine whether the passed files had any
2494 installation data at all. */
2495
2496 return install_context_apply(scope, &c, &paths, config_path, !!(flags & UNIT_FILE_FORCE), SEARCH_LOAD, changes, n_changes);
2497}
2498
2499int unit_file_disable(
2500 UnitFileScope scope,
2501 UnitFileFlags flags,
2502 const char *root_dir,
2503 char **files,
2504 UnitFileChange **changes,
2505 size_t *n_changes) {
2506
2507 _cleanup_(lookup_paths_free)__attribute__((cleanup(lookup_paths_free))) LookupPaths paths = {};
2508 _cleanup_(install_context_done)__attribute__((cleanup(install_context_done))) InstallContext c = {};
2509 _cleanup_set_free_free___attribute__((cleanup(set_free_freep))) Set *remove_symlinks_to = NULL((void*)0);
2510 bool_Bool dry_run = !!(flags & UNIT_FILE_DRY_RUN);
2511 const char *config_path;
2512 char **i;
2513 int r;
2514
2515 assert(scope >= 0)do { if ((__builtin_expect(!!(!(scope >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("scope >= 0"), "../src/shared/install.c"
, 2515, __PRETTY_FUNCTION__); } while (0)
;
2516 assert(scope < _UNIT_FILE_SCOPE_MAX)do { if ((__builtin_expect(!!(!(scope < _UNIT_FILE_SCOPE_MAX
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("scope < _UNIT_FILE_SCOPE_MAX"
), "../src/shared/install.c", 2516, __PRETTY_FUNCTION__); } while
(0)
;
2517
2518 r = lookup_paths_init(&paths, scope, 0, root_dir);
2519 if (r < 0)
2520 return r;
2521
2522 STRV_FOREACH(i, files)for ((i) = (files); (i) && *(i); (i)++) {
2523 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
2524 return -EINVAL22;
2525
2526 r = install_info_add(&c, *i, NULL((void*)0), false0, NULL((void*)0));
2527 if (r < 0)
2528 return r;
2529 }
2530
2531 r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, changes, n_changes);
2532 if (r < 0)
2533 return r;
2534
2535 FOREACH_STRING(config_path, paths.runtime_config, paths.persistent_config)for (char **_l = ({ char **_ll = ((char**) ((const char*[]) {
paths.runtime_config, paths.persistent_config, ((void*)0) })
); config_path = _ll ? _ll[0] : ((void*)0); _ll; }); _l &&
*_l; config_path = ({ _l ++; _l[0]; }))
{
2536 r = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, dry_run, changes, n_changes);
2537 if (r < 0)
2538 return r;
2539 }
2540
2541 return 0;
2542}
2543
2544int unit_file_reenable(
2545 UnitFileScope scope,
2546 UnitFileFlags flags,
2547 const char *root_dir,
2548 char **files,
2549 UnitFileChange **changes,
2550 size_t *n_changes) {
2551
2552 char **n;
2553 int r;
2554 size_t l, i;
2555
2556 /* First, we invoke the disable command with only the basename... */
2557 l = strv_length(files);
2558 n = newa(char*, l+1)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(char*), l+1))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("!size_multiply_overflow(sizeof(char*), l+1)"), "../src/shared/install.c"
, 2558, __PRETTY_FUNCTION__); } while (0); (char**) __builtin_alloca
(sizeof(char*)*(l+1)); })
;
2559 for (i = 0; i < l; i++)
2560 n[i] = basename(files[i]);
2561 n[i] = NULL((void*)0);
2562
2563 r = unit_file_disable(scope, flags, root_dir, n, changes, n_changes);
2564 if (r < 0)
2565 return r;
2566
2567 /* But the enable command with the full name */
2568 return unit_file_enable(scope, flags, root_dir, files, changes, n_changes);
2569}
2570
2571int unit_file_set_default(
2572 UnitFileScope scope,
2573 UnitFileFlags flags,
2574 const char *root_dir,
2575 const char *name,
2576 UnitFileChange **changes,
2577 size_t *n_changes) {
2578
2579 _cleanup_(lookup_paths_free)__attribute__((cleanup(lookup_paths_free))) LookupPaths paths = {};
2580 _cleanup_(install_context_done)__attribute__((cleanup(install_context_done))) InstallContext c = {};
2581 UnitFileInstallInfo *i;
2582 const char *new_path;
2583 int r;
2584
2585 assert(scope >= 0)do { if ((__builtin_expect(!!(!(scope >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("scope >= 0"), "../src/shared/install.c"
, 2585, __PRETTY_FUNCTION__); } while (0)
;
2586 assert(scope < _UNIT_FILE_SCOPE_MAX)do { if ((__builtin_expect(!!(!(scope < _UNIT_FILE_SCOPE_MAX
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("scope < _UNIT_FILE_SCOPE_MAX"
), "../src/shared/install.c", 2586, __PRETTY_FUNCTION__); } while
(0)
;
2587 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/shared/install.c", 2587
, __PRETTY_FUNCTION__); } while (0)
;
2588
2589 if (unit_name_to_type(name) != UNIT_TARGET) /* this also validates the name */
2590 return -EINVAL22;
2591 if (streq(name, SPECIAL_DEFAULT_TARGET)(strcmp((name),("default.target")) == 0))
2592 return -EINVAL22;
2593
2594 r = lookup_paths_init(&paths, scope, 0, root_dir);
2595 if (r < 0)
2596 return r;
2597
2598 r = install_info_discover_and_check(scope, &c, &paths, name, 0, &i, changes, n_changes);
2599 if (r < 0)
2600 return r;
2601
2602 new_path = strjoina(paths.persistent_config, "/" SPECIAL_DEFAULT_TARGET)({ const char *_appendees_[] = { paths.persistent_config, "/"
"default.target" }; char *_d_, *_p_; size_t _len_ = 0; size_t
_i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _len_ += strlen
(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1);
for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr(
!__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
2603 return create_symlink(&paths, i->path, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
2604}
2605
2606int unit_file_get_default(
2607 UnitFileScope scope,
2608 const char *root_dir,
2609 char **name) {
2610
2611 _cleanup_(lookup_paths_free)__attribute__((cleanup(lookup_paths_free))) LookupPaths paths = {};
2612 _cleanup_(install_context_done)__attribute__((cleanup(install_context_done))) InstallContext c = {};
2613 UnitFileInstallInfo *i;
2614 char *n;
2615 int r;
2616
2617 assert(scope >= 0)do { if ((__builtin_expect(!!(!(scope >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("scope >= 0"), "../src/shared/install.c"
, 2617, __PRETTY_FUNCTION__); } while (0)
;
2618 assert(scope < _UNIT_FILE_SCOPE_MAX)do { if ((__builtin_expect(!!(!(scope < _UNIT_FILE_SCOPE_MAX
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("scope < _UNIT_FILE_SCOPE_MAX"
), "../src/shared/install.c", 2618, __PRETTY_FUNCTION__); } while
(0)
;
2619 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/shared/install.c", 2619
, __PRETTY_FUNCTION__); } while (0)
;
2620
2621 r = lookup_paths_init(&paths, scope, 0, root_dir);
2622 if (r < 0)
2623 return r;
2624
2625 r = install_info_discover(scope, &c, &paths, SPECIAL_DEFAULT_TARGET"default.target", SEARCH_FOLLOW_CONFIG_SYMLINKS,
2626 &i, NULL((void*)0), NULL((void*)0));
2627 if (r < 0)
2628 return r;
2629 r = install_info_may_process(i, &paths, NULL((void*)0), 0);
2630 if (r < 0)
2631 return r;
2632
2633 n = strdup(i->name);
2634 if (!n)
2635 return -ENOMEM12;
2636
2637 *name = n;
2638 return 0;
2639}
2640
2641int unit_file_lookup_state(
2642 UnitFileScope scope,
2643 const LookupPaths *paths,
2644 const char *name,
2645 UnitFileState *ret) {
2646
2647 _cleanup_(install_context_done)__attribute__((cleanup(install_context_done))) InstallContext c = {};
2648 UnitFileInstallInfo *i;
2649 UnitFileState state;
2650 int r;
2651
2652 assert(paths)do { if ((__builtin_expect(!!(!(paths)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("paths"), "../src/shared/install.c", 2652
, __PRETTY_FUNCTION__); } while (0)
;
2653 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/shared/install.c", 2653
, __PRETTY_FUNCTION__); } while (0)
;
2654
2655 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
2656 return -EINVAL22;
2657
2658 r = install_info_discover(scope, &c, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
2659 &i, NULL((void*)0), NULL((void*)0));
2660 if (r < 0)
2661 return r;
2662
2663 /* Shortcut things, if the caller just wants to know if this unit exists. */
2664 if (!ret)
2665 return 0;
2666
2667 switch (i->type) {
2668
2669 case UNIT_FILE_TYPE_MASKED:
2670 r = path_is_runtime(paths, i->path, true1);
2671 if (r < 0)
2672 return r;
2673
2674 state = r > 0 ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
2675 break;
2676
2677 case UNIT_FILE_TYPE_REGULAR:
2678 r = path_is_generator(paths, i->path);
2679 if (r < 0)
2680 return r;
2681 if (r > 0) {
2682 state = UNIT_FILE_GENERATED;
2683 break;
2684 }
2685
2686 r = path_is_transient(paths, i->path);
2687 if (r < 0)
2688 return r;
2689 if (r > 0) {
2690 state = UNIT_FILE_TRANSIENT;
2691 break;
2692 }
2693
2694 /* Check if any of the Alias= symlinks have been created.
2695 * We ignore other aliases, and only check those that would
2696 * be created by systemctl enable for this unit. */
2697 r = find_symlinks_in_scope(scope, paths, i, true1, &state);
2698 if (r < 0)
2699 return r;
2700 if (r > 0)
2701 break;
2702
2703 /* Check if the file is known under other names. If it is,
2704 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
2705 r = find_symlinks_in_scope(scope, paths, i, false0, &state);
2706 if (r < 0)
2707 return r;
2708 if (r > 0)
2709 state = UNIT_FILE_INDIRECT;
2710 else {
2711 if (unit_file_install_info_has_rules(i))
2712 state = UNIT_FILE_DISABLED;
2713 else if (unit_file_install_info_has_also(i))
2714 state = UNIT_FILE_INDIRECT;
2715 else
2716 state = UNIT_FILE_STATIC;
2717 }
2718
2719 break;
2720
2721 default:
2722 assert_not_reached("Unexpect unit file type.")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, (
"Unexpect unit file type."), "../src/shared/install.c", 2722,
__PRETTY_FUNCTION__); } while (0)
;
2723 }
2724
2725 *ret = state;
2726 return 0;
2727}
2728
2729int unit_file_get_state(
2730 UnitFileScope scope,
2731 const char *root_dir,
2732 const char *name,
2733 UnitFileState *ret) {
2734
2735 _cleanup_(lookup_paths_free)__attribute__((cleanup(lookup_paths_free))) LookupPaths paths = {};
2736 int r;
2737
2738 assert(scope >= 0)do { if ((__builtin_expect(!!(!(scope >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("scope >= 0"), "../src/shared/install.c"
, 2738, __PRETTY_FUNCTION__); } while (0)
;
2739 assert(scope < _UNIT_FILE_SCOPE_MAX)do { if ((__builtin_expect(!!(!(scope < _UNIT_FILE_SCOPE_MAX
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("scope < _UNIT_FILE_SCOPE_MAX"
), "../src/shared/install.c", 2739, __PRETTY_FUNCTION__); } while
(0)
;
2740 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/shared/install.c", 2740
, __PRETTY_FUNCTION__); } while (0)
;
2741
2742 r = lookup_paths_init(&paths, scope, 0, root_dir);
2743 if (r < 0)
2744 return r;
2745
2746 return unit_file_lookup_state(scope, &paths, name, ret);
2747}
2748
2749int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name) {
2750 _cleanup_(install_context_done)__attribute__((cleanup(install_context_done))) InstallContext c = {};
2751 int r;
2752
2753 assert(paths)do { if ((__builtin_expect(!!(!(paths)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("paths"), "../src/shared/install.c", 2753
, __PRETTY_FUNCTION__); } while (0)
;
2754 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/shared/install.c", 2754
, __PRETTY_FUNCTION__); } while (0)
;
2755
2756 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
2757 return -EINVAL22;
2758
2759 r = install_info_discover(scope, &c, paths, name, 0, NULL((void*)0), NULL((void*)0), NULL((void*)0));
2760 if (r == -ENOENT2)
2761 return 0;
2762 if (r < 0)
2763 return r;
2764
2765 return 1;
2766}
2767
2768static int split_pattern_into_name_and_instances(const char *pattern, char **out_unit_name, char ***out_instances) {
2769 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **instances = NULL((void*)0);
2770 _cleanup_free___attribute__((cleanup(freep))) char *unit_name = NULL((void*)0);
2771 int r;
2772
2773 assert(pattern)do { if ((__builtin_expect(!!(!(pattern)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("pattern"), "../src/shared/install.c", 2773
, __PRETTY_FUNCTION__); } while (0)
;
2774 assert(out_instances)do { if ((__builtin_expect(!!(!(out_instances)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("out_instances"), "../src/shared/install.c"
, 2774, __PRETTY_FUNCTION__); } while (0)
;
2775 assert(out_unit_name)do { if ((__builtin_expect(!!(!(out_unit_name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("out_unit_name"), "../src/shared/install.c"
, 2775, __PRETTY_FUNCTION__); } while (0)
;
2776
2777 r = extract_first_word(&pattern, &unit_name, NULL((void*)0), 0);
2778 if (r < 0)
2779 return r;
2780
2781 /* We handle the instances logic when unit name is extracted */
2782 if (pattern) {
2783 /* We only create instances when a rule of templated unit
2784 * is seen. A rule like enable foo@.service a b c will
2785 * result in an array of (a, b, c) as instance names */
2786 if (!unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE))
2787 return -EINVAL22;
2788
2789 instances = strv_split(pattern, WHITESPACE" \t\n\r");
2790 if (!instances)
2791 return -ENOMEM12;
2792
2793 *out_instances = TAKE_PTR(instances)({ typeof(instances) _ptr_ = (instances); (instances) = ((void
*)0); _ptr_; })
;
2794 }
2795
2796 *out_unit_name = TAKE_PTR(unit_name)({ typeof(unit_name) _ptr_ = (unit_name); (unit_name) = ((void
*)0); _ptr_; })
;
2797
2798 return 0;
2799}
2800
2801static int read_presets(UnitFileScope scope, const char *root_dir, Presets *presets) {
2802 _cleanup_(presets_freep)__attribute__((cleanup(presets_freep))) Presets ps = {};
2803 size_t n_allocated = 0;
2804 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **files = NULL((void*)0);
2805 char **p;
2806 int r;
2807
2808 assert(scope >= 0)do { if ((__builtin_expect(!!(!(scope >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("scope >= 0"), "../src/shared/install.c"
, 2808, __PRETTY_FUNCTION__); } while (0)
;
2809 assert(scope < _UNIT_FILE_SCOPE_MAX)do { if ((__builtin_expect(!!(!(scope < _UNIT_FILE_SCOPE_MAX
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("scope < _UNIT_FILE_SCOPE_MAX"
), "../src/shared/install.c", 2809, __PRETTY_FUNCTION__); } while
(0)
;
2810 assert(presets)do { if ((__builtin_expect(!!(!(presets)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("presets"), "../src/shared/install.c", 2810
, __PRETTY_FUNCTION__); } while (0)
;
2811
2812 switch (scope) {
2813 case UNIT_FILE_SYSTEM:
2814 r = conf_files_list(&files, ".preset", root_dir, 0,
2815 "/etc/systemd/system-preset",
2816 "/run/systemd/system-preset",
2817 "/usr/local/lib/systemd/system-preset",
2818 "/usr/lib/systemd/system-preset",
2819#if HAVE_SPLIT_USR0
2820 "/lib/systemd/system-preset",
2821#endif
2822 NULL((void*)0));
2823 break;
2824
2825 case UNIT_FILE_GLOBAL:
2826 case UNIT_FILE_USER:
2827 r = conf_files_list(&files, ".preset", root_dir, 0,
2828 "/etc/systemd/user-preset",
2829 "/run/systemd/user-preset",
2830 "/usr/local/lib/systemd/user-preset",
2831 "/usr/lib/systemd/user-preset",
2832 NULL((void*)0));
2833 break;
2834
2835 default:
2836 assert_not_reached("Invalid unit file scope")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, (
"Invalid unit file scope"), "../src/shared/install.c", 2836, __PRETTY_FUNCTION__
); } while (0)
;
2837 }
2838
2839 if (r < 0)
2840 return r;
2841
2842 STRV_FOREACH(p, files)for ((p) = (files); (p) && *(p); (p)++) {
2843 _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f;
2844 char line[LINE_MAX2048];
2845 int n = 0;
2846
2847 f = fopen(*p, "re");
2848 if (!f) {
2849 if (errno(*__errno_location ()) == ENOENT2)
2850 continue;
2851
2852 return -errno(*__errno_location ());
2853 }
2854
2855 FOREACH_LINE(line, f, return -errno)for (;;) if (!fgets(line, sizeof(line), f)) { if (ferror(f)) {
return -(*__errno_location ()); } break; } else
{
2856 PresetRule rule = {};
2857 const char *parameter;
2858 char *l;
2859
2860 l = strstrip(line);
2861 n++;
2862
2863 if (isempty(l))
2864 continue;
2865 if (strchr(COMMENTS"#;", *l))
2866 continue;
2867
2868 parameter = first_word(l, "enable");
2869 if (parameter) {
2870 char *unit_name;
2871 char **instances = NULL((void*)0);
2872
2873 /* Unit_name will remain the same as parameter when no instances are specified */
2874 r = split_pattern_into_name_and_instances(parameter, &unit_name, &instances);
2875 if (r < 0) {
2876 log_syntax(NULL, LOG_WARNING, *p, n, 0, "Couldn't parse line '%s'. Ignoring.", line)({ int _level = (4), _e = (0); (log_get_max_level_realm(LOG_REALM_SYSTEMD
) >= ((_level) & 0x07)) ? log_syntax_internal(((void*)
0), _level, *p, n, _e, "../src/shared/install.c", 2876, __func__
, "Couldn't parse line '%s'. Ignoring.", line) : -abs(_e); })
;
2877 continue;
2878 }
2879
2880 rule = (PresetRule) {
2881 .pattern = unit_name,
2882 .action = PRESET_ENABLE,
2883 .instances = instances,
2884 };
2885 }
2886
2887 parameter = first_word(l, "disable");
2888 if (parameter) {
2889 char *pattern;
2890
2891 pattern = strdup(parameter);
2892 if (!pattern)
2893 return -ENOMEM12;
2894
2895 rule = (PresetRule) {
2896 .pattern = pattern,
2897 .action = PRESET_DISABLE,
2898 };
2899 }
2900
2901 if (rule.action) {
2902 if (!GREEDY_REALLOC(ps.rules, n_allocated, ps.n_rules + 1)greedy_realloc((void**) &(ps.rules), &(n_allocated), (
ps.n_rules + 1), sizeof((ps.rules)[0]))
)
2903 return -ENOMEM12;
2904
2905 ps.rules[ps.n_rules++] = rule;
2906 continue;
2907 }
2908
2909 log_syntax(NULL, LOG_WARNING, *p, n, 0, "Couldn't parse line '%s'. Ignoring.", line)({ int _level = (4), _e = (0); (log_get_max_level_realm(LOG_REALM_SYSTEMD
) >= ((_level) & 0x07)) ? log_syntax_internal(((void*)
0), _level, *p, n, _e, "../src/shared/install.c", 2909, __func__
, "Couldn't parse line '%s'. Ignoring.", line) : -abs(_e); })
;
2910 }
2911 }
2912
2913 *presets = ps;
2914 ps = (Presets){};
Value stored to 'ps' is never read
2915
2916 return 0;
2917}
2918
2919static int pattern_match_multiple_instances(
2920 const PresetRule rule,
2921 const char *unit_name,
2922 char ***ret) {
2923
2924 _cleanup_free___attribute__((cleanup(freep))) char *templated_name = NULL((void*)0);
2925 int r;
2926
2927 /* If no ret is needed or the rule itself does not have instances
2928 * initalized, we return not matching */
2929 if (!ret || !rule.instances)
2930 return 0;
2931
2932 r = unit_name_template(unit_name, &templated_name);
2933 if (r < 0)
2934 return r;
2935 if (!streq(rule.pattern, templated_name)(strcmp((rule.pattern),(templated_name)) == 0))
2936 return 0;
2937
2938 /* Compose a list of specified instances when unit name is a template */
2939 if (unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
2940 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **out_strv = NULL((void*)0);
2941
2942 char **iter;
2943 STRV_FOREACH(iter, rule.instances)for ((iter) = (rule.instances); (iter) && *(iter); (iter
)++)
{
2944 _cleanup_free___attribute__((cleanup(freep))) char *name = NULL((void*)0);
2945
2946 r = unit_name_replace_instance(unit_name, *iter, &name);
2947 if (r < 0)
2948 return r;
2949
2950 r = strv_consume(&out_strv, TAKE_PTR(name)({ typeof(name) _ptr_ = (name); (name) = ((void*)0); _ptr_; }
)
);
2951 if (r < 0)
2952 return r;
2953 }
2954
2955 *ret = TAKE_PTR(out_strv)({ typeof(out_strv) _ptr_ = (out_strv); (out_strv) = ((void*)
0); _ptr_; })
;
2956 return 1;
2957 } else {
2958 /* We now know the input unit name is an instance name */
2959 _cleanup_free___attribute__((cleanup(freep))) char *instance_name = NULL((void*)0);
2960
2961 r = unit_name_to_instance(unit_name, &instance_name);
2962 if (r < 0)
2963 return r;
2964
2965 if (strv_find(rule.instances, instance_name))
2966 return 1;
2967 }
2968 return 0;
2969}
2970
2971static int query_presets(const char *name, const Presets presets, char ***instance_name_list) {
2972 PresetAction action = PRESET_UNKNOWN;
2973 size_t i;
2974 char **s;
2975 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
2976 return -EINVAL22;
2977
2978 for (i = 0; i < presets.n_rules; i++)
2979 if (pattern_match_multiple_instances(presets.rules[i], name, instance_name_list) > 0 ||
2980 fnmatch(presets.rules[i].pattern, name, FNM_NOESCAPE(1 << 1)) == 0) {
2981 action = presets.rules[i].action;
2982 break;
2983 }
2984
2985 switch (action) {
2986 case PRESET_UNKNOWN:
2987 log_debug("Preset files don't specify rule for %s. Enabling.", name)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 2987, __func__, "Preset files don't specify rule for %s. Enabling."
, name) : -abs(_e); })
;
2988 return 1;
2989 case PRESET_ENABLE:
2990 if (instance_name_list && *instance_name_list)
2991 STRV_FOREACH(s, *instance_name_list)for ((s) = (*instance_name_list); (s) && *(s); (s)++)
2992 log_debug("Preset files say enable %s.", *s)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 2992, __func__, "Preset files say enable %s."
, *s) : -abs(_e); })
;
2993 else
2994 log_debug("Preset files say enable %s.", name)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 2994, __func__, "Preset files say enable %s."
, name) : -abs(_e); })
;
2995 return 1;
2996 case PRESET_DISABLE:
2997 log_debug("Preset files say disable %s.", name)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 2997, __func__, "Preset files say disable %s."
, name) : -abs(_e); })
;
2998 return 0;
2999 default:
3000 assert_not_reached("invalid preset action")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, (
"invalid preset action"), "../src/shared/install.c", 3000, __PRETTY_FUNCTION__
); } while (0)
;
3001 }
3002}
3003
3004int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) {
3005 _cleanup_(presets_freep)__attribute__((cleanup(presets_freep))) Presets presets = {};
3006 int r;
3007
3008 r = read_presets(scope, root_dir, &presets);
3009 if (r < 0)
3010 return r;
3011
3012 return query_presets(name, presets, NULL((void*)0));
3013}
3014
3015static int execute_preset(
3016 UnitFileScope scope,
3017 UnitFileFlags flags,
3018 InstallContext *plus,
3019 InstallContext *minus,
3020 const LookupPaths *paths,
3021 char **files,
3022 UnitFilePresetMode mode,
3023 UnitFileChange **changes,
3024 size_t *n_changes) {
3025
3026 const char *config_path;
3027 bool_Bool force = !!(flags & UNIT_FILE_FORCE);
3028 bool_Bool runtime = !!(flags & UNIT_FILE_RUNTIME);
3029 int r = 0, q;
3030
3031 assert(plus)do { if ((__builtin_expect(!!(!(plus)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("plus"), "../src/shared/install.c", 3031
, __PRETTY_FUNCTION__); } while (0)
;
3032 assert(minus)do { if ((__builtin_expect(!!(!(minus)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("minus"), "../src/shared/install.c", 3032
, __PRETTY_FUNCTION__); } while (0)
;
3033 assert(paths)do { if ((__builtin_expect(!!(!(paths)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("paths"), "../src/shared/install.c", 3033
, __PRETTY_FUNCTION__); } while (0)
;
3034
3035 if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
3036 _cleanup_set_free_free___attribute__((cleanup(set_free_freep))) Set *remove_symlinks_to = NULL((void*)0);
3037
3038 q = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, changes, n_changes);
3039 if (q < 0)
3040 return q;
3041
3042 FOREACH_STRING(config_path, paths->runtime_config, paths->persistent_config)for (char **_l = ({ char **_ll = ((char**) ((const char*[]) {
paths->runtime_config, paths->persistent_config, ((void
*)0) })); config_path = _ll ? _ll[0] : ((void*)0); _ll; }); _l
&& *_l; config_path = ({ _l ++; _l[0]; }))
{
3043 q = remove_marked_symlinks(remove_symlinks_to, config_path, paths, false0, changes, n_changes);
3044 if (r == 0)
3045 r = q;
3046 }
3047 }
3048
3049 if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) {
3050 /* Returns number of symlinks that where supposed to be installed. */
3051 q = install_context_apply(scope, plus, paths,
3052 runtime ? paths->runtime_config : paths->persistent_config,
3053 force, SEARCH_LOAD, changes, n_changes);
3054 if (r == 0)
3055 r = q;
3056 }
3057
3058 return r;
3059}
3060
3061static int preset_prepare_one(
3062 UnitFileScope scope,
3063 InstallContext *plus,
3064 InstallContext *minus,
3065 LookupPaths *paths,
3066 const char *name,
3067 Presets presets,
3068 UnitFileChange **changes,
3069 size_t *n_changes) {
3070
3071 _cleanup_(install_context_done)__attribute__((cleanup(install_context_done))) InstallContext tmp = {};
3072 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **instance_name_list = NULL((void*)0);
3073 UnitFileInstallInfo *i;
3074 int r;
3075
3076 if (install_info_find(plus, name) || install_info_find(minus, name))
3077 return 0;
3078
3079 r = install_info_discover(scope, &tmp, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS,
3080 &i, changes, n_changes);
3081 if (r < 0)
3082 return r;
3083 if (!streq(name, i->name)(strcmp((name),(i->name)) == 0)) {
3084 log_debug("Skipping %s because it is an alias for %s.", name, i->name)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/shared/install.c", 3084, __func__, "Skipping %s because it is an alias for %s."
, name, i->name) : -abs(_e); })
;
3085 return 0;
3086 }
3087
3088 r = query_presets(name, presets, &instance_name_list);
3089 if (r < 0)
3090 return r;
3091
3092 if (r > 0) {
3093 if (instance_name_list) {
3094 char **s;
3095 STRV_FOREACH(s, instance_name_list)for ((s) = (instance_name_list); (s) && *(s); (s)++) {
3096 r = install_info_discover_and_check(scope, plus, paths, *s, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
3097 &i, changes, n_changes);
3098 if (r < 0)
3099 return r;
3100 }
3101 } else {
3102 r = install_info_discover_and_check(scope, plus, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
3103 &i, changes, n_changes);
3104 if (r < 0)
3105 return r;
3106 }
3107
3108 } else
3109 r = install_info_discover(scope, minus, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS,
3110 &i, changes, n_changes);
3111
3112 return r;
3113}
3114
3115int unit_file_preset(
3116 UnitFileScope scope,
3117 UnitFileFlags flags,
3118 const char *root_dir,
3119 char **files,
3120 UnitFilePresetMode mode,
3121 UnitFileChange **changes,
3122 size_t *n_changes) {
3123
3124 _cleanup_(install_context_done)__attribute__((cleanup(install_context_done))) InstallContext plus = {}, minus = {};
3125 _cleanup_(lookup_paths_free)__attribute__((cleanup(lookup_paths_free))) LookupPaths paths = {};
3126 _cleanup_(presets_freep)__attribute__((cleanup(presets_freep))) Presets presets = {};
3127 char **i;
3128 int r;
3129
3130 assert(scope >= 0)do { if ((__builtin_expect(!!(!(scope >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("scope >= 0"), "../src/shared/install.c"
, 3130, __PRETTY_FUNCTION__); } while (0)
;
3131 assert(scope < _UNIT_FILE_SCOPE_MAX)do { if ((__builtin_expect(!!(!(scope < _UNIT_FILE_SCOPE_MAX
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("scope < _UNIT_FILE_SCOPE_MAX"
), "../src/shared/install.c", 3131, __PRETTY_FUNCTION__); } while
(0)
;
3132 assert(mode < _UNIT_FILE_PRESET_MAX)do { if ((__builtin_expect(!!(!(mode < _UNIT_FILE_PRESET_MAX
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("mode < _UNIT_FILE_PRESET_MAX"
), "../src/shared/install.c", 3132, __PRETTY_FUNCTION__); } while
(0)
;
3133
3134 r = lookup_paths_init(&paths, scope, 0, root_dir);
3135 if (r < 0)
3136 return r;
3137
3138 r = read_presets(scope, root_dir, &presets);
3139 if (r < 0)
3140 return r;
3141
3142 STRV_FOREACH(i, files)for ((i) = (files); (i) && *(i); (i)++) {
3143 r = preset_prepare_one(scope, &plus, &minus, &paths, *i, presets, changes, n_changes);
3144 if (r < 0)
3145 return r;
3146 }
3147
3148 return execute_preset(scope, flags, &plus, &minus, &paths, files, mode, changes, n_changes);
3149}
3150
3151int unit_file_preset_all(
3152 UnitFileScope scope,
3153 UnitFileFlags flags,
3154 const char *root_dir,
3155 UnitFilePresetMode mode,
3156 UnitFileChange **changes,
3157 size_t *n_changes) {
3158
3159 _cleanup_(install_context_done)__attribute__((cleanup(install_context_done))) InstallContext plus = {}, minus = {};
3160 _cleanup_(lookup_paths_free)__attribute__((cleanup(lookup_paths_free))) LookupPaths paths = {};
3161 _cleanup_(presets_freep)__attribute__((cleanup(presets_freep))) Presets presets = {};
3162 char **i;
3163 int r;
3164
3165 assert(scope >= 0)do { if ((__builtin_expect(!!(!(scope >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("scope >= 0"), "../src/shared/install.c"
, 3165, __PRETTY_FUNCTION__); } while (0)
;
3166 assert(scope < _UNIT_FILE_SCOPE_MAX)do { if ((__builtin_expect(!!(!(scope < _UNIT_FILE_SCOPE_MAX
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("scope < _UNIT_FILE_SCOPE_MAX"
), "../src/shared/install.c", 3166, __PRETTY_FUNCTION__); } while
(0)
;
3167 assert(mode < _UNIT_FILE_PRESET_MAX)do { if ((__builtin_expect(!!(!(mode < _UNIT_FILE_PRESET_MAX
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("mode < _UNIT_FILE_PRESET_MAX"
), "../src/shared/install.c", 3167, __PRETTY_FUNCTION__); } while
(0)
;
3168
3169 r = lookup_paths_init(&paths, scope, 0, root_dir);
3170 if (r < 0)
3171 return r;
3172
3173 r = read_presets(scope, root_dir, &presets);
3174 if (r < 0)
3175 return r;
3176
3177 STRV_FOREACH(i, paths.search_path)for ((i) = (paths.search_path); (i) && *(i); (i)++) {
3178 _cleanup_closedir___attribute__((cleanup(closedirp))) DIR *d = NULL((void*)0);
3179 struct dirent *de;
3180
3181 d = opendir(*i);
3182 if (!d) {
3183 if (errno(*__errno_location ()) == ENOENT2)
3184 continue;
3185
3186 return -errno(*__errno_location ());
3187 }
3188
3189 FOREACH_DIRENT(de, d, return -errno)for ((*__errno_location ()) = 0, de = readdir(d);; (*__errno_location
()) = 0, de = readdir(d)) if (!de) { if ((*__errno_location (
)) > 0) { return -(*__errno_location ()); } break; } else if
(hidden_or_backup_file((de)->d_name)) continue; else
{
3190 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
3191 continue;
3192
3193 dirent_ensure_type(d, de);
3194
3195 if (!IN_SET(de->d_type, DT_LNK, DT_REG)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){DT_LNK, DT_REG})/sizeof(int)]; switch(de
->d_type) { case DT_LNK: case DT_REG: _found = 1; break; default
: break; } _found; })
)
3196 continue;
3197
3198 /* we don't pass changes[] in, because we want to handle errors on our own */
3199 r = preset_prepare_one(scope, &plus, &minus, &paths, de->d_name, presets, NULL((void*)0), 0);
3200 if (r == -ERFKILL132)
3201 r = unit_file_changes_add(changes, n_changes,
3202 UNIT_FILE_IS_MASKED, de->d_name, NULL((void*)0));
3203 else if (r == -ENOLINK67)
3204 r = unit_file_changes_add(changes, n_changes,
3205 UNIT_FILE_IS_DANGLING, de->d_name, NULL((void*)0));
3206 else if (r == -EADDRNOTAVAIL99) /* Ignore generated/transient units when applying preset */
3207 continue;
3208 if (r < 0)
3209 return r;
3210 }
3211 }
3212
3213 return execute_preset(scope, flags, &plus, &minus, &paths, NULL((void*)0), mode, changes, n_changes);
3214}
3215
3216static void unit_file_list_free_one(UnitFileList *f) {
3217 if (!f)
3218 return;
3219
3220 free(f->path);
3221 free(f);
3222}
3223
3224Hashmap* unit_file_list_free(Hashmap *h) {
3225 return hashmap_free_with_destructor(h, unit_file_list_free_one)({ ({ void *_item; while ((_item = hashmap_steal_first(h))) unit_file_list_free_one
(_item); }); hashmap_free(h); })
;
3226}
3227
3228DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one)static inline void unit_file_list_free_onep(UnitFileList* *p)
{ if (*p) unit_file_list_free_one(*p); }
;
3229
3230int unit_file_get_list(
3231 UnitFileScope scope,
3232 const char *root_dir,
3233 Hashmap *h,
3234 char **states,
3235 char **patterns) {
3236
3237 _cleanup_(lookup_paths_free)__attribute__((cleanup(lookup_paths_free))) LookupPaths paths = {};
3238 char **i;
3239 int r;
3240
3241 assert(scope >= 0)do { if ((__builtin_expect(!!(!(scope >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("scope >= 0"), "../src/shared/install.c"
, 3241, __PRETTY_FUNCTION__); } while (0)
;
3242 assert(scope < _UNIT_FILE_SCOPE_MAX)do { if ((__builtin_expect(!!(!(scope < _UNIT_FILE_SCOPE_MAX
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("scope < _UNIT_FILE_SCOPE_MAX"
), "../src/shared/install.c", 3242, __PRETTY_FUNCTION__); } while
(0)
;
3243 assert(h)do { if ((__builtin_expect(!!(!(h)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("h"), "../src/shared/install.c", 3243, __PRETTY_FUNCTION__
); } while (0)
;
3244
3245 r = lookup_paths_init(&paths, scope, 0, root_dir);
3246 if (r < 0)
3247 return r;
3248
3249 STRV_FOREACH(i, paths.search_path)for ((i) = (paths.search_path); (i) && *(i); (i)++) {
3250 _cleanup_closedir___attribute__((cleanup(closedirp))) DIR *d = NULL((void*)0);
3251 struct dirent *de;
3252
3253 d = opendir(*i);
3254 if (!d) {
3255 if (errno(*__errno_location ()) == ENOENT2)
3256 continue;
3257 if (IN_SET(errno, ENOTDIR, EACCES)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){20, 13})/sizeof(int)]; switch((*__errno_location
())) { case 20: case 13: _found = 1; break; default: break; }
_found; })
) {
3258 log_debug_errno(errno, "Failed to open \"%s\": %m", *i)({ int _level = ((7)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/shared/install.c", 3258, __func__
, "Failed to open \"%s\": %m", *i) : -abs(_e); })
;
3259 continue;
3260 }
3261
3262 return -errno(*__errno_location ());
3263 }
3264
3265 FOREACH_DIRENT(de, d, return -errno)for ((*__errno_location ()) = 0, de = readdir(d);; (*__errno_location
()) = 0, de = readdir(d)) if (!de) { if ((*__errno_location (
)) > 0) { return -(*__errno_location ()); } break; } else if
(hidden_or_backup_file((de)->d_name)) continue; else
{
3266 _cleanup_(unit_file_list_free_onep)__attribute__((cleanup(unit_file_list_free_onep))) UnitFileList *f = NULL((void*)0);
3267
3268 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
3269 continue;
3270
3271 if (!strv_fnmatch_or_empty(patterns, de->d_name, FNM_NOESCAPE(1 << 1)))
3272 continue;
3273
3274 if (hashmap_get(h, de->d_name))
3275 continue;
3276
3277 dirent_ensure_type(d, de);
3278
3279 if (!IN_SET(de->d_type, DT_LNK, DT_REG)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){DT_LNK, DT_REG})/sizeof(int)]; switch(de
->d_type) { case DT_LNK: case DT_REG: _found = 1; break; default
: break; } _found; })
)
3280 continue;
3281
3282 f = new0(UnitFileList, 1)((UnitFileList*) calloc((1), sizeof(UnitFileList)));
3283 if (!f)
3284 return -ENOMEM12;
3285
3286 f->path = path_make_absolute(de->d_name, *i);
3287 if (!f->path)
3288 return -ENOMEM12;
3289
3290 r = unit_file_lookup_state(scope, &paths, de->d_name, &f->state);
3291 if (r < 0)
3292 f->state = UNIT_FILE_BAD;
3293
3294 if (!strv_isempty(states) &&
3295 !strv_contains(states, unit_file_state_to_string(f->state))(!!strv_find((states), (unit_file_state_to_string(f->state
))))
)
3296 continue;
3297
3298 r = hashmap_put(h, basename(f->path), f);
3299 if (r < 0)
3300 return r;
3301
3302 f = NULL((void*)0); /* prevent cleanup */
3303 }
3304 }
3305
3306 return 0;
3307}
3308
3309static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
3310 [UNIT_FILE_ENABLED] = "enabled",
3311 [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
3312 [UNIT_FILE_LINKED] = "linked",
3313 [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
3314 [UNIT_FILE_MASKED] = "masked",
3315 [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
3316 [UNIT_FILE_STATIC] = "static",
3317 [UNIT_FILE_DISABLED] = "disabled",
3318 [UNIT_FILE_INDIRECT] = "indirect",
3319 [UNIT_FILE_GENERATED] = "generated",
3320 [UNIT_FILE_TRANSIENT] = "transient",
3321 [UNIT_FILE_BAD] = "bad",
3322};
3323
3324DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState)const char *unit_file_state_to_string(UnitFileState i) { if (
i < 0 || i >= (UnitFileState) __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(unit_file_state_table)
, typeof(&*(unit_file_state_table))), sizeof(unit_file_state_table
)/sizeof((unit_file_state_table)[0]), ((void)0)))) return ((void
*)0); return unit_file_state_table[i]; } UnitFileState unit_file_state_from_string
(const char *s) { return (UnitFileState) string_table_lookup(
unit_file_state_table, __extension__ (__builtin_choose_expr( !
__builtin_types_compatible_p(typeof(unit_file_state_table), typeof
(&*(unit_file_state_table))), sizeof(unit_file_state_table
)/sizeof((unit_file_state_table)[0]), ((void)0))), s); }
;
3325
3326static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
3327 [UNIT_FILE_SYMLINK] = "symlink",
3328 [UNIT_FILE_UNLINK] = "unlink",
3329 [UNIT_FILE_IS_MASKED] = "masked",
3330 [UNIT_FILE_IS_DANGLING] = "dangling",
3331};
3332
3333DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType)const char *unit_file_change_type_to_string(UnitFileChangeType
i) { if (i < 0 || i >= (UnitFileChangeType) __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(unit_file_change_type_table), typeof(&*(unit_file_change_type_table
))), sizeof(unit_file_change_type_table)/sizeof((unit_file_change_type_table
)[0]), ((void)0)))) return ((void*)0); return unit_file_change_type_table
[i]; } UnitFileChangeType unit_file_change_type_from_string(const
char *s) { return (UnitFileChangeType) string_table_lookup(unit_file_change_type_table
, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(unit_file_change_type_table), typeof(&*(unit_file_change_type_table
))), sizeof(unit_file_change_type_table)/sizeof((unit_file_change_type_table
)[0]), ((void)0))), s); }
;
3334
3335static const char* const unit_file_preset_mode_table[_UNIT_FILE_PRESET_MAX] = {
3336 [UNIT_FILE_PRESET_FULL] = "full",
3337 [UNIT_FILE_PRESET_ENABLE_ONLY] = "enable-only",
3338 [UNIT_FILE_PRESET_DISABLE_ONLY] = "disable-only",
3339};
3340
3341DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode, UnitFilePresetMode)const char *unit_file_preset_mode_to_string(UnitFilePresetMode
i) { if (i < 0 || i >= (UnitFilePresetMode) __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(unit_file_preset_mode_table), typeof(&*(unit_file_preset_mode_table
))), sizeof(unit_file_preset_mode_table)/sizeof((unit_file_preset_mode_table
)[0]), ((void)0)))) return ((void*)0); return unit_file_preset_mode_table
[i]; } UnitFilePresetMode unit_file_preset_mode_from_string(const
char *s) { return (UnitFilePresetMode) string_table_lookup(unit_file_preset_mode_table
, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(unit_file_preset_mode_table), typeof(&*(unit_file_preset_mode_table
))), sizeof(unit_file_preset_mode_table)/sizeof((unit_file_preset_mode_table
)[0]), ((void)0))), s); }
;