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