chiark / gitweb /
tmpfiles: let's always use DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING() instead...
[elogind.git] / src / tmpfiles / tmpfiles.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering, Kay Sievers
7   Copyright 2015 Zbigniew JÄ™drzejewski-Szmek
8
9   systemd is free software; you can redistribute it and/or modify it
10   under the terms of the GNU Lesser General Public License as published by
11   the Free Software Foundation; either version 2.1 of the License, or
12   (at your option) any later version.
13
14   systemd is distributed in the hope that it will be useful, but
15   WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   Lesser General Public License for more details.
18
19   You should have received a copy of the GNU Lesser General Public License
20   along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 ***/
22
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <errno.h>
26 #include <string.h>
27 #include <limits.h>
28 #include <dirent.h>
29 #include <grp.h>
30 #include <pwd.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stddef.h>
34 #include <getopt.h>
35 #include <stdbool.h>
36 #include <time.h>
37 #include <glob.h>
38 #include <fnmatch.h>
39 #include <sys/stat.h>
40 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <sys/xattr.h>
43
44 #include "log.h"
45 #include "util.h"
46 #include "macro.h"
47 #include "missing.h"
48 #include "mkdir.h"
49 #include "path-util.h"
50 #include "strv.h"
51 #include "label.h"
52 #include "set.h"
53 #include "conf-files.h"
54 #include "capability.h"
55 #include "specifier.h"
56 #include "build.h"
57 #include "copy.h"
58 #include "selinux-util.h"
59 #include "btrfs-util.h"
60 #include "acl-util.h"
61
62 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
63  * them in the file system. This is intended to be used to create
64  * properly owned directories beneath /tmp, /var/tmp, /run, which are
65  * volatile and hence need to be recreated on bootup. */
66
67 typedef enum ItemType {
68         /* These ones take file names */
69         CREATE_FILE = 'f',
70         TRUNCATE_FILE = 'F',
71         CREATE_DIRECTORY = 'd',
72         TRUNCATE_DIRECTORY = 'D',
73         CREATE_SUBVOLUME = 'v',
74         CREATE_FIFO = 'p',
75         CREATE_SYMLINK = 'L',
76         CREATE_CHAR_DEVICE = 'c',
77         CREATE_BLOCK_DEVICE = 'b',
78         COPY_FILES = 'C',
79
80         /* These ones take globs */
81         SET_XATTR = 't',
82         RECURSIVE_SET_XATTR = 'T',
83         SET_ACL = 'a',
84         RECURSIVE_SET_ACL = 'A',
85         WRITE_FILE = 'w',
86         IGNORE_PATH = 'x',
87         IGNORE_DIRECTORY_PATH = 'X',
88         REMOVE_PATH = 'r',
89         RECURSIVE_REMOVE_PATH = 'R',
90         ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
91         RELABEL_PATH = 'z',
92         RECURSIVE_RELABEL_PATH = 'Z',
93 } ItemType;
94
95 typedef struct Item {
96         ItemType type;
97
98         char *path;
99         char *argument;
100         char **xattrs;
101 #ifdef HAVE_ACL
102         acl_t acl_access;
103         acl_t acl_default;
104 #endif
105         uid_t uid;
106         gid_t gid;
107         mode_t mode;
108         usec_t age;
109
110         dev_t major_minor;
111
112         bool uid_set:1;
113         bool gid_set:1;
114         bool mode_set:1;
115         bool age_set:1;
116         bool mask_perms:1;
117
118         bool keep_first_level:1;
119
120         bool force:1;
121
122         bool done:1;
123 } Item;
124
125 typedef struct ItemArray {
126         Item *items;
127         size_t count;
128         size_t size;
129 } ItemArray;
130
131 static bool arg_create = false;
132 static bool arg_clean = false;
133 static bool arg_remove = false;
134 static bool arg_boot = false;
135
136 static char **arg_include_prefixes = NULL;
137 static char **arg_exclude_prefixes = NULL;
138 static char *arg_root = NULL;
139
140 static const char conf_file_dirs[] = CONF_DIRS_NULSTR("tmpfiles");
141
142 #define MAX_DEPTH 256
143
144 static Hashmap *items = NULL, *globs = NULL;
145 static Set *unix_sockets = NULL;
146
147 static bool needs_glob(ItemType t) {
148         return IN_SET(t,
149                       WRITE_FILE,
150                       IGNORE_PATH,
151                       IGNORE_DIRECTORY_PATH,
152                       REMOVE_PATH,
153                       RECURSIVE_REMOVE_PATH,
154                       ADJUST_MODE,
155                       RELABEL_PATH,
156                       RECURSIVE_RELABEL_PATH,
157                       SET_XATTR,
158                       RECURSIVE_SET_XATTR,
159                       SET_ACL,
160                       RECURSIVE_SET_ACL);
161 }
162
163 static bool takes_ownership(ItemType t) {
164         return IN_SET(t,
165                       CREATE_FILE,
166                       TRUNCATE_FILE,
167                       CREATE_DIRECTORY,
168                       TRUNCATE_DIRECTORY,
169                       CREATE_SUBVOLUME,
170                       CREATE_FIFO,
171                       CREATE_SYMLINK,
172                       CREATE_CHAR_DEVICE,
173                       CREATE_BLOCK_DEVICE,
174                       COPY_FILES,
175
176                       WRITE_FILE,
177                       IGNORE_PATH,
178                       IGNORE_DIRECTORY_PATH,
179                       REMOVE_PATH,
180                       RECURSIVE_REMOVE_PATH);
181 }
182
183 static struct Item* find_glob(Hashmap *h, const char *match) {
184         ItemArray *j;
185         Iterator i;
186
187         HASHMAP_FOREACH(j, h, i) {
188                 unsigned n;
189
190                 for (n = 0; n < j->count; n++) {
191                         Item *item = j->items + n;
192
193                         if (fnmatch(item->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
194                                 return item;
195                 }
196         }
197
198         return NULL;
199 }
200
201 static void load_unix_sockets(void) {
202         _cleanup_fclose_ FILE *f = NULL;
203         char line[LINE_MAX];
204
205         if (unix_sockets)
206                 return;
207
208         /* We maintain a cache of the sockets we found in
209          * /proc/net/unix to speed things up a little. */
210
211         unix_sockets = set_new(&string_hash_ops);
212         if (!unix_sockets)
213                 return;
214
215         f = fopen("/proc/net/unix", "re");
216         if (!f)
217                 return;
218
219         /* Skip header */
220         if (!fgets(line, sizeof(line), f))
221                 goto fail;
222
223         for (;;) {
224                 char *p, *s;
225                 int k;
226
227                 if (!fgets(line, sizeof(line), f))
228                         break;
229
230                 truncate_nl(line);
231
232                 p = strchr(line, ':');
233                 if (!p)
234                         continue;
235
236                 if (strlen(p) < 37)
237                         continue;
238
239                 p += 37;
240                 p += strspn(p, WHITESPACE);
241                 p += strcspn(p, WHITESPACE); /* skip one more word */
242                 p += strspn(p, WHITESPACE);
243
244                 if (*p != '/')
245                         continue;
246
247                 s = strdup(p);
248                 if (!s)
249                         goto fail;
250
251                 path_kill_slashes(s);
252
253                 k = set_consume(unix_sockets, s);
254                 if (k < 0 && k != -EEXIST)
255                         goto fail;
256         }
257
258         return;
259
260 fail:
261         set_free_free(unix_sockets);
262         unix_sockets = NULL;
263 }
264
265 static bool unix_socket_alive(const char *fn) {
266         assert(fn);
267
268         load_unix_sockets();
269
270         if (unix_sockets)
271                 return !!set_get(unix_sockets, (char*) fn);
272
273         /* We don't know, so assume yes */
274         return true;
275 }
276
277 static int dir_is_mount_point(DIR *d, const char *subdir) {
278
279         union file_handle_union h = FILE_HANDLE_INIT;
280         int mount_id_parent, mount_id;
281         int r_p, r;
282
283         r_p = name_to_handle_at(dirfd(d), ".", &h.handle, &mount_id_parent, 0);
284         if (r_p < 0)
285                 r_p = -errno;
286
287         h.handle.handle_bytes = MAX_HANDLE_SZ;
288         r = name_to_handle_at(dirfd(d), subdir, &h.handle, &mount_id, 0);
289         if (r < 0)
290                 r = -errno;
291
292         /* got no handle; make no assumptions, return error */
293         if (r_p < 0 && r < 0)
294                 return r_p;
295
296         /* got both handles; if they differ, it is a mount point */
297         if (r_p >= 0 && r >= 0)
298                 return mount_id_parent != mount_id;
299
300         /* got only one handle; assume different mount points if one
301          * of both queries was not supported by the filesystem */
302         if (r_p == -ENOSYS || r_p == -EOPNOTSUPP || r == -ENOSYS || r == -EOPNOTSUPP)
303                 return true;
304
305         /* return error */
306         if (r_p < 0)
307                 return r_p;
308         return r;
309 }
310
311 static DIR* xopendirat_nomod(int dirfd, const char *path) {
312         DIR *dir;
313
314         dir = xopendirat(dirfd, path, O_NOFOLLOW|O_NOATIME);
315         if (!dir) {
316                 log_debug_errno(errno, "Cannot open %sdirectory \"%s\": %m",
317                                 dirfd == AT_FDCWD ? "" : "sub", path);
318                 if (errno == EPERM) {
319                         dir = xopendirat(dirfd, path, O_NOFOLLOW);
320                         if (!dir)
321                                 log_debug_errno(errno, "Cannot open %sdirectory \"%s\": %m",
322                                                 dirfd == AT_FDCWD ? "" : "sub", path);
323                 }
324         }
325
326         return dir;
327 }
328
329 static DIR* opendir_nomod(const char *path) {
330         return xopendirat_nomod(AT_FDCWD, path);
331 }
332
333 static int dir_cleanup(
334                 Item *i,
335                 const char *p,
336                 DIR *d,
337                 const struct stat *ds,
338                 usec_t cutoff,
339                 dev_t rootdev,
340                 bool mountpoint,
341                 int maxdepth,
342                 bool keep_this_level) {
343
344         struct dirent *dent;
345         struct timespec times[2];
346         bool deleted = false;
347         int r = 0;
348
349         while ((dent = readdir(d))) {
350                 struct stat s;
351                 usec_t age;
352                 _cleanup_free_ char *sub_path = NULL;
353
354                 if (STR_IN_SET(dent->d_name, ".", ".."))
355                         continue;
356
357                 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
358                         if (errno == ENOENT)
359                                 continue;
360
361                         /* FUSE, NFS mounts, SELinux might return EACCES */
362                         if (errno == EACCES)
363                                 log_debug_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
364                         else
365                                 log_error_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
366                         r = -errno;
367                         continue;
368                 }
369
370                 /* Stay on the same filesystem */
371                 if (s.st_dev != rootdev) {
372                         log_debug("Ignoring \"%s/%s\": different filesystem.", p, dent->d_name);
373                         continue;
374                 }
375
376                 /* Try to detect bind mounts of the same filesystem instance; they
377                  * do not differ in device major/minors. This type of query is not
378                  * supported on all kernels or filesystem types though. */
379                 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0) {
380                         log_debug("Ignoring \"%s/%s\": different mount of the same filesystem.",
381                                   p, dent->d_name);
382                         continue;
383                 }
384
385                 /* Do not delete read-only files owned by root */
386                 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR)) {
387                         log_debug("Ignoring \"%s/%s\": read-only and owner by root.", p, dent->d_name);
388                         continue;
389                 }
390
391                 sub_path = strjoin(p, "/", dent->d_name, NULL);
392                 if (!sub_path) {
393                         r = log_oom();
394                         goto finish;
395                 }
396
397                 /* Is there an item configured for this path? */
398                 if (hashmap_get(items, sub_path)) {
399                         log_debug("Ignoring \"%s\": a separate entry exists.", sub_path);
400                         continue;
401                 }
402
403                 if (find_glob(globs, sub_path)) {
404                         log_debug("Ignoring \"%s\": a separate glob exists.", sub_path);
405                         continue;
406                 }
407
408                 if (S_ISDIR(s.st_mode)) {
409
410                         if (mountpoint &&
411                             streq(dent->d_name, "lost+found") &&
412                             s.st_uid == 0) {
413                                 log_debug("Ignoring \"%s\".", sub_path);
414                                 continue;
415                         }
416
417                         if (maxdepth <= 0)
418                                 log_warning("Reached max depth on \"%s\".", sub_path);
419                         else {
420                                 _cleanup_closedir_ DIR *sub_dir;
421                                 int q;
422
423                                 sub_dir = xopendirat_nomod(dirfd(d), dent->d_name);
424                                 if (!sub_dir) {
425                                         if (errno != ENOENT)
426                                                 r = log_error_errno(errno, "opendir(%s) failed: %m", sub_path);
427
428                                         continue;
429                                 }
430
431                                 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
432                                 if (q < 0)
433                                         r = q;
434                         }
435
436                         /* Note: if you are wondering why we don't
437                          * support the sticky bit for excluding
438                          * directories from cleaning like we do it for
439                          * other file system objects: well, the sticky
440                          * bit already has a meaning for directories,
441                          * so we don't want to overload that. */
442
443                         if (keep_this_level) {
444                                 log_debug("Keeping \"%s\".", sub_path);
445                                 continue;
446                         }
447
448                         /* Ignore ctime, we change it when deleting */
449                         age = timespec_load(&s.st_mtim);
450                         if (age >= cutoff) {
451                                 char a[FORMAT_TIMESTAMP_MAX];
452                                 /* Follows spelling in stat(1). */
453                                 log_debug("Directory \"%s\": modify time %s is too new.",
454                                           sub_path,
455                                           format_timestamp_us(a, sizeof(a), age));
456                                 continue;
457                         }
458
459                         age = timespec_load(&s.st_atim);
460                         if (age >= cutoff) {
461                                 char a[FORMAT_TIMESTAMP_MAX];
462                                 log_debug("Directory \"%s\": access time %s is too new.",
463                                           sub_path,
464                                           format_timestamp_us(a, sizeof(a), age));
465                                 continue;
466                         }
467
468                         log_debug("Removing directory \"%s\".", sub_path);
469                         if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0)
470                                 if (errno != ENOENT && errno != ENOTEMPTY) {
471                                         log_error_errno(errno, "rmdir(%s): %m", sub_path);
472                                         r = -errno;
473                                 }
474
475                 } else {
476                         /* Skip files for which the sticky bit is
477                          * set. These are semantics we define, and are
478                          * unknown elsewhere. See XDG_RUNTIME_DIR
479                          * specification for details. */
480                         if (s.st_mode & S_ISVTX) {
481                                 log_debug("Skipping \"%s\": sticky bit set.", sub_path);
482                                 continue;
483                         }
484
485                         if (mountpoint && S_ISREG(s.st_mode))
486                                 if ((streq(dent->d_name, ".journal") && s.st_uid == 0) ||
487                                     streq(dent->d_name, "aquota.user") ||
488                                     streq(dent->d_name, "aquota.group")) {
489                                         log_debug("Skipping \"%s\".", sub_path);
490                                         continue;
491                                 }
492
493                         /* Ignore sockets that are listed in /proc/net/unix */
494                         if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path)) {
495                                 log_debug("Skipping \"%s\": live socket.", sub_path);
496                                 continue;
497                         }
498
499                         /* Ignore device nodes */
500                         if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode)) {
501                                 log_debug("Skipping \"%s\": a device.", sub_path);
502                                 continue;
503                         }
504
505                         /* Keep files on this level around if this is
506                          * requested */
507                         if (keep_this_level) {
508                                 log_debug("Keeping \"%s\".", sub_path);
509                                 continue;
510                         }
511
512                         age = timespec_load(&s.st_mtim);
513                         if (age >= cutoff) {
514                                 char a[FORMAT_TIMESTAMP_MAX];
515                                 /* Follows spelling in stat(1). */
516                                 log_debug("File \"%s\": modify time %s is too new.",
517                                           sub_path,
518                                           format_timestamp_us(a, sizeof(a), age));
519                                 continue;
520                         }
521
522                         age = timespec_load(&s.st_atim);
523                         if (age >= cutoff) {
524                                 char a[FORMAT_TIMESTAMP_MAX];
525                                 log_debug("File \"%s\": access time %s is too new.",
526                                           sub_path,
527                                           format_timestamp_us(a, sizeof(a), age));
528                                 continue;
529                         }
530
531                         age = timespec_load(&s.st_ctim);
532                         if (age >= cutoff) {
533                                 char a[FORMAT_TIMESTAMP_MAX];
534                                 log_debug("File \"%s\": change time %s is too new.",
535                                           sub_path,
536                                           format_timestamp_us(a, sizeof(a), age));
537                                 continue;
538                         }
539
540                         log_debug("unlink \"%s\"", sub_path);
541
542                         if (unlinkat(dirfd(d), dent->d_name, 0) < 0)
543                                 if (errno != ENOENT)
544                                         r = log_error_errno(errno, "unlink(%s): %m", sub_path);
545
546                         deleted = true;
547                 }
548         }
549
550 finish:
551         if (deleted) {
552                 usec_t age1, age2;
553                 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX];
554
555                 /* Restore original directory timestamps */
556                 times[0] = ds->st_atim;
557                 times[1] = ds->st_mtim;
558
559                 age1 = timespec_load(&ds->st_atim);
560                 age2 = timespec_load(&ds->st_mtim);
561                 log_debug("Restoring access and modification time on \"%s\": %s, %s",
562                           p,
563                           format_timestamp_us(a, sizeof(a), age1),
564                           format_timestamp_us(b, sizeof(b), age2));
565                 if (futimens(dirfd(d), times) < 0)
566                         log_error_errno(errno, "utimensat(%s): %m", p);
567         }
568
569         return r;
570 }
571
572 static int path_set_perms(Item *i, const char *path) {
573         struct stat st;
574         bool st_valid;
575
576         assert(i);
577         assert(path);
578
579         st_valid = stat(path, &st) == 0;
580
581         /* not using i->path directly because it may be a glob */
582         if (i->mode_set) {
583                 mode_t m = i->mode;
584
585                 if (i->mask_perms && st_valid) {
586                         if (!(st.st_mode & 0111))
587                                 m &= ~0111;
588                         if (!(st.st_mode & 0222))
589                                 m &= ~0222;
590                         if (!(st.st_mode & 0444))
591                                 m &= ~0444;
592                         if (!S_ISDIR(st.st_mode))
593                                 m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
594                 }
595
596                 if (st_valid && m == (st.st_mode & 07777))
597                         log_debug("\"%s\" has right mode %o", path, st.st_mode);
598                 else {
599                         log_debug("chmod \"%s\" to mode %o", path, m);
600                         if (chmod(path, m) < 0)
601                                 return log_error_errno(errno, "chmod(%s) failed: %m", path);
602                 }
603         }
604
605         if ((!st_valid || i->uid != st.st_uid || i->gid != st.st_gid) &&
606             (i->uid_set || i->gid_set)) {
607                 log_debug("chown \"%s\" to "UID_FMT"."GID_FMT,
608                           path,
609                           i->uid_set ? i->uid : UID_INVALID,
610                           i->gid_set ? i->gid : GID_INVALID);
611                 if (chown(path,
612                           i->uid_set ? i->uid : UID_INVALID,
613                           i->gid_set ? i->gid : GID_INVALID) < 0)
614
615                         return log_error_errno(errno, "chown(%s) failed: %m", path);
616         }
617
618         return label_fix(path, false, false);
619 }
620
621 static int get_xattrs_from_arg(Item *i) {
622         char *xattr;
623         const char *p;
624         int r;
625
626         assert(i);
627         assert(i->argument);
628
629         p = i->argument;
630
631         while ((r = unquote_first_word(&p, &xattr, false)) > 0) {
632                 _cleanup_free_ char *tmp = NULL, *name = NULL,
633                         *value = NULL, *value2 = NULL, *_xattr = xattr;
634
635                 r = split_pair(xattr, "=", &name, &value);
636                 if (r < 0) {
637                         log_warning("Illegal xattr found: \"%s\" - ignoring.", xattr);
638                         continue;
639                 }
640
641                 if (strempty(name) || strempty(value)) {
642                         log_warning("Malformed xattr found: \"%s\" - ignoring.", xattr);
643                         continue;
644                 }
645
646                 tmp = unquote(value, "\"");
647                 if (!tmp)
648                         return log_oom();
649
650                 value2 = cunescape(tmp);
651                 if (!value2)
652                         return log_oom();
653
654                 if (strv_push_pair(&i->xattrs, name, value2) < 0)
655                         return log_oom();
656                 name = value2 = NULL;
657         }
658
659         return r;
660 }
661
662 static int path_set_xattrs(Item *i, const char *path) {
663         char **name, **value;
664
665         assert(i);
666         assert(path);
667
668         STRV_FOREACH_PAIR(name, value, i->xattrs) {
669                 int n;
670
671                 n = strlen(*value);
672                 log_debug("\"%s\": setting xattr \"%s=%s\"", path, *name, *value);
673                 if (lsetxattr(path, *name, *value, n, 0) < 0) {
674                         log_error("Setting extended attribute %s=%s on %s failed: %m",
675                                   *name, *value, path);
676                         return -errno;
677                 }
678         }
679         return 0;
680 }
681
682 static int get_acls_from_arg(Item *item) {
683 #ifdef HAVE_ACL
684         int r;
685         _cleanup_(acl_freep) acl_t a = NULL, d = NULL;
686
687         assert(item);
688
689         /* If force (= modify) is set, we will not modify the acl
690          * afterwards, so the mask can be added now if necessary. */
691         r = parse_acl(item->argument, &item->acl_access, &item->acl_default, !item->force);
692         if (r < 0)
693                 log_warning_errno(errno, "Failed to parse ACL \"%s\": %m. Ignoring",
694                                   item->argument);
695 #else
696         log_warning_errno(ENOSYS, "ACLs are not supported. Ignoring");
697 #endif
698
699         return 0;
700 }
701
702 static int path_set_acl(const char *path, acl_type_t type, acl_t acl, bool modify) {
703         _cleanup_(acl_freep) acl_t dup = NULL;
704         int r;
705         _cleanup_(acl_free_charpp) char *t = NULL;
706
707         if (modify) {
708                 r = acls_for_file(path, type, acl, &dup);
709                 if (r < 0)
710                         return r;
711
712                 r = calc_acl_mask_if_needed(&dup);
713                 if (r < 0)
714                         return r;
715         } else {
716                 dup = acl_dup(acl);
717                 if (!dup)
718                         return -errno;
719
720                 /* the mask was already added earlier if needed */
721         }
722
723         r = add_base_acls_if_needed(&dup, path);
724         if (r < 0)
725                 return r;
726
727         t = acl_to_any_text(dup, NULL, ',', TEXT_ABBREVIATE);
728         log_debug("\"%s\": setting %s ACL \"%s\"", path,
729                   type == ACL_TYPE_ACCESS ? "access" : "default",
730                   strna(t));
731
732         r = acl_set_file(path, type, dup);
733         if (r < 0)
734                 return log_error_errno(-errno,
735                                        "Setting %s ACL \"%s\" on %s failed: %m",
736                                        type == ACL_TYPE_ACCESS ? "access" : "default",
737                                        strna(t), path);
738         return 0;
739 }
740
741 static int path_set_acls(Item *item, const char *path) {
742 #ifdef HAVE_ACL
743         int r;
744
745         assert(item);
746         assert(path);
747
748         if (item->acl_access) {
749                 r = path_set_acl(path, ACL_TYPE_ACCESS, item->acl_access, item->force);
750                 if (r < 0)
751                         return r;
752         }
753
754         if (item->acl_default) {
755                 r = path_set_acl(path, ACL_TYPE_DEFAULT, item->acl_default, item->force);
756                 if (r < 0)
757                         return r;
758         }
759 #endif
760
761         return 0;
762 }
763
764 static int write_one_file(Item *i, const char *path) {
765         _cleanup_close_ int fd = -1;
766         int flags, r = 0;
767         struct stat st;
768
769         assert(i);
770         assert(path);
771
772         flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND|O_NOFOLLOW :
773                 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
774
775         RUN_WITH_UMASK(0000) {
776                 mac_selinux_create_file_prepare(path, S_IFREG);
777                 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
778                 mac_selinux_create_file_clear();
779         }
780
781         if (fd < 0) {
782                 if (i->type == WRITE_FILE && errno == ENOENT) {
783                         log_debug_errno(errno, "Not writing \"%s\": %m", path);
784                         return 0;
785                 }
786
787                 log_error_errno(errno, "Failed to create file %s: %m", path);
788                 return -errno;
789         }
790
791         if (i->argument) {
792                 _cleanup_free_ char *unescaped;
793
794                 log_debug("%s to \"%s\".",
795                           i->type == CREATE_FILE ? "Appending" : "Writing", path);
796
797                 unescaped = cunescape(i->argument);
798                 if (!unescaped)
799                         return log_oom();
800
801                 r = loop_write(fd, unescaped, strlen(unescaped), false);
802                 if (r < 0)
803                         return log_error_errno(r, "Failed to write file \"%s\": %m", path);
804         } else
805                 log_debug("\"%s\" has been created.", path);
806
807         fd = safe_close(fd);
808
809         if (stat(path, &st) < 0)
810                 return log_error_errno(errno, "stat(%s) failed: %m", path);
811
812         if (!S_ISREG(st.st_mode)) {
813                 log_error("%s is not a file.", path);
814                 return -EEXIST;
815         }
816
817         r = path_set_perms(i, path);
818         if (r < 0)
819                 return r;
820
821         return 0;
822 }
823
824 typedef int (*action_t)(Item *, const char *);
825
826 static int item_do_children(Item *i, const char *path, action_t action) {
827         _cleanup_closedir_ DIR *d;
828         int r = 0;
829
830         assert(i);
831         assert(path);
832
833         /* This returns the first error we run into, but nevertheless
834          * tries to go on */
835
836         d = opendir_nomod(path);
837         if (!d)
838                 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
839
840         for (;;) {
841                 _cleanup_free_ char *p = NULL;
842                 struct dirent *de;
843                 int q;
844
845                 errno = 0;
846                 de = readdir(d);
847                 if (!de) {
848                         if (errno != 0 && r == 0)
849                                 r = -errno;
850
851                         break;
852                 }
853
854                 if (STR_IN_SET(de->d_name, ".", ".."))
855                         continue;
856
857                 p = strjoin(path, "/", de->d_name, NULL);
858                 if (!p)
859                         return -ENOMEM;
860
861                 q = action(i, p);
862                 if (q < 0 && q != -ENOENT && r == 0)
863                         r = q;
864
865                 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
866                         q = item_do_children(i, p, action);
867                         if (q < 0 && r == 0)
868                                 r = q;
869                 }
870         }
871
872         return r;
873 }
874
875 static int glob_item(Item *i, action_t action, bool recursive) {
876         _cleanup_globfree_ glob_t g = {
877                 .gl_closedir = (void (*)(void *)) closedir,
878                 .gl_readdir = (struct dirent *(*)(void *)) readdir,
879                 .gl_opendir = (void *(*)(const char *)) opendir_nomod,
880                 .gl_lstat = lstat,
881                 .gl_stat = stat,
882         };
883         int r = 0, k;
884         char **fn;
885
886         errno = 0;
887         k = glob(i->path, GLOB_NOSORT|GLOB_BRACE|GLOB_ALTDIRFUNC, NULL, &g);
888         if (k != 0 && k != GLOB_NOMATCH)
889                 return log_error_errno(errno ?: EIO, "glob(%s) failed: %m", i->path);
890
891         STRV_FOREACH(fn, g.gl_pathv) {
892                 k = action(i, *fn);
893                 if (k < 0 && r == 0)
894                         r = k;
895
896                 if (recursive) {
897                         k = item_do_children(i, *fn, action);
898                         if (k < 0 && r == 0)
899                                 r = k;
900                 }
901         }
902
903         return r;
904 }
905
906 typedef enum {
907         CREATION_NORMAL,
908         CREATION_EXISTING,
909         CREATION_FORCE,
910         _CREATION_MODE_MAX,
911         _CREATION_MODE_INVALID = -1
912 } CreationMode;
913
914 static const char *creation_mode_verb_table[_CREATION_MODE_MAX] = {
915         [CREATION_NORMAL] = "Created",
916         [CREATION_EXISTING] = "Found existing",
917         [CREATION_FORCE] = "Created replacement",
918 };
919
920 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb, CreationMode);
921
922 static int create_item(Item *i) {
923         struct stat st;
924         int r = 0;
925         CreationMode creation;
926
927         assert(i);
928
929         log_debug("Running create action for entry %c %s", (char) i->type, i->path);
930
931         switch (i->type) {
932
933         case IGNORE_PATH:
934         case IGNORE_DIRECTORY_PATH:
935         case REMOVE_PATH:
936         case RECURSIVE_REMOVE_PATH:
937                 return 0;
938
939         case CREATE_FILE:
940         case TRUNCATE_FILE:
941                 r = write_one_file(i, i->path);
942                 if (r < 0)
943                         return r;
944                 break;
945
946         case COPY_FILES:
947                 log_debug("Copying tree \"%s\" to \"%s\".", i->argument, i->path);
948                 r = copy_tree(i->argument, i->path, false);
949                 if (r < 0) {
950                         struct stat a, b;
951
952                         if (r != -EEXIST)
953                                 return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
954
955                         if (stat(i->argument, &a) < 0)
956                                 return log_error_errno(errno, "stat(%s) failed: %m", i->argument);
957
958                         if (stat(i->path, &b) < 0)
959                                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
960
961                         if ((a.st_mode ^ b.st_mode) & S_IFMT) {
962                                 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
963                                 return 0;
964                         }
965                 }
966
967                 r = path_set_perms(i, i->path);
968                 if (r < 0)
969                         return r;
970
971                 break;
972
973         case WRITE_FILE:
974                 r = glob_item(i, write_one_file, false);
975                 if (r < 0)
976                         return r;
977
978                 break;
979
980         case CREATE_DIRECTORY:
981         case TRUNCATE_DIRECTORY:
982         case CREATE_SUBVOLUME:
983
984                 RUN_WITH_UMASK(0000)
985                         mkdir_parents_label(i->path, 0755);
986
987                 if (i->type == CREATE_SUBVOLUME)
988                         RUN_WITH_UMASK((~i->mode) & 0777) {
989                                 r = btrfs_subvol_make(i->path);
990                                 log_debug_errno(r, "Creating subvolume \"%s\": %m", i->path);
991                         }
992                 else
993                         r = 0;
994
995                 if (IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY) || r == -ENOTTY)
996                         RUN_WITH_UMASK(0000)
997                                 r = mkdir_label(i->path, i->mode);
998
999                 if (r < 0) {
1000                         if (r != -EEXIST)
1001                                 return log_error_errno(r, "Failed to create directory or subvolume \"%s\": %m", i->path);
1002
1003                         if (stat(i->path, &st) < 0)
1004                                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1005
1006                         if (!S_ISDIR(st.st_mode)) {
1007                                 log_debug("\"%s\" already exists and is not a directory.", i->path);
1008                                 return 0;
1009                         }
1010
1011                         creation = CREATION_EXISTING;
1012                 } else
1013                         creation = CREATION_NORMAL;
1014                 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation), i->path);
1015
1016                 r = path_set_perms(i, i->path);
1017                 if (r < 0)
1018                         return r;
1019
1020                 break;
1021
1022         case CREATE_FIFO:
1023
1024                 RUN_WITH_UMASK(0000) {
1025                         mac_selinux_create_file_prepare(i->path, S_IFIFO);
1026                         r = mkfifo(i->path, i->mode);
1027                         mac_selinux_create_file_clear();
1028                 }
1029
1030                 if (r < 0) {
1031                         if (errno != EEXIST)
1032                                 return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
1033
1034                         if (stat(i->path, &st) < 0)
1035                                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1036
1037                         if (!S_ISFIFO(st.st_mode)) {
1038
1039                                 if (i->force) {
1040
1041                                         RUN_WITH_UMASK(0000) {
1042                                                 mac_selinux_create_file_prepare(i->path, S_IFIFO);
1043                                                 r = mkfifo_atomic(i->path, i->mode);
1044                                                 mac_selinux_create_file_clear();
1045                                         }
1046
1047                                         if (r < 0)
1048                                                 return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
1049                                         creation = CREATION_FORCE;
1050                                 } else {
1051                                         log_debug("%s is not a fifo.", i->path);
1052                                         return 0;
1053                                 }
1054                         } else
1055                                 creation = CREATION_EXISTING;
1056                 } else
1057                         creation = CREATION_NORMAL;
1058                 log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation), i->path);
1059
1060                 r = path_set_perms(i, i->path);
1061                 if (r < 0)
1062                         return r;
1063
1064                 break;
1065
1066         case CREATE_SYMLINK:
1067
1068                 mac_selinux_create_file_prepare(i->path, S_IFLNK);
1069                 r = symlink(i->argument, i->path);
1070                 mac_selinux_create_file_clear();
1071
1072                 if (r < 0) {
1073                         _cleanup_free_ char *x = NULL;
1074
1075                         if (errno != EEXIST)
1076                                 return log_error_errno(errno, "symlink(%s, %s) failed: %m", i->argument, i->path);
1077
1078                         r = readlink_malloc(i->path, &x);
1079                         if (r < 0 || !streq(i->argument, x)) {
1080
1081                                 if (i->force) {
1082                                         mac_selinux_create_file_prepare(i->path, S_IFLNK);
1083                                         r = symlink_atomic(i->argument, i->path);
1084                                         mac_selinux_create_file_clear();
1085
1086                                         if (r < 0)
1087                                                 return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
1088                                         creation = CREATION_FORCE;
1089                                 } else {
1090                                         log_debug("\"%s\" is not a symlink or does not point to the correct path.", i->path);
1091                                         return 0;
1092                                 }
1093                         } else
1094                                 creation = CREATION_EXISTING;
1095                 } else
1096                         creation = CREATION_NORMAL;
1097                 log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation), i->path);
1098
1099                 break;
1100
1101         case CREATE_BLOCK_DEVICE:
1102         case CREATE_CHAR_DEVICE: {
1103                 mode_t file_type;
1104
1105                 if (have_effective_cap(CAP_MKNOD) == 0) {
1106                         /* In a container we lack CAP_MKNOD. We
1107                         shouldn't attempt to create the device node in
1108                         that case to avoid noise, and we don't support
1109                         virtualized devices in containers anyway. */
1110
1111                         log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
1112                         return 0;
1113                 }
1114
1115                 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
1116
1117                 RUN_WITH_UMASK(0000) {
1118                         mac_selinux_create_file_prepare(i->path, file_type);
1119                         r = mknod(i->path, i->mode | file_type, i->major_minor);
1120                         mac_selinux_create_file_clear();
1121                 }
1122
1123                 if (r < 0) {
1124                         if (errno == EPERM) {
1125                                 log_debug("We lack permissions, possibly because of cgroup configuration; "
1126                                           "skipping creation of device node %s.", i->path);
1127                                 return 0;
1128                         }
1129
1130                         if (errno != EEXIST)
1131                                 return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
1132
1133                         if (stat(i->path, &st) < 0)
1134                                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1135
1136                         if ((st.st_mode & S_IFMT) != file_type) {
1137
1138                                 if (i->force) {
1139
1140                                         RUN_WITH_UMASK(0000) {
1141                                                 mac_selinux_create_file_prepare(i->path, file_type);
1142                                                 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
1143                                                 mac_selinux_create_file_clear();
1144                                         }
1145
1146                                         if (r < 0)
1147                                                 return log_error_errno(r, "Failed to create device node \"%s\": %m", i->path);
1148                                         creation = CREATION_FORCE;
1149                                 } else {
1150                                         log_debug("%s is not a device node.", i->path);
1151                                         return 0;
1152                                 }
1153                         } else
1154                                 creation = CREATION_EXISTING;
1155                 } else
1156                         creation = CREATION_NORMAL;
1157                 log_debug("%s %s device node \"%s\" %u:%u.",
1158                           creation_mode_verb_to_string(creation),
1159                           i->type == CREATE_BLOCK_DEVICE ? "block" : "char",
1160                           i->path, major(i->mode), minor(i->mode));
1161
1162                 r = path_set_perms(i, i->path);
1163                 if (r < 0)
1164                         return r;
1165
1166                 break;
1167         }
1168
1169         case ADJUST_MODE:
1170         case RELABEL_PATH:
1171                 r = glob_item(i, path_set_perms, false);
1172                 if (r < 0)
1173                         return r;
1174                 break;
1175
1176         case RECURSIVE_RELABEL_PATH:
1177                 r = glob_item(i, path_set_perms, true);
1178                 if (r < 0)
1179                         return r;
1180                 break;
1181
1182         case SET_XATTR:
1183                 r = glob_item(i, path_set_xattrs, false);
1184                 if (r < 0)
1185                         return r;
1186                 break;
1187
1188         case RECURSIVE_SET_XATTR:
1189                 r = glob_item(i, path_set_xattrs, true);
1190                 if (r < 0)
1191                         return r;
1192                 break;
1193
1194         case SET_ACL:
1195                 r = glob_item(i, path_set_acls, false);
1196                 if (r < 0)
1197                         return r;
1198                 break;
1199
1200         case RECURSIVE_SET_ACL:
1201                 r = glob_item(i, path_set_acls, true);
1202                 if (r < 0)
1203                         return r;
1204                 break;
1205         }
1206
1207         log_debug("%s created successfully.", i->path);
1208
1209         return 0;
1210 }
1211
1212 static int remove_item_instance(Item *i, const char *instance) {
1213         int r;
1214
1215         assert(i);
1216
1217         switch (i->type) {
1218
1219         case REMOVE_PATH:
1220                 if (remove(instance) < 0 && errno != ENOENT)
1221                         return log_error_errno(errno, "rm(%s): %m", instance);
1222
1223                 break;
1224
1225         case TRUNCATE_DIRECTORY:
1226         case RECURSIVE_REMOVE_PATH:
1227                 /* FIXME: we probably should use dir_cleanup() here
1228                  * instead of rm_rf() so that 'x' is honoured. */
1229                 log_debug("rm -rf \"%s\"", instance);
1230                 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
1231                 if (r < 0 && r != -ENOENT)
1232                         return log_error_errno(r, "rm_rf(%s): %m", instance);
1233
1234                 break;
1235
1236         default:
1237                 assert_not_reached("wut?");
1238         }
1239
1240         return 0;
1241 }
1242
1243 static int remove_item(Item *i) {
1244         int r = 0;
1245
1246         assert(i);
1247
1248         log_debug("Running remove action for entry %c %s", (char) i->type, i->path);
1249
1250         switch (i->type) {
1251
1252         case CREATE_FILE:
1253         case TRUNCATE_FILE:
1254         case CREATE_DIRECTORY:
1255         case CREATE_SUBVOLUME:
1256         case CREATE_FIFO:
1257         case CREATE_SYMLINK:
1258         case CREATE_CHAR_DEVICE:
1259         case CREATE_BLOCK_DEVICE:
1260         case IGNORE_PATH:
1261         case IGNORE_DIRECTORY_PATH:
1262         case ADJUST_MODE:
1263         case RELABEL_PATH:
1264         case RECURSIVE_RELABEL_PATH:
1265         case WRITE_FILE:
1266         case COPY_FILES:
1267         case SET_XATTR:
1268         case RECURSIVE_SET_XATTR:
1269         case SET_ACL:
1270         case RECURSIVE_SET_ACL:
1271                 break;
1272
1273         case REMOVE_PATH:
1274         case TRUNCATE_DIRECTORY:
1275         case RECURSIVE_REMOVE_PATH:
1276                 r = glob_item(i, remove_item_instance, false);
1277                 break;
1278         }
1279
1280         return r;
1281 }
1282
1283 static int clean_item_instance(Item *i, const char* instance) {
1284         _cleanup_closedir_ DIR *d = NULL;
1285         struct stat s, ps;
1286         bool mountpoint;
1287         usec_t cutoff, n;
1288         char timestamp[FORMAT_TIMESTAMP_MAX];
1289
1290         assert(i);
1291
1292         if (!i->age_set)
1293                 return 0;
1294
1295         n = now(CLOCK_REALTIME);
1296         if (n < i->age)
1297                 return 0;
1298
1299         cutoff = n - i->age;
1300
1301         d = opendir_nomod(instance);
1302         if (!d) {
1303                 if (errno == ENOENT || errno == ENOTDIR) {
1304                         log_debug_errno(errno, "Directory \"%s\": %m", instance);
1305                         return 0;
1306                 }
1307
1308                 log_error_errno(errno, "Failed to open directory %s: %m", instance);
1309                 return -errno;
1310         }
1311
1312         if (fstat(dirfd(d), &s) < 0)
1313                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1314
1315         if (!S_ISDIR(s.st_mode)) {
1316                 log_error("%s is not a directory.", i->path);
1317                 return -ENOTDIR;
1318         }
1319
1320         if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
1321                 return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
1322
1323         mountpoint = s.st_dev != ps.st_dev ||
1324                      (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1325
1326         log_debug("Cleanup threshold for %s \"%s\" is %s",
1327                   mountpoint ? "mount point" : "directory",
1328                   instance,
1329                   format_timestamp_us(timestamp, sizeof(timestamp), cutoff));
1330
1331         return dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1332                            MAX_DEPTH, i->keep_first_level);
1333 }
1334
1335 static int clean_item(Item *i) {
1336         int r = 0;
1337
1338         assert(i);
1339
1340         log_debug("Running clean action for entry %c %s", (char) i->type, i->path);
1341
1342         switch (i->type) {
1343         case CREATE_DIRECTORY:
1344         case CREATE_SUBVOLUME:
1345         case TRUNCATE_DIRECTORY:
1346         case IGNORE_PATH:
1347         case COPY_FILES:
1348                 clean_item_instance(i, i->path);
1349                 break;
1350         case IGNORE_DIRECTORY_PATH:
1351                 r = glob_item(i, clean_item_instance, false);
1352                 break;
1353         default:
1354                 break;
1355         }
1356
1357         return r;
1358 }
1359
1360 static int process_item_array(ItemArray *array);
1361
1362 static int process_item(Item *i) {
1363         int r, q, p, t = 0;
1364         _cleanup_free_ char *prefix = NULL;
1365
1366         assert(i);
1367
1368         if (i->done)
1369                 return 0;
1370
1371         i->done = true;
1372
1373         prefix = malloc(strlen(i->path) + 1);
1374         if (!prefix)
1375                 return log_oom();
1376
1377         PATH_FOREACH_PREFIX(prefix, i->path) {
1378                 ItemArray *j;
1379
1380                 j = hashmap_get(items, prefix);
1381                 if (j) {
1382                         int s;
1383
1384                         s = process_item_array(j);
1385                         if (s < 0 && t == 0)
1386                                 t = s;
1387                 }
1388         }
1389
1390         r = arg_create ? create_item(i) : 0;
1391         q = arg_remove ? remove_item(i) : 0;
1392         p = arg_clean ? clean_item(i) : 0;
1393
1394         return t < 0 ? t :
1395                 r < 0 ? r :
1396                 q < 0 ? q :
1397                 p;
1398 }
1399
1400 static int process_item_array(ItemArray *array) {
1401         unsigned n;
1402         int r = 0, k;
1403
1404         assert(array);
1405
1406         for (n = 0; n < array->count; n++) {
1407                 k = process_item(array->items + n);
1408                 if (k < 0 && r == 0)
1409                         r = k;
1410         }
1411
1412         return r;
1413 }
1414
1415 static void item_free_contents(Item *i) {
1416         assert(i);
1417         free(i->path);
1418         free(i->argument);
1419         strv_free(i->xattrs);
1420
1421 #ifdef HAVE_ACL
1422         acl_free(i->acl_access);
1423         acl_free(i->acl_default);
1424 #endif
1425 }
1426
1427 static void item_array_free(ItemArray *a) {
1428         unsigned n;
1429
1430         if (!a)
1431                 return;
1432
1433         for (n = 0; n < a->count; n++)
1434                 item_free_contents(a->items + n);
1435         free(a->items);
1436         free(a);
1437 }
1438
1439 static bool item_compatible(Item *a, Item *b) {
1440         assert(a);
1441         assert(b);
1442         assert(streq(a->path, b->path));
1443
1444         if (takes_ownership(a->type) && takes_ownership(b->type))
1445                 /* check if the items are the same */
1446                 return  streq_ptr(a->argument, b->argument) &&
1447
1448                         a->uid_set == b->uid_set &&
1449                         a->uid == b->uid &&
1450
1451                         a->gid_set == b->gid_set &&
1452                         a->gid == b->gid &&
1453
1454                         a->mode_set == b->mode_set &&
1455                         a->mode == b->mode &&
1456
1457                         a->age_set == b->age_set &&
1458                         a->age == b->age &&
1459
1460                         a->mask_perms == b->mask_perms &&
1461
1462                         a->keep_first_level == b->keep_first_level &&
1463
1464                         a->major_minor == b->major_minor;
1465
1466         return true;
1467 }
1468
1469 static bool should_include_path(const char *path) {
1470         char **prefix;
1471
1472         STRV_FOREACH(prefix, arg_exclude_prefixes)
1473                 if (path_startswith(path, *prefix)) {
1474                         log_debug("Entry \"%s\" matches exclude prefix \"%s\", skipping.",
1475                                   path, *prefix);
1476                         return false;
1477                 }
1478
1479         STRV_FOREACH(prefix, arg_include_prefixes)
1480                 if (path_startswith(path, *prefix)) {
1481                         log_debug("Entry \"%s\" matches include prefix \"%s\".", path, *prefix);
1482                         return true;
1483                 }
1484
1485         /* no matches, so we should include this path only if we
1486          * have no whitelist at all */
1487         if (strv_length(arg_include_prefixes) == 0)
1488                 return true;
1489
1490         log_debug("Entry \"%s\" does not match any include prefix, skipping.", path);
1491         return false;
1492 }
1493
1494 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1495
1496         static const Specifier specifier_table[] = {
1497                 { 'm', specifier_machine_id, NULL },
1498                 { 'b', specifier_boot_id, NULL },
1499                 { 'H', specifier_host_name, NULL },
1500                 { 'v', specifier_kernel_release, NULL },
1501                 {}
1502         };
1503
1504         _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1505         _cleanup_(item_free_contents) Item i = {};
1506         ItemArray *existing;
1507         Hashmap *h;
1508         int r, c = -1, pos;
1509         bool force = false, boot = false;
1510
1511         assert(fname);
1512         assert(line >= 1);
1513         assert(buffer);
1514
1515         r = sscanf(buffer,
1516                    "%ms %ms %ms %ms %ms %ms %n",
1517                    &action,
1518                    &path,
1519                    &mode,
1520                    &user,
1521                    &group,
1522                    &age,
1523                    &c);
1524         if (r < 2) {
1525                 log_error("[%s:%u] Syntax error.", fname, line);
1526                 return -EIO;
1527         }
1528
1529         if (isempty(action)) {
1530                 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1531                 return -EINVAL;
1532         }
1533
1534         for (pos = 1; action[pos]; pos++) {
1535                 if (action[pos] == '!' && !boot)
1536                         boot = true;
1537                 else if (action[pos] == '+' && !force)
1538                         force = true;
1539                 else {
1540                         log_error("[%s:%u] Unknown modifiers in command '%s'",
1541                                   fname, line, action);
1542                         return -EINVAL;
1543                 }
1544         }
1545
1546         if (boot && !arg_boot) {
1547                 log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
1548                           action, path);
1549                 return 0;
1550         }
1551
1552         i.type = action[0];
1553         i.force = force;
1554
1555         r = specifier_printf(path, specifier_table, NULL, &i.path);
1556         if (r < 0) {
1557                 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1558                 return r;
1559         }
1560
1561         if (c >= 0)  {
1562                 c += strspn(buffer+c, WHITESPACE);
1563                 if (buffer[c] != 0 && (buffer[c] != '-' || buffer[c+1] != 0)) {
1564                         i.argument = unquote(buffer+c, "\"");
1565                         if (!i.argument)
1566                                 return log_oom();
1567                 }
1568         }
1569
1570         switch (i.type) {
1571
1572         case CREATE_FILE:
1573         case TRUNCATE_FILE:
1574         case CREATE_DIRECTORY:
1575         case CREATE_SUBVOLUME:
1576         case TRUNCATE_DIRECTORY:
1577         case CREATE_FIFO:
1578         case IGNORE_PATH:
1579         case IGNORE_DIRECTORY_PATH:
1580         case REMOVE_PATH:
1581         case RECURSIVE_REMOVE_PATH:
1582         case ADJUST_MODE:
1583         case RELABEL_PATH:
1584         case RECURSIVE_RELABEL_PATH:
1585                 break;
1586
1587         case CREATE_SYMLINK:
1588                 if (!i.argument) {
1589                         i.argument = strappend("/usr/share/factory/", i.path);
1590                         if (!i.argument)
1591                                 return log_oom();
1592                 }
1593                 break;
1594
1595         case WRITE_FILE:
1596                 if (!i.argument) {
1597                         log_error("[%s:%u] Write file requires argument.", fname, line);
1598                         return -EBADMSG;
1599                 }
1600                 break;
1601
1602         case COPY_FILES:
1603                 if (!i.argument) {
1604                         i.argument = strappend("/usr/share/factory/", i.path);
1605                         if (!i.argument)
1606                                 return log_oom();
1607                 } else if (!path_is_absolute(i.argument)) {
1608                         log_error("[%s:%u] Source path is not absolute.", fname, line);
1609                         return -EBADMSG;
1610                 }
1611
1612                 path_kill_slashes(i.argument);
1613                 break;
1614
1615         case CREATE_CHAR_DEVICE:
1616         case CREATE_BLOCK_DEVICE: {
1617                 unsigned major, minor;
1618
1619                 if (!i.argument) {
1620                         log_error("[%s:%u] Device file requires argument.", fname, line);
1621                         return -EBADMSG;
1622                 }
1623
1624                 if (sscanf(i.argument, "%u:%u", &major, &minor) != 2) {
1625                         log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i.argument);
1626                         return -EBADMSG;
1627                 }
1628
1629                 i.major_minor = makedev(major, minor);
1630                 break;
1631         }
1632
1633         case SET_XATTR:
1634         case RECURSIVE_SET_XATTR:
1635                 if (!i.argument) {
1636                         log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1637                         return -EBADMSG;
1638                 }
1639                 r = get_xattrs_from_arg(&i);
1640                 if (r < 0)
1641                         return r;
1642                 break;
1643
1644         case SET_ACL:
1645         case RECURSIVE_SET_ACL:
1646                 if (!i.argument) {
1647                         log_error("[%s:%u] Set ACLs requires argument.", fname, line);
1648                         return -EBADMSG;
1649                 }
1650                 r = get_acls_from_arg(&i);
1651                 if (r < 0)
1652                         return r;
1653                 break;
1654
1655         default:
1656                 log_error("[%s:%u] Unknown command type '%c'.", fname, line, (char) i.type);
1657                 return -EBADMSG;
1658         }
1659
1660         if (!path_is_absolute(i.path)) {
1661                 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i.path);
1662                 return -EBADMSG;
1663         }
1664
1665         path_kill_slashes(i.path);
1666
1667         if (!should_include_path(i.path))
1668                 return 0;
1669
1670         if (arg_root) {
1671                 char *p;
1672
1673                 p = strappend(arg_root, i.path);
1674                 if (!p)
1675                         return log_oom();
1676
1677                 free(i.path);
1678                 i.path = p;
1679         }
1680
1681         if (user && !streq(user, "-")) {
1682                 const char *u = user;
1683
1684                 r = get_user_creds(&u, &i.uid, NULL, NULL, NULL);
1685                 if (r < 0) {
1686                         log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1687                         return r;
1688                 }
1689
1690                 i.uid_set = true;
1691         }
1692
1693         if (group && !streq(group, "-")) {
1694                 const char *g = group;
1695
1696                 r = get_group_creds(&g, &i.gid);
1697                 if (r < 0) {
1698                         log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1699                         return r;
1700                 }
1701
1702                 i.gid_set = true;
1703         }
1704
1705         if (mode && !streq(mode, "-")) {
1706                 const char *mm = mode;
1707                 unsigned m;
1708
1709                 if (*mm == '~') {
1710                         i.mask_perms = true;
1711                         mm++;
1712                 }
1713
1714                 if (sscanf(mm, "%o", &m) != 1) {
1715                         log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1716                         return -ENOENT;
1717                 }
1718
1719                 i.mode = m;
1720                 i.mode_set = true;
1721         } else
1722                 i.mode = IN_SET(i.type, CREATE_DIRECTORY, CREATE_SUBVOLUME, TRUNCATE_DIRECTORY)
1723                         ? 0755 : 0644;
1724
1725         if (age && !streq(age, "-")) {
1726                 const char *a = age;
1727
1728                 if (*a == '~') {
1729                         i.keep_first_level = true;
1730                         a++;
1731                 }
1732
1733                 if (parse_sec(a, &i.age) < 0) {
1734                         log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1735                         return -EBADMSG;
1736                 }
1737
1738                 i.age_set = true;
1739         }
1740
1741         h = needs_glob(i.type) ? globs : items;
1742
1743         existing = hashmap_get(h, i.path);
1744         if (existing) {
1745                 unsigned n;
1746
1747                 for (n = 0; n < existing->count; n++) {
1748                         if (!item_compatible(existing->items + n, &i))
1749                                 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
1750                                             fname, line, i.path);
1751                 }
1752         } else {
1753                 existing = new0(ItemArray, 1);
1754                 r = hashmap_put(h, i.path, existing);
1755                 if (r < 0)
1756                         return log_oom();
1757         }
1758
1759         if (!GREEDY_REALLOC(existing->items, existing->size, existing->count + 1))
1760                 return log_oom();
1761
1762         memcpy(existing->items + existing->count++, &i, sizeof(i));
1763         zero(i);
1764         return 0;
1765 }
1766
1767 static void help(void) {
1768         printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1769                "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1770                "  -h --help                 Show this help\n"
1771                "     --version              Show package version\n"
1772                "     --create               Create marked files/directories\n"
1773                "     --clean                Clean up marked directories\n"
1774                "     --remove               Remove marked files/directories\n"
1775                "     --boot                 Execute actions only safe at boot\n"
1776                "     --prefix=PATH          Only apply rules with the specified prefix\n"
1777                "     --exclude-prefix=PATH  Ignore rules with the specified prefix\n"
1778                "     --root=PATH            Operate on an alternate filesystem root\n",
1779                program_invocation_short_name);
1780 }
1781
1782 static int parse_argv(int argc, char *argv[]) {
1783
1784         enum {
1785                 ARG_VERSION = 0x100,
1786                 ARG_CREATE,
1787                 ARG_CLEAN,
1788                 ARG_REMOVE,
1789                 ARG_BOOT,
1790                 ARG_PREFIX,
1791                 ARG_EXCLUDE_PREFIX,
1792                 ARG_ROOT,
1793         };
1794
1795         static const struct option options[] = {
1796                 { "help",           no_argument,         NULL, 'h'                },
1797                 { "version",        no_argument,         NULL, ARG_VERSION        },
1798                 { "create",         no_argument,         NULL, ARG_CREATE         },
1799                 { "clean",          no_argument,         NULL, ARG_CLEAN          },
1800                 { "remove",         no_argument,         NULL, ARG_REMOVE         },
1801                 { "boot",           no_argument,         NULL, ARG_BOOT           },
1802                 { "prefix",         required_argument,   NULL, ARG_PREFIX         },
1803                 { "exclude-prefix", required_argument,   NULL, ARG_EXCLUDE_PREFIX },
1804                 { "root",           required_argument,   NULL, ARG_ROOT           },
1805                 {}
1806         };
1807
1808         int c;
1809
1810         assert(argc >= 0);
1811         assert(argv);
1812
1813         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1814
1815                 switch (c) {
1816
1817                 case 'h':
1818                         help();
1819                         return 0;
1820
1821                 case ARG_VERSION:
1822                         puts(PACKAGE_STRING);
1823                         puts(SYSTEMD_FEATURES);
1824                         return 0;
1825
1826                 case ARG_CREATE:
1827                         arg_create = true;
1828                         break;
1829
1830                 case ARG_CLEAN:
1831                         arg_clean = true;
1832                         break;
1833
1834                 case ARG_REMOVE:
1835                         arg_remove = true;
1836                         break;
1837
1838                 case ARG_BOOT:
1839                         arg_boot = true;
1840                         break;
1841
1842                 case ARG_PREFIX:
1843                         if (strv_push(&arg_include_prefixes, optarg) < 0)
1844                                 return log_oom();
1845                         break;
1846
1847                 case ARG_EXCLUDE_PREFIX:
1848                         if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1849                                 return log_oom();
1850                         break;
1851
1852                 case ARG_ROOT:
1853                         free(arg_root);
1854                         arg_root = path_make_absolute_cwd(optarg);
1855                         if (!arg_root)
1856                                 return log_oom();
1857
1858                         path_kill_slashes(arg_root);
1859                         break;
1860
1861                 case '?':
1862                         return -EINVAL;
1863
1864                 default:
1865                         assert_not_reached("Unhandled option");
1866                 }
1867
1868         if (!arg_clean && !arg_create && !arg_remove) {
1869                 log_error("You need to specify at least one of --clean, --create or --remove.");
1870                 return -EINVAL;
1871         }
1872
1873         return 1;
1874 }
1875
1876 static int read_config_file(const char *fn, bool ignore_enoent) {
1877         _cleanup_fclose_ FILE *f = NULL;
1878         char line[LINE_MAX];
1879         Iterator iterator;
1880         unsigned v = 0;
1881         Item *i;
1882         int r;
1883
1884         assert(fn);
1885
1886         r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1887         if (r < 0) {
1888                 if (ignore_enoent && r == -ENOENT) {
1889                         log_debug_errno(r, "Failed to open \"%s\": %m", fn);
1890                         return 0;
1891                 }
1892
1893                 return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
1894         }
1895         log_debug("Reading config file \"%s\".", fn);
1896
1897         FOREACH_LINE(line, f, break) {
1898                 char *l;
1899                 int k;
1900
1901                 v++;
1902
1903                 l = strstrip(line);
1904                 if (*l == '#' || *l == 0)
1905                         continue;
1906
1907                 k = parse_line(fn, v, l);
1908                 if (k < 0 && r == 0)
1909                         r = k;
1910         }
1911
1912         /* we have to determine age parameter for each entry of type X */
1913         HASHMAP_FOREACH(i, globs, iterator) {
1914                 Iterator iter;
1915                 Item *j, *candidate_item = NULL;
1916
1917                 if (i->type != IGNORE_DIRECTORY_PATH)
1918                         continue;
1919
1920                 HASHMAP_FOREACH(j, items, iter) {
1921                         if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME)
1922                                 continue;
1923
1924                         if (path_equal(j->path, i->path)) {
1925                                 candidate_item = j;
1926                                 break;
1927                         }
1928
1929                         if ((!candidate_item && path_startswith(i->path, j->path)) ||
1930                             (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1931                                 candidate_item = j;
1932                 }
1933
1934                 if (candidate_item && candidate_item->age_set) {
1935                         i->age = candidate_item->age;
1936                         i->age_set = true;
1937                 }
1938         }
1939
1940         if (ferror(f)) {
1941                 log_error_errno(errno, "Failed to read from file %s: %m", fn);
1942                 if (r == 0)
1943                         r = -EIO;
1944         }
1945
1946         return r;
1947 }
1948
1949 int main(int argc, char *argv[]) {
1950         int r, k;
1951         ItemArray *a;
1952         Iterator iterator;
1953
1954         r = parse_argv(argc, argv);
1955         if (r <= 0)
1956                 goto finish;
1957
1958         log_set_target(LOG_TARGET_AUTO);
1959         log_parse_environment();
1960         log_open();
1961
1962         umask(0022);
1963
1964         mac_selinux_init(NULL);
1965
1966         items = hashmap_new(&string_hash_ops);
1967         globs = hashmap_new(&string_hash_ops);
1968
1969         if (!items || !globs) {
1970                 r = log_oom();
1971                 goto finish;
1972         }
1973
1974         r = 0;
1975
1976         if (optind < argc) {
1977                 int j;
1978
1979                 for (j = optind; j < argc; j++) {
1980                         k = read_config_file(argv[j], false);
1981                         if (k < 0 && r == 0)
1982                                 r = k;
1983                 }
1984
1985         } else {
1986                 _cleanup_strv_free_ char **files = NULL;
1987                 char **f;
1988
1989                 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1990                 if (r < 0) {
1991                         log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
1992                         goto finish;
1993                 }
1994
1995                 STRV_FOREACH(f, files) {
1996                         k = read_config_file(*f, true);
1997                         if (k < 0 && r == 0)
1998                                 r = k;
1999                 }
2000         }
2001
2002         HASHMAP_FOREACH(a, globs, iterator) {
2003                 k = process_item_array(a);
2004                 if (k < 0 && r == 0)
2005                         r = k;
2006         }
2007
2008         HASHMAP_FOREACH(a, items, iterator) {
2009                 k = process_item_array(a);
2010                 if (k < 0 && r == 0)
2011                         r = k;
2012         }
2013
2014 finish:
2015         while ((a = hashmap_steal_first(items)))
2016                 item_array_free(a);
2017
2018         while ((a = hashmap_steal_first(globs)))
2019                 item_array_free(a);
2020
2021         hashmap_free(items);
2022         hashmap_free(globs);
2023
2024         free(arg_include_prefixes);
2025         free(arg_exclude_prefixes);
2026         free(arg_root);
2027
2028         set_free_free(unix_sockets);
2029
2030         mac_selinux_finish();
2031
2032         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
2033 }