~ubuntu-branches/ubuntu/trusty/systemd/trusty

« back to all changes in this revision

Viewing changes to src/shared/install.c

  • Committer: Package Import Robot
  • Author(s): Michael Biebl, Michael Biebl, Michael Stapelberg, Daniel Schaal, Ondrej Balaz
  • Date: 2013-09-12 00:13:11 UTC
  • mfrom: (1.1.11) (9.1.2 experimental)
  • mto: This revision was merged to the branch mainline in revision 53.
  • Revision ID: package-import@ubuntu.com-20130912001311-dz35it34wr2lbday
Tags: 204-3
[ Michael Biebl ]
* Upload to unstable.
* Use /bin/bash in debug-shell.service as Debian doesn't have /sbin/sushell.
* Only import net.ifaces cmdline property for network devices.
* Generate strict dependencies between the binary packages using a
  shlibs.local file and add an explicit versioned dependency on
  libsystemd-login0 to systemd to ensure packages are upgraded in sync.
  Closes: #719444
* Drop obsolete Replaces: libudev0 from udev package.
* Use correct paths for various binaries, like /sbin/quotaon, which are
  installed in / and not /usr in Debian.  Closes: #721347
* Don't install kernel-install(8) man page since we don't install the
  corresponding binary either.  Closes: #722180
* Cherry-pick upstream fixes to make switching runlevels and starting
  reboot via ctrl-alt-del more robust.
* Cherry-pick upstream fix to properly apply ACLs to Journal files.

[ Michael Stapelberg ]
* Make systemctl enable|disable call update-rc.d for SysV init scripts.
  Closes: #709780
* Don't mount /tmp as tmpfs by default and make it possible to enable this
  feature via "systemctl enable tmp.mount".

[ Daniel Schaal ]
* Add bug-script to systemd and udev.  Closes: #711245

[ Ondrej Balaz ]
* Recognize discard option in /etc/crypttab.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
 
2
 
 
3
/***
 
4
  This file is part of systemd.
 
5
 
 
6
  Copyright 2011 Lennart Poettering
 
7
 
 
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.
 
12
 
 
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.
 
17
 
 
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/>.
 
20
***/
 
21
 
 
22
#include <errno.h>
 
23
#include <fcntl.h>
 
24
#include <unistd.h>
 
25
#include <string.h>
 
26
#include <fnmatch.h>
 
27
 
 
28
#include "util.h"
 
29
#include "mkdir.h"
 
30
#include "hashmap.h"
 
31
#include "set.h"
 
32
#include "path-util.h"
 
33
#include "path-lookup.h"
 
34
#include "strv.h"
 
35
#include "unit-name.h"
 
36
#include "install.h"
 
37
#include "conf-parser.h"
 
38
#include "conf-files.h"
 
39
#include "specifier.h"
 
40
#include "install-printf.h"
 
41
 
 
42
typedef struct {
 
43
        Hashmap *will_install;
 
44
        Hashmap *have_installed;
 
45
} InstallContext;
 
46
 
 
47
#define _cleanup_lookup_paths_free_ \
 
48
        __attribute__((cleanup(lookup_paths_free)))
 
49
#define _cleanup_install_context_done_ \
 
50
        __attribute__((cleanup(install_context_done)))
 
51
 
 
52
static int lookup_paths_init_from_scope(LookupPaths *paths, UnitFileScope scope) {
 
53
        assert(paths);
 
54
        assert(scope >= 0);
 
55
        assert(scope < _UNIT_FILE_SCOPE_MAX);
 
56
 
 
57
        zero(*paths);
 
58
 
 
59
        return lookup_paths_init(paths,
 
60
                                 scope == UNIT_FILE_SYSTEM ? SYSTEMD_SYSTEM : SYSTEMD_USER,
 
61
                                 scope == UNIT_FILE_USER,
 
62
                                 NULL, NULL, NULL);
 
63
}
 
64
 
 
65
static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) {
 
66
        char *p = NULL;
 
67
        int r;
 
68
 
 
69
        assert(scope >= 0);
 
70
        assert(scope < _UNIT_FILE_SCOPE_MAX);
 
71
        assert(ret);
 
72
 
 
73
        switch (scope) {
 
74
 
 
75
        case UNIT_FILE_SYSTEM:
 
76
 
 
77
                if (root_dir && runtime)
 
78
                        asprintf(&p, "%s/run/systemd/system", root_dir);
 
79
                else if (runtime)
 
80
                        p = strdup("/run/systemd/system");
 
81
                else if (root_dir)
 
82
                        asprintf(&p, "%s/%s", root_dir, SYSTEM_CONFIG_UNIT_PATH);
 
83
                else
 
84
                        p = strdup(SYSTEM_CONFIG_UNIT_PATH);
 
85
 
 
86
                break;
 
87
 
 
88
        case UNIT_FILE_GLOBAL:
 
89
 
 
90
                if (root_dir)
 
91
                        return -EINVAL;
 
92
 
 
93
                if (runtime)
 
94
                        p = strdup("/run/systemd/user");
 
95
                else
 
96
                        p = strdup(USER_CONFIG_UNIT_PATH);
 
97
                break;
 
98
 
 
99
        case UNIT_FILE_USER:
 
100
 
 
101
                if (root_dir || runtime)
 
102
                        return -EINVAL;
 
103
 
 
104
                r = user_config_home(&p);
 
105
                if (r <= 0)
 
106
                        return r < 0 ? r : -ENOENT;
 
107
 
 
108
                break;
 
109
 
 
110
        default:
 
111
                assert_not_reached("Bad scope");
 
112
        }
 
113
 
 
114
        if (!p)
 
115
                return -ENOMEM;
 
116
 
 
117
        *ret = p;
 
118
        return 0;
 
119
}
 
120
 
 
121
static int add_file_change(
 
122
                UnitFileChange **changes,
 
123
                unsigned *n_changes,
 
124
                UnitFileChangeType type,
 
125
                const char *path,
 
126
                const char *source) {
 
127
 
 
128
        UnitFileChange *c;
 
129
        unsigned i;
 
130
 
 
131
        assert(path);
 
132
        assert(!changes == !n_changes);
 
133
 
 
134
        if (!changes)
 
135
                return 0;
 
136
 
 
137
        c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
 
138
        if (!c)
 
139
                return -ENOMEM;
 
140
 
 
141
        *changes = c;
 
142
        i = *n_changes;
 
143
 
 
144
        c[i].type = type;
 
145
        c[i].path = strdup(path);
 
146
        if (!c[i].path)
 
147
                return -ENOMEM;
 
148
 
 
149
        if (source) {
 
150
                c[i].source = strdup(source);
 
151
                if (!c[i].source) {
 
152
                        free(c[i].path);
 
153
                        return -ENOMEM;
 
154
                }
 
155
        } else
 
156
                c[i].source = NULL;
 
157
 
 
158
        *n_changes = i+1;
 
159
        return 0;
 
160
}
 
161
 
 
162
static int mark_symlink_for_removal(
 
163
                Set **remove_symlinks_to,
 
164
                const char *p) {
 
165
 
 
166
        char *n;
 
167
        int r;
 
168
 
 
169
        assert(p);
 
170
 
 
171
        r = set_ensure_allocated(remove_symlinks_to, string_hash_func, string_compare_func);
 
172
        if (r < 0)
 
173
                return r;
 
174
 
 
175
        n = strdup(p);
 
176
        if (!n)
 
177
                return -ENOMEM;
 
178
 
 
179
        path_kill_slashes(n);
 
180
 
 
181
        r = set_consume(*remove_symlinks_to, n);
 
182
        if (r < 0)
 
183
                return r == -EEXIST ? 0 : r;
 
184
 
 
185
        return 0;
 
186
}
 
187
 
 
188
static int remove_marked_symlinks_fd(
 
189
                Set *remove_symlinks_to,
 
190
                int fd,
 
191
                const char *path,
 
192
                const char *config_path,
 
193
                bool *deleted,
 
194
                UnitFileChange **changes,
 
195
                unsigned *n_changes,
 
196
                char** files) {
 
197
 
 
198
        int r = 0;
 
199
        _cleanup_closedir_ DIR *d = NULL;
 
200
 
 
201
        assert(remove_symlinks_to);
 
202
        assert(fd >= 0);
 
203
        assert(path);
 
204
        assert(config_path);
 
205
        assert(deleted);
 
206
 
 
207
        d = fdopendir(fd);
 
208
        if (!d) {
 
209
                close_nointr_nofail(fd);
 
210
                return -errno;
 
211
        }
 
212
 
 
213
        rewinddir(d);
 
214
 
 
215
        for (;;) {
 
216
                struct dirent *de;
 
217
                union dirent_storage buf;
 
218
                int k;
 
219
 
 
220
                k = readdir_r(d, &buf.de, &de);
 
221
                if (k != 0) {
 
222
                        r = -errno;
 
223
                        break;
 
224
                }
 
225
 
 
226
                if (!de)
 
227
                        break;
 
228
 
 
229
                if (ignore_file(de->d_name))
 
230
                        continue;
 
231
 
 
232
                dirent_ensure_type(d, de);
 
233
 
 
234
                if (de->d_type == DT_DIR) {
 
235
                        int nfd, q;
 
236
                        _cleanup_free_ char *p = NULL;
 
237
 
 
238
                        nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
 
239
                        if (nfd < 0) {
 
240
                                if (errno == ENOENT)
 
241
                                        continue;
 
242
 
 
243
                                if (r == 0)
 
244
                                        r = -errno;
 
245
                                continue;
 
246
                        }
 
247
 
 
248
                        p = path_make_absolute(de->d_name, path);
 
249
                        if (!p) {
 
250
                                close_nointr_nofail(nfd);
 
251
                                return -ENOMEM;
 
252
                        }
 
253
 
 
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);
 
256
 
 
257
                        if (r == 0)
 
258
                                r = q;
 
259
 
 
260
                } else if (de->d_type == DT_LNK) {
 
261
                        _cleanup_free_ char *p = NULL, *dest = NULL;
 
262
                        int q;
 
263
                        bool found;
 
264
 
 
265
                        p = path_make_absolute(de->d_name, path);
 
266
                        if (!p)
 
267
                                return -ENOMEM;
 
268
 
 
269
                        q = readlink_and_canonicalize(p, &dest);
 
270
                        if (q < 0) {
 
271
                                if (q == -ENOENT)
 
272
                                        continue;
 
273
 
 
274
                                if (r == 0)
 
275
                                        r = q;
 
276
                                continue;
 
277
                        }
 
278
 
 
279
                        found =
 
280
                                set_get(remove_symlinks_to, dest) ||
 
281
                                set_get(remove_symlinks_to, path_get_file_name(dest));
 
282
 
 
283
                        if (unit_name_is_instance(p))
 
284
                                found = found && strv_contains(files, path_get_file_name(p));
 
285
 
 
286
                        if (found) {
 
287
 
 
288
                                if (unlink(p) < 0 && errno != ENOENT) {
 
289
 
 
290
                                        if (r == 0)
 
291
                                                r = -errno;
 
292
                                } else {
 
293
                                        rmdir_parents(p, config_path);
 
294
                                        path_kill_slashes(p);
 
295
 
 
296
                                        add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
 
297
 
 
298
                                        if (!set_get(remove_symlinks_to, p)) {
 
299
 
 
300
                                                q = mark_symlink_for_removal(&remove_symlinks_to, p);
 
301
                                                if (q < 0) {
 
302
                                                        if (r == 0)
 
303
                                                                r = q;
 
304
                                                } else
 
305
                                                        *deleted = true;
 
306
                                        }
 
307
                                }
 
308
                        }
 
309
                }
 
310
        }
 
311
 
 
312
        return r;
 
313
}
 
314
 
 
315
static int remove_marked_symlinks(
 
316
                Set *remove_symlinks_to,
 
317
                const char *config_path,
 
318
                UnitFileChange **changes,
 
319
                unsigned *n_changes,
 
320
                char** files) {
 
321
 
 
322
        int fd, r = 0;
 
323
        bool deleted;
 
324
 
 
325
        assert(config_path);
 
326
 
 
327
        if (set_size(remove_symlinks_to) <= 0)
 
328
                return 0;
 
329
 
 
330
        fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
 
331
        if (fd < 0)
 
332
                return -errno;
 
333
 
 
334
        do {
 
335
                int q, cfd;
 
336
                deleted = false;
 
337
 
 
338
                cfd = dup(fd);
 
339
                if (cfd < 0) {
 
340
                        r = -errno;
 
341
                        break;
 
342
                }
 
343
 
 
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);
 
346
                if (r == 0)
 
347
                        r = q;
 
348
        } while (deleted);
 
349
 
 
350
        close_nointr_nofail(fd);
 
351
 
 
352
        return r;
 
353
}
 
354
 
 
355
static int find_symlinks_fd(
 
356
                const char *name,
 
357
                int fd,
 
358
                const char *path,
 
359
                const char *config_path,
 
360
                bool *same_name_link) {
 
361
 
 
362
        int r = 0;
 
363
        _cleanup_closedir_ DIR *d = NULL;
 
364
 
 
365
        assert(name);
 
366
        assert(fd >= 0);
 
367
        assert(path);
 
368
        assert(config_path);
 
369
        assert(same_name_link);
 
370
 
 
371
        d = fdopendir(fd);
 
372
        if (!d) {
 
373
                close_nointr_nofail(fd);
 
374
                return -errno;
 
375
        }
 
376
 
 
377
        for (;;) {
 
378
                int k;
 
379
                struct dirent *de;
 
380
                union dirent_storage buf;
 
381
 
 
382
                k = readdir_r(d, &buf.de, &de);
 
383
                if (k != 0)
 
384
                        return -errno;
 
385
 
 
386
                if (!de)
 
387
                        return r;
 
388
 
 
389
                if (ignore_file(de->d_name))
 
390
                        continue;
 
391
 
 
392
                dirent_ensure_type(d, de);
 
393
 
 
394
                if (de->d_type == DT_DIR) {
 
395
                        int nfd, q;
 
396
                        _cleanup_free_ char *p = NULL;
 
397
 
 
398
                        nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
 
399
                        if (nfd < 0) {
 
400
                                if (errno == ENOENT)
 
401
                                        continue;
 
402
 
 
403
                                if (r == 0)
 
404
                                        r = -errno;
 
405
                                continue;
 
406
                        }
 
407
 
 
408
                        p = path_make_absolute(de->d_name, path);
 
409
                        if (!p) {
 
410
                                close_nointr_nofail(nfd);
 
411
                                return -ENOMEM;
 
412
                        }
 
413
 
 
414
                        /* This will close nfd, regardless whether it succeeds or not */
 
415
                        q = find_symlinks_fd(name, nfd, p, config_path, same_name_link);
 
416
 
 
417
                        if (q > 0)
 
418
                                return 1;
 
419
 
 
420
                        if (r == 0)
 
421
                                r = q;
 
422
 
 
423
                } else if (de->d_type == DT_LNK) {
 
424
                        _cleanup_free_ char *p = NULL, *dest = NULL;
 
425
                        bool found_path, found_dest, b = false;
 
426
                        int q;
 
427
 
 
428
                        /* Acquire symlink name */
 
429
                        p = path_make_absolute(de->d_name, path);
 
430
                        if (!p)
 
431
                                return -ENOMEM;
 
432
 
 
433
                        /* Acquire symlink destination */
 
434
                        q = readlink_and_canonicalize(p, &dest);
 
435
                        if (q < 0) {
 
436
                                if (q == -ENOENT)
 
437
                                        continue;
 
438
 
 
439
                                if (r == 0)
 
440
                                        r = q;
 
441
                                continue;
 
442
                        }
 
443
 
 
444
                        /* Check if the symlink itself matches what we
 
445
                         * are looking for */
 
446
                        if (path_is_absolute(name))
 
447
                                found_path = path_equal(p, name);
 
448
                        else
 
449
                                found_path = streq(de->d_name, name);
 
450
 
 
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);
 
455
                        else
 
456
                                found_dest = streq(path_get_file_name(dest), name);
 
457
 
 
458
                        if (found_path && found_dest) {
 
459
                                _cleanup_free_ char *t = NULL;
 
460
 
 
461
                                /* Filter out same name links in the main
 
462
                                 * config path */
 
463
                                t = path_make_absolute(name, config_path);
 
464
                                if (!t)
 
465
                                        return -ENOMEM;
 
466
 
 
467
                                b = path_equal(t, p);
 
468
                        }
 
469
 
 
470
                        if (b)
 
471
                                *same_name_link = true;
 
472
                        else if (found_path || found_dest)
 
473
                                return 1;
 
474
                }
 
475
        }
 
476
 
 
477
        return r;
 
478
}
 
479
 
 
480
static int find_symlinks(
 
481
                const char *name,
 
482
                const char *config_path,
 
483
                bool *same_name_link) {
 
484
 
 
485
        int fd;
 
486
 
 
487
        assert(name);
 
488
        assert(config_path);
 
489
        assert(same_name_link);
 
490
 
 
491
        fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
 
492
        if (fd < 0) {
 
493
                if (errno == ENOENT)
 
494
                        return 0;
 
495
                return -errno;
 
496
        }
 
497
 
 
498
        /* This takes possession of fd and closes it */
 
499
        return find_symlinks_fd(name, fd, config_path, config_path, same_name_link);
 
500
}
 
501
 
 
502
static int find_symlinks_in_scope(
 
503
                UnitFileScope scope,
 
504
                const char *root_dir,
 
505
                const char *name,
 
506
                UnitFileState *state) {
 
507
 
 
508
        int r;
 
509
        _cleanup_free_ char *path = NULL;
 
510
        bool same_name_link_runtime = false, same_name_link = false;
 
511
 
 
512
        assert(scope >= 0);
 
513
        assert(scope < _UNIT_FILE_SCOPE_MAX);
 
514
        assert(name);
 
515
 
 
516
        if (scope == UNIT_FILE_SYSTEM || scope == UNIT_FILE_GLOBAL) {
 
517
 
 
518
                /* First look in runtime config path */
 
519
                r = get_config_path(scope, true, root_dir, &path);
 
520
                if (r < 0)
 
521
                        return r;
 
522
 
 
523
                r = find_symlinks(name, path, &same_name_link_runtime);
 
524
                if (r < 0)
 
525
                        return r;
 
526
                else if (r > 0) {
 
527
                        *state = UNIT_FILE_ENABLED_RUNTIME;
 
528
                        return r;
 
529
                }
 
530
        }
 
531
 
 
532
        /* Then look in the normal config path */
 
533
        r = get_config_path(scope, false, root_dir, &path);
 
534
        if (r < 0)
 
535
                return r;
 
536
 
 
537
        r = find_symlinks(name, path, &same_name_link);
 
538
        if (r < 0)
 
539
                return r;
 
540
        else if (r > 0) {
 
541
                *state = UNIT_FILE_ENABLED;
 
542
                return r;
 
543
        }
 
544
 
 
545
        /* Hmm, we didn't find it, but maybe we found the same name
 
546
         * link? */
 
547
        if (same_name_link_runtime) {
 
548
                *state = UNIT_FILE_LINKED_RUNTIME;
 
549
                return 1;
 
550
        } else if (same_name_link) {
 
551
                *state = UNIT_FILE_LINKED;
 
552
                return 1;
 
553
        }
 
554
 
 
555
        return 0;
 
556
}
 
557
 
 
558
int unit_file_mask(
 
559
                UnitFileScope scope,
 
560
                bool runtime,
 
561
                const char *root_dir,
 
562
                char *files[],
 
563
                bool force,
 
564
                UnitFileChange **changes,
 
565
                unsigned *n_changes) {
 
566
 
 
567
        char **i;
 
568
        _cleanup_free_ char *prefix;
 
569
        int r;
 
570
 
 
571
        assert(scope >= 0);
 
572
        assert(scope < _UNIT_FILE_SCOPE_MAX);
 
573
 
 
574
        r = get_config_path(scope, runtime, root_dir, &prefix);
 
575
        if (r < 0)
 
576
                return r;
 
577
 
 
578
        STRV_FOREACH(i, files) {
 
579
                _cleanup_free_ char *path = NULL;
 
580
 
 
581
                if (!unit_name_is_valid(*i, true)) {
 
582
                        if (r == 0)
 
583
                                r = -EINVAL;
 
584
                        continue;
 
585
                }
 
586
 
 
587
                path = path_make_absolute(*i, prefix);
 
588
                if (!path) {
 
589
                        r = -ENOMEM;
 
590
                        break;
 
591
                }
 
592
 
 
593
                if (symlink("/dev/null", path) >= 0) {
 
594
                        add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
 
595
 
 
596
                        continue;
 
597
                }
 
598
 
 
599
                if (errno == EEXIST) {
 
600
 
 
601
                        if (null_or_empty_path(path) > 0)
 
602
                                continue;
 
603
 
 
604
                        if (force) {
 
605
                                unlink(path);
 
606
 
 
607
                                if (symlink("/dev/null", path) >= 0) {
 
608
 
 
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");
 
611
 
 
612
                                        continue;
 
613
                                }
 
614
                        }
 
615
 
 
616
                        if (r == 0)
 
617
                                r = -EEXIST;
 
618
                } else {
 
619
                        if (r == 0)
 
620
                                r = -errno;
 
621
                }
 
622
        }
 
623
 
 
624
        return r;
 
625
}
 
626
 
 
627
int unit_file_unmask(
 
628
                UnitFileScope scope,
 
629
                bool runtime,
 
630
                const char *root_dir,
 
631
                char *files[],
 
632
                UnitFileChange **changes,
 
633
                unsigned *n_changes) {
 
634
 
 
635
        char **i, *config_path = NULL;
 
636
        int r, q;
 
637
        Set *remove_symlinks_to = NULL;
 
638
 
 
639
        assert(scope >= 0);
 
640
        assert(scope < _UNIT_FILE_SCOPE_MAX);
 
641
 
 
642
        r = get_config_path(scope, runtime, root_dir, &config_path);
 
643
        if (r < 0)
 
644
                goto finish;
 
645
 
 
646
        STRV_FOREACH(i, files) {
 
647
                char *path;
 
648
 
 
649
                if (!unit_name_is_valid(*i, true)) {
 
650
                        if (r == 0)
 
651
                                r = -EINVAL;
 
652
                        continue;
 
653
                }
 
654
 
 
655
                path = path_make_absolute(*i, config_path);
 
656
                if (!path) {
 
657
                        r = -ENOMEM;
 
658
                        break;
 
659
                }
 
660
 
 
661
                q = null_or_empty_path(path);
 
662
                if (q > 0) {
 
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);
 
666
 
 
667
                                free(path);
 
668
                                continue;
 
669
                        }
 
670
 
 
671
                        q = -errno;
 
672
                }
 
673
 
 
674
                if (q != -ENOENT && r == 0)
 
675
                        r = q;
 
676
 
 
677
                free(path);
 
678
        }
 
679
 
 
680
 
 
681
finish:
 
682
        q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
 
683
        if (r == 0)
 
684
                r = q;
 
685
 
 
686
        set_free_free(remove_symlinks_to);
 
687
        free(config_path);
 
688
 
 
689
        return r;
 
690
}
 
691
 
 
692
int unit_file_link(
 
693
                UnitFileScope scope,
 
694
                bool runtime,
 
695
                const char *root_dir,
 
696
                char *files[],
 
697
                bool force,
 
698
                UnitFileChange **changes,
 
699
                unsigned *n_changes) {
 
700
 
 
701
        _cleanup_lookup_paths_free_ LookupPaths paths = {};
 
702
        char **i;
 
703
        _cleanup_free_ char *config_path = NULL;
 
704
        int r, q;
 
705
 
 
706
        assert(scope >= 0);
 
707
        assert(scope < _UNIT_FILE_SCOPE_MAX);
 
708
 
 
709
        r = lookup_paths_init_from_scope(&paths, scope);
 
710
        if (r < 0)
 
711
                return r;
 
712
 
 
713
        r = get_config_path(scope, runtime, root_dir, &config_path);
 
714
        if (r < 0)
 
715
                return r;
 
716
 
 
717
        STRV_FOREACH(i, files) {
 
718
                _cleanup_free_ char *path = NULL;
 
719
                char *fn;
 
720
                struct stat st;
 
721
 
 
722
                fn = path_get_file_name(*i);
 
723
 
 
724
                if (!path_is_absolute(*i) ||
 
725
                    !unit_name_is_valid(fn, true)) {
 
726
                        if (r == 0)
 
727
                                r = -EINVAL;
 
728
                        continue;
 
729
                }
 
730
 
 
731
                if (lstat(*i, &st) < 0) {
 
732
                        if (r == 0)
 
733
                                r = -errno;
 
734
                        continue;
 
735
                }
 
736
 
 
737
                if (!S_ISREG(st.st_mode)) {
 
738
                        r = -ENOENT;
 
739
                        continue;
 
740
                }
 
741
 
 
742
                q = in_search_path(*i, paths.unit_path);
 
743
                if (q < 0)
 
744
                        return q;
 
745
 
 
746
                if (q > 0)
 
747
                        continue;
 
748
 
 
749
                path = path_make_absolute(fn, config_path);
 
750
                if (!path)
 
751
                        return -ENOMEM;
 
752
 
 
753
                if (symlink(*i, path) >= 0) {
 
754
                        add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
 
755
                        continue;
 
756
                }
 
757
 
 
758
                if (errno == EEXIST) {
 
759
                        _cleanup_free_ char *dest = NULL;
 
760
 
 
761
                        q = readlink_and_make_absolute(path, &dest);
 
762
 
 
763
                        if (q < 0 && errno != ENOENT) {
 
764
                                if (r == 0)
 
765
                                        r = q;
 
766
                                continue;
 
767
                        }
 
768
 
 
769
                        if (q >= 0 && path_equal(dest, *i))
 
770
                                continue;
 
771
 
 
772
                        if (force) {
 
773
                                unlink(path);
 
774
 
 
775
                                if (symlink(*i, path) >= 0) {
 
776
 
 
777
                                        add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
 
778
                                        add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
 
779
 
 
780
                                        continue;
 
781
                                }
 
782
                        }
 
783
 
 
784
                        if (r == 0)
 
785
                                r = -EEXIST;
 
786
                } else {
 
787
                        if (r == 0)
 
788
                                r = -errno;
 
789
                }
 
790
        }
 
791
 
 
792
        return r;
 
793
}
 
794
 
 
795
void unit_file_list_free(Hashmap *h) {
 
796
        UnitFileList *i;
 
797
 
 
798
        while ((i = hashmap_steal_first(h))) {
 
799
                free(i->path);
 
800
                free(i);
 
801
        }
 
802
 
 
803
        hashmap_free(h);
 
804
}
 
805
 
 
806
void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
 
807
        unsigned i;
 
808
 
 
809
        assert(changes || n_changes == 0);
 
810
 
 
811
        if (!changes)
 
812
                return;
 
813
 
 
814
        for (i = 0; i < n_changes; i++) {
 
815
                free(changes[i].path);
 
816
                free(changes[i].source);
 
817
        }
 
818
 
 
819
        free(changes);
 
820
}
 
821
 
 
822
static void install_info_free(InstallInfo *i) {
 
823
        assert(i);
 
824
 
 
825
        free(i->name);
 
826
        free(i->path);
 
827
        strv_free(i->aliases);
 
828
        strv_free(i->wanted_by);
 
829
        strv_free(i->required_by);
 
830
        free(i);
 
831
}
 
832
 
 
833
static void install_info_hashmap_free(Hashmap *m) {
 
834
        InstallInfo *i;
 
835
 
 
836
        if (!m)
 
837
                return;
 
838
 
 
839
        while ((i = hashmap_steal_first(m)))
 
840
                install_info_free(i);
 
841
 
 
842
        hashmap_free(m);
 
843
}
 
844
 
 
845
static void install_context_done(InstallContext *c) {
 
846
        assert(c);
 
847
 
 
848
        install_info_hashmap_free(c->will_install);
 
849
        install_info_hashmap_free(c->have_installed);
 
850
 
 
851
        c->will_install = c->have_installed = NULL;
 
852
}
 
853
 
 
854
static int install_info_add(
 
855
                InstallContext *c,
 
856
                const char *name,
 
857
                const char *path) {
 
858
        InstallInfo *i = NULL;
 
859
        int r;
 
860
 
 
861
        assert(c);
 
862
        assert(name || path);
 
863
 
 
864
        if (!name)
 
865
                name = path_get_file_name(path);
 
866
 
 
867
        if (!unit_name_is_valid(name, true))
 
868
                return -EINVAL;
 
869
 
 
870
        if (hashmap_get(c->have_installed, name) ||
 
871
            hashmap_get(c->will_install, name))
 
872
                return 0;
 
873
 
 
874
        r = hashmap_ensure_allocated(&c->will_install, string_hash_func, string_compare_func);
 
875
        if (r < 0)
 
876
                return r;
 
877
 
 
878
        i = new0(InstallInfo, 1);
 
879
        if (!i)
 
880
                return -ENOMEM;
 
881
 
 
882
        i->name = strdup(name);
 
883
        if (!i->name) {
 
884
                r = -ENOMEM;
 
885
                goto fail;
 
886
        }
 
887
 
 
888
        if (path) {
 
889
                i->path = strdup(path);
 
890
                if (!i->path) {
 
891
                        r = -ENOMEM;
 
892
                        goto fail;
 
893
                }
 
894
        }
 
895
 
 
896
        r = hashmap_put(c->will_install, i->name, i);
 
897
        if (r < 0)
 
898
                goto fail;
 
899
 
 
900
        return 0;
 
901
 
 
902
fail:
 
903
        if (i)
 
904
                install_info_free(i);
 
905
 
 
906
        return r;
 
907
}
 
908
 
 
909
static int install_info_add_auto(
 
910
                InstallContext *c,
 
911
                const char *name_or_path) {
 
912
 
 
913
        assert(c);
 
914
        assert(name_or_path);
 
915
 
 
916
        if (path_is_absolute(name_or_path))
 
917
                return install_info_add(c, NULL, name_or_path);
 
918
        else
 
919
                return install_info_add(c, name_or_path, NULL);
 
920
}
 
921
 
 
922
static int config_parse_also(const char *unit,
 
923
                             const char *filename,
 
924
                             unsigned line,
 
925
                             const char *section,
 
926
                             const char *lvalue,
 
927
                             int ltype,
 
928
                             const char *rvalue,
 
929
                             void *data,
 
930
                             void *userdata) {
 
931
 
 
932
        char *w;
 
933
        size_t l;
 
934
        char *state;
 
935
        InstallContext *c = data;
 
936
 
 
937
        assert(filename);
 
938
        assert(lvalue);
 
939
        assert(rvalue);
 
940
 
 
941
        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
 
942
                _cleanup_free_ char *n;
 
943
                int r;
 
944
 
 
945
                n = strndup(w, l);
 
946
                if (!n)
 
947
                        return -ENOMEM;
 
948
 
 
949
                r = install_info_add(c, n, NULL);
 
950
                if (r < 0)
 
951
                        return r;
 
952
        }
 
953
 
 
954
        return 0;
 
955
}
 
956
 
 
957
static int config_parse_user(const char *unit,
 
958
                             const char *filename,
 
959
                             unsigned line,
 
960
                             const char *section,
 
961
                             const char *lvalue,
 
962
                             int ltype,
 
963
                             const char *rvalue,
 
964
                             void *data,
 
965
                             void *userdata) {
 
966
 
 
967
        InstallInfo *i = data;
 
968
        char* printed;
 
969
 
 
970
        assert(filename);
 
971
        assert(lvalue);
 
972
        assert(rvalue);
 
973
 
 
974
        printed = install_full_printf(i, rvalue);
 
975
        if (!printed)
 
976
                return -ENOMEM;
 
977
 
 
978
        free(i->user);
 
979
        i->user = printed;
 
980
 
 
981
        return 0;
 
982
}
 
983
 
 
984
static int unit_file_load(
 
985
                InstallContext *c,
 
986
                InstallInfo *info,
 
987
                const char *path,
 
988
                bool allow_symlink) {
 
989
 
 
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 }
 
997
        };
 
998
 
 
999
        int fd;
 
1000
        _cleanup_fclose_ FILE *f = NULL;
 
1001
        int r;
 
1002
 
 
1003
        assert(c);
 
1004
        assert(info);
 
1005
        assert(path);
 
1006
 
 
1007
        fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
 
1008
        if (fd < 0)
 
1009
                return -errno;
 
1010
 
 
1011
        f = fdopen(fd, "re");
 
1012
        if (!f) {
 
1013
                close_nointr_nofail(fd);
 
1014
                return -ENOMEM;
 
1015
        }
 
1016
 
 
1017
        r = config_parse(NULL, path, f, NULL,
 
1018
                         config_item_table_lookup, (void*) items, true, true, info);
 
1019
        if (r < 0)
 
1020
                return r;
 
1021
 
 
1022
        return
 
1023
                strv_length(info->aliases) +
 
1024
                strv_length(info->wanted_by) +
 
1025
                strv_length(info->required_by);
 
1026
}
 
1027
 
 
1028
static int unit_file_search(
 
1029
                InstallContext *c,
 
1030
                InstallInfo *info,
 
1031
                LookupPaths *paths,
 
1032
                const char *root_dir,
 
1033
                bool allow_symlink) {
 
1034
 
 
1035
        char **p;
 
1036
        int r;
 
1037
 
 
1038
        assert(c);
 
1039
        assert(info);
 
1040
        assert(paths);
 
1041
 
 
1042
        if (info->path)
 
1043
                return unit_file_load(c, info, info->path, allow_symlink);
 
1044
 
 
1045
        assert(info->name);
 
1046
 
 
1047
        STRV_FOREACH(p, paths->unit_path) {
 
1048
                char *path = NULL;
 
1049
 
 
1050
                if (isempty(root_dir))
 
1051
                        asprintf(&path, "%s/%s", *p, info->name);
 
1052
                else
 
1053
                        asprintf(&path, "%s/%s/%s", root_dir, *p, info->name);
 
1054
 
 
1055
                if (!path)
 
1056
                        return -ENOMEM;
 
1057
 
 
1058
                r = unit_file_load(c, info, path, allow_symlink);
 
1059
 
 
1060
                if (r >= 0)
 
1061
                        info->path = path;
 
1062
                else {
 
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;
 
1069
 
 
1070
                                template = unit_name_template(info->name);
 
1071
                                if (!template) {
 
1072
                                        free(path);
 
1073
                                        return -ENOMEM;
 
1074
                                }
 
1075
 
 
1076
                                /* we will reuse path variable since we don't need it anymore */
 
1077
                                template_dir = path;
 
1078
                                *(strrchr(path, '/') + 1) = '\0';
 
1079
 
 
1080
                                template_path = strjoin(template_dir, template, NULL);
 
1081
                                if (!template_path) {
 
1082
                                        free(path);
 
1083
                                        free(template);
 
1084
                                        return -ENOMEM;
 
1085
                                }
 
1086
 
 
1087
                                /* let's try to load template unit */
 
1088
                                r = unit_file_load(c, info, template_path, allow_symlink);
 
1089
                                if (r >= 0) {
 
1090
                                        info->path = strdup(template_path);
 
1091
                                        if (!info->path) {
 
1092
                                                free(path);
 
1093
                                                free(template);
 
1094
                                                free(template_path);
 
1095
                                                return -ENOMEM;
 
1096
                                        }
 
1097
                                }
 
1098
 
 
1099
                                free(template);
 
1100
                                free(template_path);
 
1101
                        }
 
1102
                        free(path);
 
1103
                }
 
1104
 
 
1105
                if (r != -ENOENT && r != -ELOOP)
 
1106
                        return r;
 
1107
        }
 
1108
 
 
1109
        return -ENOENT;
 
1110
}
 
1111
 
 
1112
static int unit_file_can_install(
 
1113
                LookupPaths *paths,
 
1114
                const char *root_dir,
 
1115
                const char *name,
 
1116
                bool allow_symlink) {
 
1117
 
 
1118
        _cleanup_install_context_done_ InstallContext c = {};
 
1119
        InstallInfo *i;
 
1120
        int r;
 
1121
 
 
1122
        assert(paths);
 
1123
        assert(name);
 
1124
 
 
1125
        r = install_info_add_auto(&c, name);
 
1126
        if (r < 0)
 
1127
                return r;
 
1128
 
 
1129
        assert_se(i = hashmap_first(c.will_install));
 
1130
 
 
1131
        r = unit_file_search(&c, i, paths, root_dir, allow_symlink);
 
1132
 
 
1133
        if (r >= 0)
 
1134
                r =
 
1135
                        strv_length(i->aliases) +
 
1136
                        strv_length(i->wanted_by) +
 
1137
                        strv_length(i->required_by);
 
1138
 
 
1139
        return r;
 
1140
}
 
1141
 
 
1142
static int create_symlink(
 
1143
                const char *old_path,
 
1144
                const char *new_path,
 
1145
                bool force,
 
1146
                UnitFileChange **changes,
 
1147
                unsigned *n_changes) {
 
1148
 
 
1149
        _cleanup_free_ char *dest = NULL;
 
1150
        int r;
 
1151
 
 
1152
        assert(old_path);
 
1153
        assert(new_path);
 
1154
 
 
1155
        mkdir_parents_label(new_path, 0755);
 
1156
 
 
1157
        if (symlink(old_path, new_path) >= 0) {
 
1158
                add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
 
1159
                return 0;
 
1160
        }
 
1161
 
 
1162
        if (errno != EEXIST)
 
1163
                return -errno;
 
1164
 
 
1165
        r = readlink_and_make_absolute(new_path, &dest);
 
1166
        if (r < 0)
 
1167
                return r;
 
1168
 
 
1169
        if (path_equal(dest, old_path))
 
1170
                return 0;
 
1171
 
 
1172
        if (!force)
 
1173
                return -EEXIST;
 
1174
 
 
1175
        unlink(new_path);
 
1176
 
 
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);
 
1180
                return 0;
 
1181
        }
 
1182
 
 
1183
        return -errno;
 
1184
}
 
1185
 
 
1186
static int install_info_symlink_alias(
 
1187
                InstallInfo *i,
 
1188
                const char *config_path,
 
1189
                bool force,
 
1190
                UnitFileChange **changes,
 
1191
                unsigned *n_changes) {
 
1192
 
 
1193
        char **s;
 
1194
        int r = 0, q;
 
1195
 
 
1196
        assert(i);
 
1197
        assert(config_path);
 
1198
 
 
1199
        STRV_FOREACH(s, i->aliases) {
 
1200
                _cleanup_free_ char *alias_path = NULL, *dst = NULL;
 
1201
 
 
1202
                dst = install_full_printf(i, *s);
 
1203
                if (!dst)
 
1204
                        return -ENOMEM;
 
1205
 
 
1206
                alias_path = path_make_absolute(dst, config_path);
 
1207
                if (!alias_path)
 
1208
                        return -ENOMEM;
 
1209
 
 
1210
                q = create_symlink(i->path, alias_path, force, changes, n_changes);
 
1211
                if (r == 0)
 
1212
                        r = q;
 
1213
        }
 
1214
 
 
1215
        return r;
 
1216
}
 
1217
 
 
1218
static int install_info_symlink_wants(
 
1219
                InstallInfo *i,
 
1220
                const char *config_path,
 
1221
                bool force,
 
1222
                UnitFileChange **changes,
 
1223
                unsigned *n_changes) {
 
1224
 
 
1225
        char **s;
 
1226
        int r = 0, q;
 
1227
 
 
1228
        assert(i);
 
1229
        assert(config_path);
 
1230
 
 
1231
        STRV_FOREACH(s, i->wanted_by) {
 
1232
                _cleanup_free_ char *path = NULL, *dst = NULL;
 
1233
 
 
1234
                dst = install_full_printf(i, *s);
 
1235
                if (!dst)
 
1236
                        return -ENOMEM;
 
1237
 
 
1238
                if (!unit_name_is_valid(dst, true)) {
 
1239
                        r = -EINVAL;
 
1240
                        continue;
 
1241
                }
 
1242
 
 
1243
                if (asprintf(&path, "%s/%s.wants/%s", config_path, dst, i->name) < 0)
 
1244
                        return -ENOMEM;
 
1245
 
 
1246
                q = create_symlink(i->path, path, force, changes, n_changes);
 
1247
 
 
1248
                if (r == 0)
 
1249
                        r = q;
 
1250
        }
 
1251
 
 
1252
        return r;
 
1253
}
 
1254
 
 
1255
static int install_info_symlink_requires(
 
1256
                InstallInfo *i,
 
1257
                const char *config_path,
 
1258
                bool force,
 
1259
                UnitFileChange **changes,
 
1260
                unsigned *n_changes) {
 
1261
 
 
1262
        char **s;
 
1263
        int r = 0, q;
 
1264
 
 
1265
        assert(i);
 
1266
        assert(config_path);
 
1267
 
 
1268
        STRV_FOREACH(s, i->required_by) {
 
1269
                _cleanup_free_ char *path = NULL, *dst = NULL;
 
1270
 
 
1271
                dst = install_full_printf(i, *s);
 
1272
                if (!dst)
 
1273
                        return -ENOMEM;
 
1274
 
 
1275
                if (!unit_name_is_valid(dst, true)) {
 
1276
                        r = -EINVAL;
 
1277
                        continue;
 
1278
                }
 
1279
 
 
1280
                if (asprintf(&path, "%s/%s.requires/%s", config_path, dst, i->name) < 0)
 
1281
                        return -ENOMEM;
 
1282
 
 
1283
                q = create_symlink(i->path, path, force, changes, n_changes);
 
1284
 
 
1285
                if (r == 0)
 
1286
                        r = q;
 
1287
        }
 
1288
 
 
1289
        return r;
 
1290
}
 
1291
 
 
1292
static int install_info_symlink_link(
 
1293
                InstallInfo *i,
 
1294
                LookupPaths *paths,
 
1295
                const char *config_path,
 
1296
                bool force,
 
1297
                UnitFileChange **changes,
 
1298
                unsigned *n_changes) {
 
1299
 
 
1300
        int r;
 
1301
        _cleanup_free_ char *path = NULL;
 
1302
 
 
1303
        assert(i);
 
1304
        assert(paths);
 
1305
        assert(config_path);
 
1306
        assert(i->path);
 
1307
 
 
1308
        r = in_search_path(i->path, paths->unit_path);
 
1309
        if (r != 0)
 
1310
                return r;
 
1311
 
 
1312
        if (asprintf(&path, "%s/%s", config_path, i->name) < 0)
 
1313
                return -ENOMEM;
 
1314
 
 
1315
        r = create_symlink(i->path, path, force, changes, n_changes);
 
1316
        return r;
 
1317
}
 
1318
 
 
1319
static int install_info_apply(
 
1320
                InstallInfo *i,
 
1321
                LookupPaths *paths,
 
1322
                const char *config_path,
 
1323
                bool force,
 
1324
                UnitFileChange **changes,
 
1325
                unsigned *n_changes) {
 
1326
 
 
1327
        int r, q;
 
1328
 
 
1329
        assert(i);
 
1330
        assert(paths);
 
1331
        assert(config_path);
 
1332
 
 
1333
        r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
 
1334
 
 
1335
        q = install_info_symlink_wants(i, config_path, force, changes, n_changes);
 
1336
        if (r == 0)
 
1337
                r = q;
 
1338
 
 
1339
        q = install_info_symlink_requires(i, config_path, force, changes, n_changes);
 
1340
        if (r == 0)
 
1341
                r = q;
 
1342
 
 
1343
        q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
 
1344
        if (r == 0)
 
1345
                r = q;
 
1346
 
 
1347
        return r;
 
1348
}
 
1349
 
 
1350
static int install_context_apply(
 
1351
                InstallContext *c,
 
1352
                LookupPaths *paths,
 
1353
                const char *config_path,
 
1354
                const char *root_dir,
 
1355
                bool force,
 
1356
                UnitFileChange **changes,
 
1357
                unsigned *n_changes) {
 
1358
 
 
1359
        InstallInfo *i;
 
1360
        int r = 0, q;
 
1361
 
 
1362
        assert(c);
 
1363
        assert(paths);
 
1364
        assert(config_path);
 
1365
 
 
1366
        while ((i = hashmap_first(c->will_install))) {
 
1367
 
 
1368
                q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
 
1369
                if (q < 0)
 
1370
                        return q;
 
1371
 
 
1372
                assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
 
1373
 
 
1374
                q = unit_file_search(c, i, paths, root_dir, false);
 
1375
                if (q < 0) {
 
1376
                        if (r >= 0)
 
1377
                                r = q;
 
1378
 
 
1379
                        return r;
 
1380
                } else if (r >= 0)
 
1381
                        r += q;
 
1382
 
 
1383
                q = install_info_apply(i, paths, config_path, force, changes, n_changes);
 
1384
                if (r >= 0 && q < 0)
 
1385
                        r = q;
 
1386
        }
 
1387
 
 
1388
        return r;
 
1389
}
 
1390
 
 
1391
static int install_context_mark_for_removal(
 
1392
                InstallContext *c,
 
1393
                LookupPaths *paths,
 
1394
                Set **remove_symlinks_to,
 
1395
                const char *config_path,
 
1396
                const char *root_dir) {
 
1397
 
 
1398
        InstallInfo *i;
 
1399
        int r = 0, q;
 
1400
 
 
1401
        assert(c);
 
1402
        assert(paths);
 
1403
        assert(config_path);
 
1404
 
 
1405
        /* Marks all items for removal */
 
1406
 
 
1407
        while ((i = hashmap_first(c->will_install))) {
 
1408
 
 
1409
                q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
 
1410
                if (q < 0)
 
1411
                        return q;
 
1412
 
 
1413
                assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
 
1414
 
 
1415
                q = unit_file_search(c, i, paths, root_dir, false);
 
1416
                if (q < 0) {
 
1417
                        if (r >= 0)
 
1418
                                r = q;
 
1419
 
 
1420
                        return r;
 
1421
                } else if (r >= 0)
 
1422
                        r += q;
 
1423
 
 
1424
                if (unit_name_is_instance(i->name)) {
 
1425
                        char *unit_file = NULL;
 
1426
 
 
1427
                        unit_file = path_get_file_name(i->path);
 
1428
 
 
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);
 
1432
                        else
 
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);
 
1435
                } else
 
1436
                        q = mark_symlink_for_removal(remove_symlinks_to, i->name);
 
1437
 
 
1438
                if (r >= 0 && q < 0)
 
1439
                        r = q;
 
1440
        }
 
1441
 
 
1442
        return r;
 
1443
}
 
1444
 
 
1445
int unit_file_enable(
 
1446
                UnitFileScope scope,
 
1447
                bool runtime,
 
1448
                const char *root_dir,
 
1449
                char *files[],
 
1450
                bool force,
 
1451
                UnitFileChange **changes,
 
1452
                unsigned *n_changes) {
 
1453
 
 
1454
        _cleanup_lookup_paths_free_ LookupPaths paths = {};
 
1455
        _cleanup_install_context_done_ InstallContext c = {};
 
1456
        char **i;
 
1457
        _cleanup_free_ char *config_path = NULL;
 
1458
        int r;
 
1459
 
 
1460
        assert(scope >= 0);
 
1461
        assert(scope < _UNIT_FILE_SCOPE_MAX);
 
1462
 
 
1463
        r = lookup_paths_init_from_scope(&paths, scope);
 
1464
        if (r < 0)
 
1465
                return r;
 
1466
 
 
1467
        r = get_config_path(scope, runtime, root_dir, &config_path);
 
1468
        if (r < 0)
 
1469
                return r;
 
1470
 
 
1471
        STRV_FOREACH(i, files) {
 
1472
                r = install_info_add_auto(&c, *i);
 
1473
                if (r < 0)
 
1474
                        return r;
 
1475
        }
 
1476
 
 
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);
 
1482
        return r;
 
1483
}
 
1484
 
 
1485
int unit_file_disable(
 
1486
                UnitFileScope scope,
 
1487
                bool runtime,
 
1488
                const char *root_dir,
 
1489
                char *files[],
 
1490
                UnitFileChange **changes,
 
1491
                unsigned *n_changes) {
 
1492
 
 
1493
        _cleanup_lookup_paths_free_ LookupPaths paths = {};
 
1494
        _cleanup_install_context_done_ InstallContext c = {};
 
1495
        char **i;
 
1496
        _cleanup_free_ char *config_path = NULL;
 
1497
        _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
 
1498
        int r, q;
 
1499
 
 
1500
        assert(scope >= 0);
 
1501
        assert(scope < _UNIT_FILE_SCOPE_MAX);
 
1502
 
 
1503
        r = lookup_paths_init_from_scope(&paths, scope);
 
1504
        if (r < 0)
 
1505
                return r;
 
1506
 
 
1507
        r = get_config_path(scope, runtime, root_dir, &config_path);
 
1508
        if (r < 0)
 
1509
                return r;
 
1510
 
 
1511
        STRV_FOREACH(i, files) {
 
1512
                r = install_info_add_auto(&c, *i);
 
1513
                if (r < 0)
 
1514
                        return r;
 
1515
        }
 
1516
 
 
1517
        r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
 
1518
 
 
1519
        q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
 
1520
        if (r == 0)
 
1521
                r = q;
 
1522
 
 
1523
        return r;
 
1524
}
 
1525
 
 
1526
int unit_file_reenable(
 
1527
                UnitFileScope scope,
 
1528
                bool runtime,
 
1529
                const char *root_dir,
 
1530
                char *files[],
 
1531
                bool force,
 
1532
                UnitFileChange **changes,
 
1533
                unsigned *n_changes) {
 
1534
 
 
1535
        _cleanup_lookup_paths_free_ LookupPaths paths = {};
 
1536
        _cleanup_install_context_done_ InstallContext c = {};
 
1537
        char **i;
 
1538
        _cleanup_free_ char *config_path = NULL;
 
1539
        _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
 
1540
        int r, q;
 
1541
 
 
1542
        assert(scope >= 0);
 
1543
        assert(scope < _UNIT_FILE_SCOPE_MAX);
 
1544
 
 
1545
        r = lookup_paths_init_from_scope(&paths, scope);
 
1546
        if (r < 0)
 
1547
                return r;
 
1548
 
 
1549
        r = get_config_path(scope, runtime, root_dir, &config_path);
 
1550
        if (r < 0)
 
1551
                return r;
 
1552
 
 
1553
        STRV_FOREACH(i, files) {
 
1554
                r = mark_symlink_for_removal(&remove_symlinks_to, *i);
 
1555
                if (r < 0)
 
1556
                        return r;
 
1557
 
 
1558
                r = install_info_add_auto(&c, *i);
 
1559
                if (r < 0)
 
1560
                        return r;
 
1561
        }
 
1562
 
 
1563
        r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
 
1564
 
 
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);
 
1567
        if (r == 0)
 
1568
                r = q;
 
1569
 
 
1570
        return r;
 
1571
}
 
1572
 
 
1573
UnitFileState unit_file_get_state(
 
1574
                UnitFileScope scope,
 
1575
                const char *root_dir,
 
1576
                const char *name) {
 
1577
 
 
1578
        _cleanup_lookup_paths_free_ LookupPaths paths = {};
 
1579
        UnitFileState state = _UNIT_FILE_STATE_INVALID;
 
1580
        char **i;
 
1581
        _cleanup_free_ char *path = NULL;
 
1582
        int r;
 
1583
 
 
1584
        assert(scope >= 0);
 
1585
        assert(scope < _UNIT_FILE_SCOPE_MAX);
 
1586
        assert(name);
 
1587
 
 
1588
        if (root_dir && scope != UNIT_FILE_SYSTEM)
 
1589
                return -EINVAL;
 
1590
 
 
1591
        if (!unit_name_is_valid(name, true))
 
1592
                return -EINVAL;
 
1593
 
 
1594
        r = lookup_paths_init_from_scope(&paths, scope);
 
1595
        if (r < 0)
 
1596
                return r;
 
1597
 
 
1598
        STRV_FOREACH(i, paths.unit_path) {
 
1599
                struct stat st;
 
1600
 
 
1601
                free(path);
 
1602
                path = NULL;
 
1603
 
 
1604
                if (root_dir)
 
1605
                        asprintf(&path, "%s/%s/%s", root_dir, *i, name);
 
1606
                else
 
1607
                        asprintf(&path, "%s/%s", *i, name);
 
1608
 
 
1609
                if (!path)
 
1610
                        return -ENOMEM;
 
1611
 
 
1612
                if (lstat(path, &st) < 0) {
 
1613
                        r = -errno;
 
1614
                        if (errno == ENOENT)
 
1615
                                continue;
 
1616
 
 
1617
                        return -errno;
 
1618
                }
 
1619
 
 
1620
                if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
 
1621
                        return -ENOENT;
 
1622
 
 
1623
                r = null_or_empty_path(path);
 
1624
                if (r < 0 && r != -ENOENT)
 
1625
                        return r;
 
1626
                else if (r > 0) {
 
1627
                        state = path_startswith(*i, "/run") ?
 
1628
                                UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
 
1629
                        return state;
 
1630
                }
 
1631
 
 
1632
                r = find_symlinks_in_scope(scope, root_dir, name, &state);
 
1633
                if (r < 0)
 
1634
                        return r;
 
1635
                else if (r > 0)
 
1636
                        return state;
 
1637
 
 
1638
                r = unit_file_can_install(&paths, root_dir, path, true);
 
1639
                if (r < 0 && errno != ENOENT)
 
1640
                        return r;
 
1641
                else if (r > 0)
 
1642
                        return UNIT_FILE_DISABLED;
 
1643
                else if (r == 0)
 
1644
                        return UNIT_FILE_STATIC;
 
1645
        }
 
1646
 
 
1647
        return r < 0 ? r : state;
 
1648
}
 
1649
 
 
1650
int unit_file_query_preset(UnitFileScope scope, const char *name) {
 
1651
        _cleanup_strv_free_ char **files = NULL;
 
1652
        char **i;
 
1653
        int r;
 
1654
 
 
1655
        assert(scope >= 0);
 
1656
        assert(scope < _UNIT_FILE_SCOPE_MAX);
 
1657
        assert(name);
 
1658
 
 
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",
 
1666
#endif
 
1667
                                    NULL);
 
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",
 
1673
                                    NULL);
 
1674
        else
 
1675
                return 1;
 
1676
 
 
1677
        if (r < 0)
 
1678
                return r;
 
1679
 
 
1680
        STRV_FOREACH(i, files) {
 
1681
                _cleanup_fclose_ FILE *f;
 
1682
 
 
1683
                f = fopen(*i, "re");
 
1684
                if (!f) {
 
1685
                        if (errno == ENOENT)
 
1686
                                continue;
 
1687
 
 
1688
                        return -errno;
 
1689
                }
 
1690
 
 
1691
                for (;;) {
 
1692
                        char line[LINE_MAX], *l;
 
1693
 
 
1694
                        if (!fgets(line, sizeof(line), f))
 
1695
                                break;
 
1696
 
 
1697
                        l = strstrip(line);
 
1698
                        if (!*l)
 
1699
                                continue;
 
1700
 
 
1701
                        if (strchr(COMMENTS "\n", *l))
 
1702
                                continue;
 
1703
 
 
1704
                        if (first_word(l, "enable")) {
 
1705
                                l += 6;
 
1706
                                l += strspn(l, WHITESPACE);
 
1707
 
 
1708
                                if (fnmatch(l, name, FNM_NOESCAPE) == 0)
 
1709
                                        return 1;
 
1710
 
 
1711
                        } else if (first_word(l, "disable")) {
 
1712
                                l += 7;
 
1713
                                l += strspn(l, WHITESPACE);
 
1714
 
 
1715
                                if (fnmatch(l, name, FNM_NOESCAPE) == 0)
 
1716
                                        return 0;
 
1717
 
 
1718
                        } else
 
1719
                                log_debug("Couldn't parse line '%s'", l);
 
1720
                }
 
1721
        }
 
1722
 
 
1723
        /* Default is "enable" */
 
1724
        return 1;
 
1725
}
 
1726
 
 
1727
int unit_file_preset(
 
1728
                UnitFileScope scope,
 
1729
                bool runtime,
 
1730
                const char *root_dir,
 
1731
                char *files[],
 
1732
                bool force,
 
1733
                UnitFileChange **changes,
 
1734
                unsigned *n_changes) {
 
1735
 
 
1736
        _cleanup_lookup_paths_free_ LookupPaths paths = {};
 
1737
        _cleanup_install_context_done_ InstallContext plus = {}, minus = {};
 
1738
        char **i;
 
1739
        _cleanup_free_ char *config_path = NULL;
 
1740
        _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
 
1741
        int r, q;
 
1742
 
 
1743
        assert(scope >= 0);
 
1744
        assert(scope < _UNIT_FILE_SCOPE_MAX);
 
1745
 
 
1746
        r = lookup_paths_init_from_scope(&paths, scope);
 
1747
        if (r < 0)
 
1748
                return r;
 
1749
 
 
1750
        r = get_config_path(scope, runtime, root_dir, &config_path);
 
1751
        if (r < 0)
 
1752
                return r;
 
1753
 
 
1754
        STRV_FOREACH(i, files) {
 
1755
 
 
1756
                if (!unit_name_is_valid(*i, true))
 
1757
                        return -EINVAL;
 
1758
 
 
1759
                r = unit_file_query_preset(scope, *i);
 
1760
                if (r < 0)
 
1761
                        return r;
 
1762
 
 
1763
                if (r)
 
1764
                        r = install_info_add_auto(&plus, *i);
 
1765
                else
 
1766
                        r = install_info_add_auto(&minus, *i);
 
1767
 
 
1768
                if (r < 0)
 
1769
                        return r;
 
1770
        }
 
1771
 
 
1772
        r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to,
 
1773
                                             config_path, root_dir);
 
1774
 
 
1775
        q = remove_marked_symlinks(remove_symlinks_to, config_path,
 
1776
                                   changes, n_changes, files);
 
1777
        if (r == 0)
 
1778
                r = q;
 
1779
 
 
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);
 
1783
        if (r == 0)
 
1784
                r = q;
 
1785
 
 
1786
        return r;
 
1787
}
 
1788
 
 
1789
static void unitfilelist_free(UnitFileList **f) {
 
1790
        if (!*f)
 
1791
                return;
 
1792
 
 
1793
        free((*f)->path);
 
1794
        free(*f);
 
1795
}
 
1796
 
 
1797
int unit_file_get_list(
 
1798
                UnitFileScope scope,
 
1799
                const char *root_dir,
 
1800
                Hashmap *h) {
 
1801
 
 
1802
        _cleanup_lookup_paths_free_ LookupPaths paths = {};
 
1803
        char **i;
 
1804
        _cleanup_free_ char *buf = NULL;
 
1805
        _cleanup_closedir_ DIR *d = NULL;
 
1806
        int r;
 
1807
 
 
1808
        assert(scope >= 0);
 
1809
        assert(scope < _UNIT_FILE_SCOPE_MAX);
 
1810
        assert(h);
 
1811
 
 
1812
        if (root_dir && scope != UNIT_FILE_SYSTEM)
 
1813
                return -EINVAL;
 
1814
 
 
1815
        r = lookup_paths_init_from_scope(&paths, scope);
 
1816
        if (r < 0)
 
1817
                return r;
 
1818
 
 
1819
        STRV_FOREACH(i, paths.unit_path) {
 
1820
                const char *units_dir;
 
1821
 
 
1822
                free(buf);
 
1823
                buf = NULL;
 
1824
 
 
1825
                if (root_dir) {
 
1826
                        if (asprintf(&buf, "%s/%s", root_dir, *i) < 0)
 
1827
                                return -ENOMEM;
 
1828
 
 
1829
                        units_dir = buf;
 
1830
                } else
 
1831
                        units_dir = *i;
 
1832
 
 
1833
                if (d)
 
1834
                        closedir(d);
 
1835
 
 
1836
                d = opendir(units_dir);
 
1837
                if (!d) {
 
1838
                        if (errno == ENOENT)
 
1839
                                continue;
 
1840
 
 
1841
                        return -errno;
 
1842
                }
 
1843
 
 
1844
                for (;;) {
 
1845
                        struct dirent *de;
 
1846
                        union dirent_storage buffer;
 
1847
                        UnitFileList __attribute__((cleanup(unitfilelist_free)))
 
1848
                                *f = NULL;
 
1849
 
 
1850
                        r = readdir_r(d, &buffer.de, &de);
 
1851
                        if (r != 0)
 
1852
                                return -r;
 
1853
 
 
1854
                        if (!de)
 
1855
                                break;
 
1856
 
 
1857
                        if (ignore_file(de->d_name))
 
1858
                                continue;
 
1859
 
 
1860
                        if (!unit_name_is_valid(de->d_name, true))
 
1861
                                continue;
 
1862
 
 
1863
                        if (hashmap_get(h, de->d_name))
 
1864
                                continue;
 
1865
 
 
1866
                        r = dirent_ensure_type(d, de);
 
1867
                        if (r < 0) {
 
1868
                                if (r == -ENOENT)
 
1869
                                        continue;
 
1870
 
 
1871
                                return r;
 
1872
                        }
 
1873
 
 
1874
                        if (de->d_type != DT_LNK && de->d_type != DT_REG)
 
1875
                                continue;
 
1876
 
 
1877
                        f = new0(UnitFileList, 1);
 
1878
                        if (!f)
 
1879
                                return -ENOMEM;
 
1880
 
 
1881
                        f->path = path_make_absolute(de->d_name, units_dir);
 
1882
                        if (!f->path)
 
1883
                                return -ENOMEM;
 
1884
 
 
1885
                        r = null_or_empty_path(f->path);
 
1886
                        if (r < 0 && r != -ENOENT)
 
1887
                                return r;
 
1888
                        else if (r > 0) {
 
1889
                                f->state =
 
1890
                                        path_startswith(*i, "/run") ?
 
1891
                                        UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
 
1892
                                goto found;
 
1893
                        }
 
1894
 
 
1895
                        r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
 
1896
                        if (r < 0)
 
1897
                                return r;
 
1898
                        else if (r > 0) {
 
1899
                                f->state = UNIT_FILE_ENABLED;
 
1900
                                goto found;
 
1901
                        }
 
1902
 
 
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;
 
1908
                        else if (r < 0)
 
1909
                                return r;
 
1910
                        else if (r > 0)
 
1911
                                f->state = UNIT_FILE_DISABLED;
 
1912
                        else
 
1913
                                f->state = UNIT_FILE_STATIC;
 
1914
 
 
1915
                found:
 
1916
                        r = hashmap_put(h, path_get_file_name(f->path), f);
 
1917
                        if (r < 0)
 
1918
                                return r;
 
1919
                        f = NULL; /* prevent cleanup */
 
1920
                }
 
1921
        }
 
1922
 
 
1923
        return r;
 
1924
}
 
1925
 
 
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",
 
1936
};
 
1937
 
 
1938
DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
 
1939
 
 
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",
 
1943
};
 
1944
 
 
1945
DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);