1
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4
This file is part of systemd.
6
Copyright 2011 Lennart Poettering
8
systemd is free software; you can redistribute it and/or modify it
9
under the terms of the GNU Lesser General Public License as published by
10
the Free Software Foundation; either version 2.1 of the License, or
11
(at your option) any later version.
13
systemd is distributed in the hope that it will be useful, but
14
WITHOUT ANY WARRANTY; without even the implied warranty <of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
Lesser General Public License for more details.
18
You should have received a copy of the GNU Lesser General Public License
19
along with systemd; If not, see <http://www.gnu.org/licenses/>.
32
#include "path-util.h"
33
#include "path-lookup.h"
35
#include "unit-name.h"
37
#include "conf-parser.h"
38
#include "conf-files.h"
39
#include "specifier.h"
40
#include "install-printf.h"
43
Hashmap *will_install;
44
Hashmap *have_installed;
47
#define _cleanup_lookup_paths_free_ \
48
__attribute__((cleanup(lookup_paths_free)))
49
#define _cleanup_install_context_done_ \
50
__attribute__((cleanup(install_context_done)))
52
static int lookup_paths_init_from_scope(LookupPaths *paths, UnitFileScope scope) {
55
assert(scope < _UNIT_FILE_SCOPE_MAX);
59
return lookup_paths_init(paths,
60
scope == UNIT_FILE_SYSTEM ? SYSTEMD_SYSTEM : SYSTEMD_USER,
61
scope == UNIT_FILE_USER,
65
static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) {
70
assert(scope < _UNIT_FILE_SCOPE_MAX);
75
case UNIT_FILE_SYSTEM:
77
if (root_dir && runtime)
78
asprintf(&p, "%s/run/systemd/system", root_dir);
80
p = strdup("/run/systemd/system");
82
asprintf(&p, "%s/%s", root_dir, SYSTEM_CONFIG_UNIT_PATH);
84
p = strdup(SYSTEM_CONFIG_UNIT_PATH);
88
case UNIT_FILE_GLOBAL:
94
p = strdup("/run/systemd/user");
96
p = strdup(USER_CONFIG_UNIT_PATH);
101
if (root_dir || runtime)
104
r = user_config_home(&p);
106
return r < 0 ? r : -ENOENT;
111
assert_not_reached("Bad scope");
121
static int add_file_change(
122
UnitFileChange **changes,
124
UnitFileChangeType type,
126
const char *source) {
132
assert(!changes == !n_changes);
137
c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
145
c[i].path = strdup(path);
150
c[i].source = strdup(source);
162
static int mark_symlink_for_removal(
163
Set **remove_symlinks_to,
171
r = set_ensure_allocated(remove_symlinks_to, string_hash_func, string_compare_func);
179
path_kill_slashes(n);
181
r = set_consume(*remove_symlinks_to, n);
183
return r == -EEXIST ? 0 : r;
188
static int remove_marked_symlinks_fd(
189
Set *remove_symlinks_to,
192
const char *config_path,
194
UnitFileChange **changes,
199
_cleanup_closedir_ DIR *d = NULL;
201
assert(remove_symlinks_to);
209
close_nointr_nofail(fd);
217
union dirent_storage buf;
220
k = readdir_r(d, &buf.de, &de);
229
if (ignore_file(de->d_name))
232
dirent_ensure_type(d, de);
234
if (de->d_type == DT_DIR) {
236
_cleanup_free_ char *p = NULL;
238
nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
248
p = path_make_absolute(de->d_name, path);
250
close_nointr_nofail(nfd);
254
/* This will close nfd, regardless whether it succeeds or not */
255
q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes, files);
260
} else if (de->d_type == DT_LNK) {
261
_cleanup_free_ char *p = NULL, *dest = NULL;
265
p = path_make_absolute(de->d_name, path);
269
q = readlink_and_canonicalize(p, &dest);
280
set_get(remove_symlinks_to, dest) ||
281
set_get(remove_symlinks_to, path_get_file_name(dest));
283
if (unit_name_is_instance(p))
284
found = found && strv_contains(files, path_get_file_name(p));
288
if (unlink(p) < 0 && errno != ENOENT) {
293
rmdir_parents(p, config_path);
294
path_kill_slashes(p);
296
add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
298
if (!set_get(remove_symlinks_to, p)) {
300
q = mark_symlink_for_removal(&remove_symlinks_to, p);
315
static int remove_marked_symlinks(
316
Set *remove_symlinks_to,
317
const char *config_path,
318
UnitFileChange **changes,
327
if (set_size(remove_symlinks_to) <= 0)
330
fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
344
/* This takes possession of cfd and closes it */
345
q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes, files);
350
close_nointr_nofail(fd);
355
static int find_symlinks_fd(
359
const char *config_path,
360
bool *same_name_link) {
363
_cleanup_closedir_ DIR *d = NULL;
369
assert(same_name_link);
373
close_nointr_nofail(fd);
380
union dirent_storage buf;
382
k = readdir_r(d, &buf.de, &de);
389
if (ignore_file(de->d_name))
392
dirent_ensure_type(d, de);
394
if (de->d_type == DT_DIR) {
396
_cleanup_free_ char *p = NULL;
398
nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
408
p = path_make_absolute(de->d_name, path);
410
close_nointr_nofail(nfd);
414
/* This will close nfd, regardless whether it succeeds or not */
415
q = find_symlinks_fd(name, nfd, p, config_path, same_name_link);
423
} else if (de->d_type == DT_LNK) {
424
_cleanup_free_ char *p = NULL, *dest = NULL;
425
bool found_path, found_dest, b = false;
428
/* Acquire symlink name */
429
p = path_make_absolute(de->d_name, path);
433
/* Acquire symlink destination */
434
q = readlink_and_canonicalize(p, &dest);
444
/* Check if the symlink itself matches what we
446
if (path_is_absolute(name))
447
found_path = path_equal(p, name);
449
found_path = streq(de->d_name, name);
451
/* Check if what the symlink points to
452
* matches what we are looking for */
453
if (path_is_absolute(name))
454
found_dest = path_equal(dest, name);
456
found_dest = streq(path_get_file_name(dest), name);
458
if (found_path && found_dest) {
459
_cleanup_free_ char *t = NULL;
461
/* Filter out same name links in the main
463
t = path_make_absolute(name, config_path);
467
b = path_equal(t, p);
471
*same_name_link = true;
472
else if (found_path || found_dest)
480
static int find_symlinks(
482
const char *config_path,
483
bool *same_name_link) {
489
assert(same_name_link);
491
fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
498
/* This takes possession of fd and closes it */
499
return find_symlinks_fd(name, fd, config_path, config_path, same_name_link);
502
static int find_symlinks_in_scope(
504
const char *root_dir,
506
UnitFileState *state) {
509
_cleanup_free_ char *path = NULL;
510
bool same_name_link_runtime = false, same_name_link = false;
513
assert(scope < _UNIT_FILE_SCOPE_MAX);
516
if (scope == UNIT_FILE_SYSTEM || scope == UNIT_FILE_GLOBAL) {
518
/* First look in runtime config path */
519
r = get_config_path(scope, true, root_dir, &path);
523
r = find_symlinks(name, path, &same_name_link_runtime);
527
*state = UNIT_FILE_ENABLED_RUNTIME;
532
/* Then look in the normal config path */
533
r = get_config_path(scope, false, root_dir, &path);
537
r = find_symlinks(name, path, &same_name_link);
541
*state = UNIT_FILE_ENABLED;
545
/* Hmm, we didn't find it, but maybe we found the same name
547
if (same_name_link_runtime) {
548
*state = UNIT_FILE_LINKED_RUNTIME;
550
} else if (same_name_link) {
551
*state = UNIT_FILE_LINKED;
561
const char *root_dir,
564
UnitFileChange **changes,
565
unsigned *n_changes) {
568
_cleanup_free_ char *prefix;
572
assert(scope < _UNIT_FILE_SCOPE_MAX);
574
r = get_config_path(scope, runtime, root_dir, &prefix);
578
STRV_FOREACH(i, files) {
579
_cleanup_free_ char *path = NULL;
581
if (!unit_name_is_valid(*i, true)) {
587
path = path_make_absolute(*i, prefix);
593
if (symlink("/dev/null", path) >= 0) {
594
add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
599
if (errno == EEXIST) {
601
if (null_or_empty_path(path) > 0)
607
if (symlink("/dev/null", path) >= 0) {
609
add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
610
add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
627
int unit_file_unmask(
630
const char *root_dir,
632
UnitFileChange **changes,
633
unsigned *n_changes) {
635
char **i, *config_path = NULL;
637
Set *remove_symlinks_to = NULL;
640
assert(scope < _UNIT_FILE_SCOPE_MAX);
642
r = get_config_path(scope, runtime, root_dir, &config_path);
646
STRV_FOREACH(i, files) {
649
if (!unit_name_is_valid(*i, true)) {
655
path = path_make_absolute(*i, config_path);
661
q = null_or_empty_path(path);
663
if (unlink(path) >= 0) {
664
mark_symlink_for_removal(&remove_symlinks_to, path);
665
add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
674
if (q != -ENOENT && r == 0)
682
q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
686
set_free_free(remove_symlinks_to);
695
const char *root_dir,
698
UnitFileChange **changes,
699
unsigned *n_changes) {
701
_cleanup_lookup_paths_free_ LookupPaths paths = {};
703
_cleanup_free_ char *config_path = NULL;
707
assert(scope < _UNIT_FILE_SCOPE_MAX);
709
r = lookup_paths_init_from_scope(&paths, scope);
713
r = get_config_path(scope, runtime, root_dir, &config_path);
717
STRV_FOREACH(i, files) {
718
_cleanup_free_ char *path = NULL;
722
fn = path_get_file_name(*i);
724
if (!path_is_absolute(*i) ||
725
!unit_name_is_valid(fn, true)) {
731
if (lstat(*i, &st) < 0) {
737
if (!S_ISREG(st.st_mode)) {
742
q = in_search_path(*i, paths.unit_path);
749
path = path_make_absolute(fn, config_path);
753
if (symlink(*i, path) >= 0) {
754
add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
758
if (errno == EEXIST) {
759
_cleanup_free_ char *dest = NULL;
761
q = readlink_and_make_absolute(path, &dest);
763
if (q < 0 && errno != ENOENT) {
769
if (q >= 0 && path_equal(dest, *i))
775
if (symlink(*i, path) >= 0) {
777
add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
778
add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
795
void unit_file_list_free(Hashmap *h) {
798
while ((i = hashmap_steal_first(h))) {
806
void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
809
assert(changes || n_changes == 0);
814
for (i = 0; i < n_changes; i++) {
815
free(changes[i].path);
816
free(changes[i].source);
822
static void install_info_free(InstallInfo *i) {
827
strv_free(i->aliases);
828
strv_free(i->wanted_by);
829
strv_free(i->required_by);
833
static void install_info_hashmap_free(Hashmap *m) {
839
while ((i = hashmap_steal_first(m)))
840
install_info_free(i);
845
static void install_context_done(InstallContext *c) {
848
install_info_hashmap_free(c->will_install);
849
install_info_hashmap_free(c->have_installed);
851
c->will_install = c->have_installed = NULL;
854
static int install_info_add(
858
InstallInfo *i = NULL;
862
assert(name || path);
865
name = path_get_file_name(path);
867
if (!unit_name_is_valid(name, true))
870
if (hashmap_get(c->have_installed, name) ||
871
hashmap_get(c->will_install, name))
874
r = hashmap_ensure_allocated(&c->will_install, string_hash_func, string_compare_func);
878
i = new0(InstallInfo, 1);
882
i->name = strdup(name);
889
i->path = strdup(path);
896
r = hashmap_put(c->will_install, i->name, i);
904
install_info_free(i);
909
static int install_info_add_auto(
911
const char *name_or_path) {
914
assert(name_or_path);
916
if (path_is_absolute(name_or_path))
917
return install_info_add(c, NULL, name_or_path);
919
return install_info_add(c, name_or_path, NULL);
922
static int config_parse_also(const char *unit,
923
const char *filename,
935
InstallContext *c = data;
941
FOREACH_WORD_QUOTED(w, l, rvalue, state) {
942
_cleanup_free_ char *n;
949
r = install_info_add(c, n, NULL);
957
static int config_parse_user(const char *unit,
958
const char *filename,
967
InstallInfo *i = data;
974
printed = install_full_printf(i, rvalue);
984
static int unit_file_load(
988
bool allow_symlink) {
990
const ConfigTableItem items[] = {
991
{ "Install", "Alias", config_parse_strv, 0, &info->aliases },
992
{ "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
993
{ "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
994
{ "Install", "Also", config_parse_also, 0, c },
995
{ "Exec", "User", config_parse_user, 0, info },
996
{ NULL, NULL, NULL, 0, NULL }
1000
_cleanup_fclose_ FILE *f = NULL;
1007
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
1011
f = fdopen(fd, "re");
1013
close_nointr_nofail(fd);
1017
r = config_parse(NULL, path, f, NULL,
1018
config_item_table_lookup, (void*) items, true, true, info);
1023
strv_length(info->aliases) +
1024
strv_length(info->wanted_by) +
1025
strv_length(info->required_by);
1028
static int unit_file_search(
1032
const char *root_dir,
1033
bool allow_symlink) {
1043
return unit_file_load(c, info, info->path, allow_symlink);
1047
STRV_FOREACH(p, paths->unit_path) {
1050
if (isempty(root_dir))
1051
asprintf(&path, "%s/%s", *p, info->name);
1053
asprintf(&path, "%s/%s/%s", root_dir, *p, info->name);
1058
r = unit_file_load(c, info, path, allow_symlink);
1063
if (r == -ENOENT && unit_name_is_instance(info->name)) {
1064
/* unit file doesn't exist, however instance enablement was request */
1065
/* we will check if it is possible to load template unit file */
1066
char *template = NULL,
1067
*template_path = NULL,
1068
*template_dir = NULL;
1070
template = unit_name_template(info->name);
1076
/* we will reuse path variable since we don't need it anymore */
1077
template_dir = path;
1078
*(strrchr(path, '/') + 1) = '\0';
1080
template_path = strjoin(template_dir, template, NULL);
1081
if (!template_path) {
1087
/* let's try to load template unit */
1088
r = unit_file_load(c, info, template_path, allow_symlink);
1090
info->path = strdup(template_path);
1094
free(template_path);
1100
free(template_path);
1105
if (r != -ENOENT && r != -ELOOP)
1112
static int unit_file_can_install(
1114
const char *root_dir,
1116
bool allow_symlink) {
1118
_cleanup_install_context_done_ InstallContext c = {};
1125
r = install_info_add_auto(&c, name);
1129
assert_se(i = hashmap_first(c.will_install));
1131
r = unit_file_search(&c, i, paths, root_dir, allow_symlink);
1135
strv_length(i->aliases) +
1136
strv_length(i->wanted_by) +
1137
strv_length(i->required_by);
1142
static int create_symlink(
1143
const char *old_path,
1144
const char *new_path,
1146
UnitFileChange **changes,
1147
unsigned *n_changes) {
1149
_cleanup_free_ char *dest = NULL;
1155
mkdir_parents_label(new_path, 0755);
1157
if (symlink(old_path, new_path) >= 0) {
1158
add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1162
if (errno != EEXIST)
1165
r = readlink_and_make_absolute(new_path, &dest);
1169
if (path_equal(dest, old_path))
1177
if (symlink(old_path, new_path) >= 0) {
1178
add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
1179
add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1186
static int install_info_symlink_alias(
1188
const char *config_path,
1190
UnitFileChange **changes,
1191
unsigned *n_changes) {
1197
assert(config_path);
1199
STRV_FOREACH(s, i->aliases) {
1200
_cleanup_free_ char *alias_path = NULL, *dst = NULL;
1202
dst = install_full_printf(i, *s);
1206
alias_path = path_make_absolute(dst, config_path);
1210
q = create_symlink(i->path, alias_path, force, changes, n_changes);
1218
static int install_info_symlink_wants(
1220
const char *config_path,
1222
UnitFileChange **changes,
1223
unsigned *n_changes) {
1229
assert(config_path);
1231
STRV_FOREACH(s, i->wanted_by) {
1232
_cleanup_free_ char *path = NULL, *dst = NULL;
1234
dst = install_full_printf(i, *s);
1238
if (!unit_name_is_valid(dst, true)) {
1243
if (asprintf(&path, "%s/%s.wants/%s", config_path, dst, i->name) < 0)
1246
q = create_symlink(i->path, path, force, changes, n_changes);
1255
static int install_info_symlink_requires(
1257
const char *config_path,
1259
UnitFileChange **changes,
1260
unsigned *n_changes) {
1266
assert(config_path);
1268
STRV_FOREACH(s, i->required_by) {
1269
_cleanup_free_ char *path = NULL, *dst = NULL;
1271
dst = install_full_printf(i, *s);
1275
if (!unit_name_is_valid(dst, true)) {
1280
if (asprintf(&path, "%s/%s.requires/%s", config_path, dst, i->name) < 0)
1283
q = create_symlink(i->path, path, force, changes, n_changes);
1292
static int install_info_symlink_link(
1295
const char *config_path,
1297
UnitFileChange **changes,
1298
unsigned *n_changes) {
1301
_cleanup_free_ char *path = NULL;
1305
assert(config_path);
1308
r = in_search_path(i->path, paths->unit_path);
1312
if (asprintf(&path, "%s/%s", config_path, i->name) < 0)
1315
r = create_symlink(i->path, path, force, changes, n_changes);
1319
static int install_info_apply(
1322
const char *config_path,
1324
UnitFileChange **changes,
1325
unsigned *n_changes) {
1331
assert(config_path);
1333
r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
1335
q = install_info_symlink_wants(i, config_path, force, changes, n_changes);
1339
q = install_info_symlink_requires(i, config_path, force, changes, n_changes);
1343
q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
1350
static int install_context_apply(
1353
const char *config_path,
1354
const char *root_dir,
1356
UnitFileChange **changes,
1357
unsigned *n_changes) {
1364
assert(config_path);
1366
while ((i = hashmap_first(c->will_install))) {
1368
q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1372
assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1374
q = unit_file_search(c, i, paths, root_dir, false);
1383
q = install_info_apply(i, paths, config_path, force, changes, n_changes);
1384
if (r >= 0 && q < 0)
1391
static int install_context_mark_for_removal(
1394
Set **remove_symlinks_to,
1395
const char *config_path,
1396
const char *root_dir) {
1403
assert(config_path);
1405
/* Marks all items for removal */
1407
while ((i = hashmap_first(c->will_install))) {
1409
q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1413
assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1415
q = unit_file_search(c, i, paths, root_dir, false);
1424
if (unit_name_is_instance(i->name)) {
1425
char *unit_file = NULL;
1427
unit_file = path_get_file_name(i->path);
1429
if (unit_name_is_instance(unit_file))
1430
/* unit file named as instance exists, thus all symlinks pointing to it, will be removed */
1431
q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1433
/* does not exist, thus we will mark for removal symlinks to template unit file */
1434
q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
1436
q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1438
if (r >= 0 && q < 0)
1445
int unit_file_enable(
1446
UnitFileScope scope,
1448
const char *root_dir,
1451
UnitFileChange **changes,
1452
unsigned *n_changes) {
1454
_cleanup_lookup_paths_free_ LookupPaths paths = {};
1455
_cleanup_install_context_done_ InstallContext c = {};
1457
_cleanup_free_ char *config_path = NULL;
1461
assert(scope < _UNIT_FILE_SCOPE_MAX);
1463
r = lookup_paths_init_from_scope(&paths, scope);
1467
r = get_config_path(scope, runtime, root_dir, &config_path);
1471
STRV_FOREACH(i, files) {
1472
r = install_info_add_auto(&c, *i);
1477
/* This will return the number of symlink rules that were
1478
supposed to be created, not the ones actually created. This is
1479
useful to determine whether the passed files had any
1480
installation data at all. */
1481
r = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1485
int unit_file_disable(
1486
UnitFileScope scope,
1488
const char *root_dir,
1490
UnitFileChange **changes,
1491
unsigned *n_changes) {
1493
_cleanup_lookup_paths_free_ LookupPaths paths = {};
1494
_cleanup_install_context_done_ InstallContext c = {};
1496
_cleanup_free_ char *config_path = NULL;
1497
_cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
1501
assert(scope < _UNIT_FILE_SCOPE_MAX);
1503
r = lookup_paths_init_from_scope(&paths, scope);
1507
r = get_config_path(scope, runtime, root_dir, &config_path);
1511
STRV_FOREACH(i, files) {
1512
r = install_info_add_auto(&c, *i);
1517
r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
1519
q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
1526
int unit_file_reenable(
1527
UnitFileScope scope,
1529
const char *root_dir,
1532
UnitFileChange **changes,
1533
unsigned *n_changes) {
1535
_cleanup_lookup_paths_free_ LookupPaths paths = {};
1536
_cleanup_install_context_done_ InstallContext c = {};
1538
_cleanup_free_ char *config_path = NULL;
1539
_cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
1543
assert(scope < _UNIT_FILE_SCOPE_MAX);
1545
r = lookup_paths_init_from_scope(&paths, scope);
1549
r = get_config_path(scope, runtime, root_dir, &config_path);
1553
STRV_FOREACH(i, files) {
1554
r = mark_symlink_for_removal(&remove_symlinks_to, *i);
1558
r = install_info_add_auto(&c, *i);
1563
r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
1565
/* Returns number of symlinks that where supposed to be installed. */
1566
q = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1573
UnitFileState unit_file_get_state(
1574
UnitFileScope scope,
1575
const char *root_dir,
1578
_cleanup_lookup_paths_free_ LookupPaths paths = {};
1579
UnitFileState state = _UNIT_FILE_STATE_INVALID;
1581
_cleanup_free_ char *path = NULL;
1585
assert(scope < _UNIT_FILE_SCOPE_MAX);
1588
if (root_dir && scope != UNIT_FILE_SYSTEM)
1591
if (!unit_name_is_valid(name, true))
1594
r = lookup_paths_init_from_scope(&paths, scope);
1598
STRV_FOREACH(i, paths.unit_path) {
1605
asprintf(&path, "%s/%s/%s", root_dir, *i, name);
1607
asprintf(&path, "%s/%s", *i, name);
1612
if (lstat(path, &st) < 0) {
1614
if (errno == ENOENT)
1620
if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
1623
r = null_or_empty_path(path);
1624
if (r < 0 && r != -ENOENT)
1627
state = path_startswith(*i, "/run") ?
1628
UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1632
r = find_symlinks_in_scope(scope, root_dir, name, &state);
1638
r = unit_file_can_install(&paths, root_dir, path, true);
1639
if (r < 0 && errno != ENOENT)
1642
return UNIT_FILE_DISABLED;
1644
return UNIT_FILE_STATIC;
1647
return r < 0 ? r : state;
1650
int unit_file_query_preset(UnitFileScope scope, const char *name) {
1651
_cleanup_strv_free_ char **files = NULL;
1656
assert(scope < _UNIT_FILE_SCOPE_MAX);
1659
if (scope == UNIT_FILE_SYSTEM)
1660
r = conf_files_list(&files, ".preset", NULL,
1661
"/etc/systemd/system-preset",
1662
"/usr/local/lib/systemd/system-preset",
1663
"/usr/lib/systemd/system-preset",
1664
#ifdef HAVE_SPLIT_USR
1665
"/lib/systemd/system-preset",
1668
else if (scope == UNIT_FILE_GLOBAL)
1669
r = conf_files_list(&files, ".preset", NULL,
1670
"/etc/systemd/user-preset",
1671
"/usr/local/lib/systemd/user-preset",
1672
"/usr/lib/systemd/user-preset",
1680
STRV_FOREACH(i, files) {
1681
_cleanup_fclose_ FILE *f;
1683
f = fopen(*i, "re");
1685
if (errno == ENOENT)
1692
char line[LINE_MAX], *l;
1694
if (!fgets(line, sizeof(line), f))
1701
if (strchr(COMMENTS "\n", *l))
1704
if (first_word(l, "enable")) {
1706
l += strspn(l, WHITESPACE);
1708
if (fnmatch(l, name, FNM_NOESCAPE) == 0)
1711
} else if (first_word(l, "disable")) {
1713
l += strspn(l, WHITESPACE);
1715
if (fnmatch(l, name, FNM_NOESCAPE) == 0)
1719
log_debug("Couldn't parse line '%s'", l);
1723
/* Default is "enable" */
1727
int unit_file_preset(
1728
UnitFileScope scope,
1730
const char *root_dir,
1733
UnitFileChange **changes,
1734
unsigned *n_changes) {
1736
_cleanup_lookup_paths_free_ LookupPaths paths = {};
1737
_cleanup_install_context_done_ InstallContext plus = {}, minus = {};
1739
_cleanup_free_ char *config_path = NULL;
1740
_cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
1744
assert(scope < _UNIT_FILE_SCOPE_MAX);
1746
r = lookup_paths_init_from_scope(&paths, scope);
1750
r = get_config_path(scope, runtime, root_dir, &config_path);
1754
STRV_FOREACH(i, files) {
1756
if (!unit_name_is_valid(*i, true))
1759
r = unit_file_query_preset(scope, *i);
1764
r = install_info_add_auto(&plus, *i);
1766
r = install_info_add_auto(&minus, *i);
1772
r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to,
1773
config_path, root_dir);
1775
q = remove_marked_symlinks(remove_symlinks_to, config_path,
1776
changes, n_changes, files);
1780
/* Returns number of symlinks that where supposed to be installed. */
1781
q = install_context_apply(&plus, &paths, config_path, root_dir, force,
1782
changes, n_changes);
1789
static void unitfilelist_free(UnitFileList **f) {
1797
int unit_file_get_list(
1798
UnitFileScope scope,
1799
const char *root_dir,
1802
_cleanup_lookup_paths_free_ LookupPaths paths = {};
1804
_cleanup_free_ char *buf = NULL;
1805
_cleanup_closedir_ DIR *d = NULL;
1809
assert(scope < _UNIT_FILE_SCOPE_MAX);
1812
if (root_dir && scope != UNIT_FILE_SYSTEM)
1815
r = lookup_paths_init_from_scope(&paths, scope);
1819
STRV_FOREACH(i, paths.unit_path) {
1820
const char *units_dir;
1826
if (asprintf(&buf, "%s/%s", root_dir, *i) < 0)
1836
d = opendir(units_dir);
1838
if (errno == ENOENT)
1846
union dirent_storage buffer;
1847
UnitFileList __attribute__((cleanup(unitfilelist_free)))
1850
r = readdir_r(d, &buffer.de, &de);
1857
if (ignore_file(de->d_name))
1860
if (!unit_name_is_valid(de->d_name, true))
1863
if (hashmap_get(h, de->d_name))
1866
r = dirent_ensure_type(d, de);
1874
if (de->d_type != DT_LNK && de->d_type != DT_REG)
1877
f = new0(UnitFileList, 1);
1881
f->path = path_make_absolute(de->d_name, units_dir);
1885
r = null_or_empty_path(f->path);
1886
if (r < 0 && r != -ENOENT)
1890
path_startswith(*i, "/run") ?
1891
UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1895
r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
1899
f->state = UNIT_FILE_ENABLED;
1903
r = unit_file_can_install(&paths, root_dir, f->path, true);
1904
if (r == -EINVAL || /* Invalid setting? */
1905
r == -EBADMSG || /* Invalid format? */
1906
r == -ENOENT /* Included file not found? */)
1907
f->state = UNIT_FILE_INVALID;
1911
f->state = UNIT_FILE_DISABLED;
1913
f->state = UNIT_FILE_STATIC;
1916
r = hashmap_put(h, path_get_file_name(f->path), f);
1919
f = NULL; /* prevent cleanup */
1926
static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
1927
[UNIT_FILE_ENABLED] = "enabled",
1928
[UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
1929
[UNIT_FILE_LINKED] = "linked",
1930
[UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
1931
[UNIT_FILE_MASKED] = "masked",
1932
[UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
1933
[UNIT_FILE_STATIC] = "static",
1934
[UNIT_FILE_DISABLED] = "disabled",
1935
[UNIT_FILE_INVALID] = "invalid",
1938
DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
1940
static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
1941
[UNIT_FILE_SYMLINK] = "symlink",
1942
[UNIT_FILE_UNLINK] = "unlink",
1945
DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);