chiark / gitweb /
tmpfiles: minor simplification
[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 int dir_cleanup(
312                 Item *i,
313                 const char *p,
314                 DIR *d,
315                 const struct stat *ds,
316                 usec_t cutoff,
317                 dev_t rootdev,
318                 bool mountpoint,
319                 int maxdepth,
320                 bool keep_this_level) {
321
322         struct dirent *dent;
323         struct timespec times[2];
324         bool deleted = false;
325         int r = 0;
326
327         while ((dent = readdir(d))) {
328                 struct stat s;
329                 usec_t age;
330                 _cleanup_free_ char *sub_path = NULL;
331
332                 if (STR_IN_SET(dent->d_name, ".", ".."))
333                         continue;
334
335                 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
336                         if (errno == ENOENT)
337                                 continue;
338
339                         /* FUSE, NFS mounts, SELinux might return EACCES */
340                         if (errno == EACCES)
341                                 log_debug_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
342                         else
343                                 log_error_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
344                         r = -errno;
345                         continue;
346                 }
347
348                 /* Stay on the same filesystem */
349                 if (s.st_dev != rootdev)
350                         continue;
351
352                 /* Try to detect bind mounts of the same filesystem instance; they
353                  * do not differ in device major/minors. This type of query is not
354                  * supported on all kernels or filesystem types though. */
355                 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
356                         continue;
357
358                 /* Do not delete read-only files owned by root */
359                 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
360                         continue;
361
362                 sub_path = strjoin(p, "/", dent->d_name, NULL);
363                 if (!sub_path) {
364                         r = log_oom();
365                         goto finish;
366                 }
367
368                 /* Is there an item configured for this path? */
369                 if (hashmap_get(items, sub_path))
370                         continue;
371
372                 if (find_glob(globs, sub_path))
373                         continue;
374
375                 if (S_ISDIR(s.st_mode)) {
376
377                         if (mountpoint &&
378                             streq(dent->d_name, "lost+found") &&
379                             s.st_uid == 0)
380                                 continue;
381
382                         if (maxdepth <= 0)
383                                 log_warning("Reached max depth on %s.", sub_path);
384                         else {
385                                 _cleanup_closedir_ DIR *sub_dir;
386                                 int q;
387
388                                 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
389                                 if (!sub_dir) {
390                                         if (errno != ENOENT) {
391                                                 log_error_errno(errno, "opendir(%s/%s) failed: %m", p, dent->d_name);
392                                                 r = -errno;
393                                         }
394
395                                         continue;
396                                 }
397
398                                 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
399                                 if (q < 0)
400                                         r = q;
401                         }
402
403                         /* Note: if you are wondering why we don't
404                          * support the sticky bit for excluding
405                          * directories from cleaning like we do it for
406                          * other file system objects: well, the sticky
407                          * bit already has a meaning for directories,
408                          * so we don't want to overload that. */
409
410                         if (keep_this_level)
411                                 continue;
412
413                         /* Ignore ctime, we change it when deleting */
414                         age = MAX(timespec_load(&s.st_mtim),
415                                   timespec_load(&s.st_atim));
416                         if (age >= cutoff)
417                                 continue;
418
419                         if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
420                                 log_debug("rmdir '%s'", sub_path);
421
422                                 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
423                                         if (errno != ENOENT && errno != ENOTEMPTY) {
424                                                 log_error_errno(errno, "rmdir(%s): %m", sub_path);
425                                                 r = -errno;
426                                         }
427                                 }
428                         }
429
430                 } else {
431                         /* Skip files for which the sticky bit is
432                          * set. These are semantics we define, and are
433                          * unknown elsewhere. See XDG_RUNTIME_DIR
434                          * specification for details. */
435                         if (s.st_mode & S_ISVTX)
436                                 continue;
437
438                         if (mountpoint && S_ISREG(s.st_mode)) {
439                                 if (streq(dent->d_name, ".journal") &&
440                                     s.st_uid == 0)
441                                         continue;
442
443                                 if (streq(dent->d_name, "aquota.user") ||
444                                     streq(dent->d_name, "aquota.group"))
445                                         continue;
446                         }
447
448                         /* Ignore sockets that are listed in /proc/net/unix */
449                         if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
450                                 continue;
451
452                         /* Ignore device nodes */
453                         if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
454                                 continue;
455
456                         /* Keep files on this level around if this is
457                          * requested */
458                         if (keep_this_level)
459                                 continue;
460
461                         age = MAX3(timespec_load(&s.st_mtim),
462                                    timespec_load(&s.st_atim),
463                                    timespec_load(&s.st_ctim));
464
465                         if (age >= cutoff)
466                                 continue;
467
468                         log_debug("unlink '%s'", sub_path);
469
470                         if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
471                                 if (errno != ENOENT) {
472                                         log_error_errno(errno, "unlink(%s): %m", sub_path);
473                                         r = -errno;
474                                 }
475                         }
476
477                         deleted = true;
478                 }
479         }
480
481 finish:
482         if (deleted) {
483                 /* Restore original directory timestamps */
484                 times[0] = ds->st_atim;
485                 times[1] = ds->st_mtim;
486
487                 if (futimens(dirfd(d), times) < 0)
488                         log_error_errno(errno, "utimensat(%s): %m", p);
489         }
490
491         return r;
492 }
493
494 static int path_set_perms(Item *i, const char *path) {
495         struct stat st;
496         bool st_valid;
497
498         assert(i);
499         assert(path);
500
501         st_valid = stat(path, &st) == 0;
502
503         /* not using i->path directly because it may be a glob */
504         if (i->mode_set) {
505                 mode_t m = i->mode;
506
507                 if (i->mask_perms && st_valid) {
508                         if (!(st.st_mode & 0111))
509                                 m &= ~0111;
510                         if (!(st.st_mode & 0222))
511                                 m &= ~0222;
512                         if (!(st.st_mode & 0444))
513                                 m &= ~0444;
514                         if (!S_ISDIR(st.st_mode))
515                                 m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
516                 }
517
518                 if (!st_valid || m != (st.st_mode & 07777)) {
519                         if (chmod(path, m) < 0)
520                                 return log_error_errno(errno, "chmod(%s) failed: %m", path);
521                 }
522         }
523
524         if ((!st_valid || (i->uid != st.st_uid || i->gid != st.st_gid)) &&
525             (i->uid_set || i->gid_set))
526                 if (chown(path,
527                           i->uid_set ? i->uid : UID_INVALID,
528                           i->gid_set ? i->gid : GID_INVALID) < 0)
529
530                         return log_error_errno(errno, "chown(%s) failed: %m", path);
531
532         return label_fix(path, false, false);
533 }
534
535 static int get_xattrs_from_arg(Item *i) {
536         char *xattr;
537         const char *p;
538         int r;
539
540         assert(i);
541         assert(i->argument);
542
543         p = i->argument;
544
545         while ((r = unquote_first_word(&p, &xattr, false)) > 0) {
546                 _cleanup_free_ char *tmp = NULL, *name = NULL,
547                         *value = NULL, *value2 = NULL, *_xattr = xattr;
548
549                 r = split_pair(xattr, "=", &name, &value);
550                 if (r < 0) {
551                         log_warning("Illegal xattr found: \"%s\" - ignoring.", xattr);
552                         continue;
553                 }
554
555                 if (strempty(name) || strempty(value)) {
556                         log_warning("Malformed xattr found: \"%s\" - ignoring.", xattr);
557                         continue;
558                 }
559
560                 tmp = unquote(value, "\"");
561                 if (!tmp)
562                         return log_oom();
563
564                 value2 = cunescape(tmp);
565                 if (!value2)
566                         return log_oom();
567
568                 if (strv_push_pair(&i->xattrs, name, value2) < 0)
569                         return log_oom();
570                 name = value2 = NULL;
571         }
572
573         return r;
574 }
575
576 static int path_set_xattrs(Item *i, const char *path) {
577         char **name, **value;
578
579         assert(i);
580         assert(path);
581
582         STRV_FOREACH_PAIR(name, value, i->xattrs) {
583                 int n;
584
585                 n = strlen(*value);
586                 if (lsetxattr(path, *name, *value, n, 0) < 0) {
587                         log_error("Setting extended attribute %s=%s on %s failed: %m",
588                                   *name, *value, path);
589                         return -errno;
590                 }
591         }
592         return 0;
593 }
594
595 static int get_acls_from_arg(Item *item) {
596 #ifdef HAVE_ACL
597         int r;
598         _cleanup_(acl_freep) acl_t a = NULL, d = NULL;
599
600         assert(item);
601
602         /* If force (= modify) is set, we will not modify the acl
603          * afterwards, so the mask can be added now if necessary. */
604         r = parse_acl(item->argument, &item->acl_access, &item->acl_default, !item->force);
605         if (r < 0)
606                 log_warning_errno(errno, "Failed to parse ACL \"%s\": %m. Ignoring",
607                                   item->argument);
608 #else
609         log_warning_errno(ENOSYS, "ACLs are not supported. Ignoring");
610 #endif
611
612         return 0;
613 }
614
615 static int path_set_acl(const char *path, acl_type_t type, acl_t acl, bool modify) {
616         _cleanup_(acl_freep) acl_t dup = NULL;
617         int r;
618
619         if (modify) {
620                 r = acls_for_file(path, type, acl, &dup);
621                 if (r < 0)
622                         return r;
623
624                 r = calc_acl_mask_if_needed(&dup);
625                 if (r < 0)
626                         return r;
627         } else {
628                 dup = acl_dup(acl);
629                 if (!dup)
630                         return -errno;
631
632                 /* the mask was already added earlier if needed */
633         }
634
635         r = add_base_acls_if_needed(&dup, path);
636         if (r < 0)
637                 return r;
638
639         r = acl_set_file(path, type, dup);
640         if (r < 0) {
641                 _cleanup_(acl_free_charpp) char *t;
642
643                 r = -errno;
644                 t = acl_to_any_text(dup, NULL, ',', TEXT_ABBREVIATE);
645                 log_error_errno(r,
646                                 "Setting %s ACL \"%s\" on %s failed: %m",
647                                 type == ACL_TYPE_ACCESS ? "access" : "default",
648                                 strna(t), path);
649         }
650
651         return r;
652 }
653
654 static int path_set_acls(Item *item, const char *path) {
655 #ifdef HAVE_ACL
656         int r;
657
658         assert(item);
659         assert(path);
660
661         if (item->acl_access) {
662                 r = path_set_acl(path, ACL_TYPE_ACCESS, item->acl_access, item->force);
663                 if (r < 0)
664                         return r;
665         }
666
667         if (item->acl_default) {
668                 r = path_set_acl(path, ACL_TYPE_DEFAULT, item->acl_default, item->force);
669                 if (r < 0)
670                         return r;
671         }
672 #endif
673
674         return 0;
675 }
676
677 static int write_one_file(Item *i, const char *path) {
678         _cleanup_close_ int fd = -1;
679         int flags, r = 0;
680         struct stat st;
681
682         assert(i);
683         assert(path);
684
685         flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND|O_NOFOLLOW :
686                 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
687
688         RUN_WITH_UMASK(0000) {
689                 mac_selinux_create_file_prepare(path, S_IFREG);
690                 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
691                 mac_selinux_create_file_clear();
692         }
693
694         if (fd < 0) {
695                 if (i->type == WRITE_FILE && errno == ENOENT)
696                         return 0;
697
698                 log_error_errno(errno, "Failed to create file %s: %m", path);
699                 return -errno;
700         }
701
702         if (i->argument) {
703                 _cleanup_free_ char *unescaped;
704                 ssize_t n;
705                 size_t l;
706
707                 unescaped = cunescape(i->argument);
708                 if (!unescaped)
709                         return log_oom();
710
711                 l = strlen(unescaped);
712                 n = write(fd, unescaped, l);
713
714                 if (n < 0 || (size_t) n < l) {
715                         log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
716                         return n < 0 ? n : -EIO;
717                 }
718         }
719
720         fd = safe_close(fd);
721
722         if (stat(path, &st) < 0)
723                 return log_error_errno(errno, "stat(%s) failed: %m", path);
724
725         if (!S_ISREG(st.st_mode)) {
726                 log_error("%s is not a file.", path);
727                 return -EEXIST;
728         }
729
730         r = path_set_perms(i, path);
731         if (r < 0)
732                 return r;
733
734         return 0;
735 }
736
737 typedef int (*action_t)(Item *, const char *);
738
739 static int item_do_children(Item *i, const char *path, action_t action) {
740         _cleanup_closedir_ DIR *d;
741         int r = 0;
742
743         assert(i);
744         assert(path);
745
746         /* This returns the first error we run into, but nevertheless
747          * tries to go on */
748
749         d = opendir(path);
750         if (!d)
751                 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
752
753         for (;;) {
754                 _cleanup_free_ char *p = NULL;
755                 struct dirent *de;
756                 int q;
757
758                 errno = 0;
759                 de = readdir(d);
760                 if (!de) {
761                         if (errno != 0 && r == 0)
762                                 r = -errno;
763
764                         break;
765                 }
766
767                 if (STR_IN_SET(de->d_name, ".", ".."))
768                         continue;
769
770                 p = strjoin(path, "/", de->d_name, NULL);
771                 if (!p)
772                         return -ENOMEM;
773
774                 q = action(i, p);
775                 if (q < 0 && q != -ENOENT && r == 0)
776                         r = q;
777
778                 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
779                         q = item_do_children(i, p, action);
780                         if (q < 0 && r == 0)
781                                 r = q;
782                 }
783         }
784
785         return r;
786 }
787
788 static int glob_item(Item *i, action_t action, bool recursive) {
789         _cleanup_globfree_ glob_t g = {};
790         int r = 0, k;
791         char **fn;
792
793         errno = 0;
794         k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
795         if (k != 0 && k != GLOB_NOMATCH)
796                 return log_error_errno(errno ?: EIO, "glob(%s) failed: %m", i->path);
797
798         STRV_FOREACH(fn, g.gl_pathv) {
799                 k = action(i, *fn);
800                 if (k < 0 && r == 0)
801                         r = k;
802
803                 if (recursive) {
804                         k = item_do_children(i, *fn, action);
805                         if (k < 0 && r == 0)
806                                 r = k;
807                 }
808         }
809
810         return r;
811 }
812
813 static int create_item(Item *i) {
814         struct stat st;
815         int r = 0;
816
817         assert(i);
818
819         switch (i->type) {
820
821         case IGNORE_PATH:
822         case IGNORE_DIRECTORY_PATH:
823         case REMOVE_PATH:
824         case RECURSIVE_REMOVE_PATH:
825                 return 0;
826
827         case CREATE_FILE:
828         case TRUNCATE_FILE:
829                 r = write_one_file(i, i->path);
830                 if (r < 0)
831                         return r;
832                 break;
833
834         case COPY_FILES:
835                 r = copy_tree(i->argument, i->path, false);
836                 if (r < 0) {
837                         struct stat a, b;
838
839                         if (r != -EEXIST)
840                                 return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
841
842                         if (stat(i->argument, &a) < 0)
843                                 return log_error_errno(errno, "stat(%s) failed: %m", i->argument);
844
845                         if (stat(i->path, &b) < 0)
846                                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
847
848                         if ((a.st_mode ^ b.st_mode) & S_IFMT) {
849                                 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
850                                 return 0;
851                         }
852                 }
853
854                 r = path_set_perms(i, i->path);
855                 if (r < 0)
856                         return r;
857
858                 break;
859
860         case WRITE_FILE:
861                 r = glob_item(i, write_one_file, false);
862                 if (r < 0)
863                         return r;
864
865                 break;
866
867         case CREATE_DIRECTORY:
868         case TRUNCATE_DIRECTORY:
869         case CREATE_SUBVOLUME:
870
871                 RUN_WITH_UMASK(0000)
872                         mkdir_parents_label(i->path, 0755);
873
874                 if (i->type == CREATE_SUBVOLUME) {
875                         RUN_WITH_UMASK((~i->mode) & 0777)
876                                 r = btrfs_subvol_make(i->path);
877                 } else
878                         r = 0;
879
880                 if (IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY) || r == -ENOTTY) {
881                         RUN_WITH_UMASK(0000)
882                                 r = mkdir_label(i->path, i->mode);
883                 }
884
885                 if (r < 0) {
886                         if (r != -EEXIST)
887                                 return log_error_errno(r, "Failed to create directory or subvolume %s: %m", i->path);
888
889                         if (stat(i->path, &st) < 0)
890                                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
891
892                         if (!S_ISDIR(st.st_mode)) {
893                                 log_debug("%s already exists and is not a directory.", i->path);
894                                 return 0;
895                         }
896                 }
897
898                 r = path_set_perms(i, i->path);
899                 if (r < 0)
900                         return r;
901
902                 break;
903
904         case CREATE_FIFO:
905
906                 RUN_WITH_UMASK(0000) {
907                         mac_selinux_create_file_prepare(i->path, S_IFIFO);
908                         r = mkfifo(i->path, i->mode);
909                         mac_selinux_create_file_clear();
910                 }
911
912                 if (r < 0) {
913                         if (errno != EEXIST)
914                                 return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
915
916                         if (stat(i->path, &st) < 0)
917                                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
918
919                         if (!S_ISFIFO(st.st_mode)) {
920
921                                 if (i->force) {
922
923                                         RUN_WITH_UMASK(0000) {
924                                                 mac_selinux_create_file_prepare(i->path, S_IFIFO);
925                                                 r = mkfifo_atomic(i->path, i->mode);
926                                                 mac_selinux_create_file_clear();
927                                         }
928
929                                         if (r < 0)
930                                                 return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
931                                 } else {
932                                         log_debug("%s is not a fifo.", i->path);
933                                         return 0;
934                                 }
935                         }
936                 }
937
938                 r = path_set_perms(i, i->path);
939                 if (r < 0)
940                         return r;
941
942                 break;
943
944         case CREATE_SYMLINK:
945
946                 mac_selinux_create_file_prepare(i->path, S_IFLNK);
947                 r = symlink(i->argument, i->path);
948                 mac_selinux_create_file_clear();
949
950                 if (r < 0) {
951                         _cleanup_free_ char *x = NULL;
952
953                         if (errno != EEXIST)
954                                 return log_error_errno(errno, "symlink(%s, %s) failed: %m", i->argument, i->path);
955
956                         r = readlink_malloc(i->path, &x);
957                         if (r < 0 || !streq(i->argument, x)) {
958
959                                 if (i->force) {
960                                         mac_selinux_create_file_prepare(i->path, S_IFLNK);
961                                         r = symlink_atomic(i->argument, i->path);
962                                         mac_selinux_create_file_clear();
963
964                                         if (r < 0)
965                                                 return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
966                                 } else {
967                                         log_debug("%s is not a symlink or does not point to the correct path.", i->path);
968                                         return 0;
969                                 }
970                         }
971                 }
972
973                 break;
974
975         case CREATE_BLOCK_DEVICE:
976         case CREATE_CHAR_DEVICE: {
977                 mode_t file_type;
978
979                 if (have_effective_cap(CAP_MKNOD) == 0) {
980                         /* In a container we lack CAP_MKNOD. We
981                         shouldn't attempt to create the device node in
982                         that case to avoid noise, and we don't support
983                         virtualized devices in containers anyway. */
984
985                         log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
986                         return 0;
987                 }
988
989                 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
990
991                 RUN_WITH_UMASK(0000) {
992                         mac_selinux_create_file_prepare(i->path, file_type);
993                         r = mknod(i->path, i->mode | file_type, i->major_minor);
994                         mac_selinux_create_file_clear();
995                 }
996
997                 if (r < 0) {
998                         if (errno == EPERM) {
999                                 log_debug("We lack permissions, possibly because of cgroup configuration; "
1000                                           "skipping creation of device node %s.", i->path);
1001                                 return 0;
1002                         }
1003
1004                         if (errno != EEXIST)
1005                                 return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
1006
1007                         if (stat(i->path, &st) < 0)
1008                                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1009
1010                         if ((st.st_mode & S_IFMT) != file_type) {
1011
1012                                 if (i->force) {
1013
1014                                         RUN_WITH_UMASK(0000) {
1015                                                 mac_selinux_create_file_prepare(i->path, file_type);
1016                                                 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
1017                                                 mac_selinux_create_file_clear();
1018                                         }
1019
1020                                         if (r < 0)
1021                                                 return log_error_errno(r, "Failed to create device node %s: %m", i->path);
1022                                 } else {
1023                                         log_debug("%s is not a device node.", i->path);
1024                                         return 0;
1025                                 }
1026                         }
1027                 }
1028
1029                 r = path_set_perms(i, i->path);
1030                 if (r < 0)
1031                         return r;
1032
1033                 break;
1034         }
1035
1036         case ADJUST_MODE:
1037         case RELABEL_PATH:
1038                 r = glob_item(i, path_set_perms, false);
1039                 if (r < 0)
1040                         return r;
1041                 break;
1042
1043         case RECURSIVE_RELABEL_PATH:
1044                 r = glob_item(i, path_set_perms, true);
1045                 if (r < 0)
1046                         return r;
1047                 break;
1048
1049         case SET_XATTR:
1050                 r = glob_item(i, path_set_xattrs, false);
1051                 if (r < 0)
1052                         return r;
1053                 break;
1054
1055         case RECURSIVE_SET_XATTR:
1056                 r = glob_item(i, path_set_xattrs, true);
1057                 if (r < 0)
1058                         return r;
1059                 break;
1060
1061         case SET_ACL:
1062                 r = glob_item(i, path_set_acls, false);
1063                 if (r < 0)
1064                         return r;
1065                 break;
1066
1067         case RECURSIVE_SET_ACL:
1068                 r = glob_item(i, path_set_acls, true);
1069                 if (r < 0)
1070                         return r;
1071                 break;
1072         }
1073
1074         log_debug("%s created successfully.", i->path);
1075
1076         return 0;
1077 }
1078
1079 static int remove_item_instance(Item *i, const char *instance) {
1080         int r;
1081
1082         assert(i);
1083
1084         switch (i->type) {
1085
1086         case REMOVE_PATH:
1087                 if (remove(instance) < 0 && errno != ENOENT)
1088                         return log_error_errno(errno, "rm(%s): %m", instance);
1089
1090                 break;
1091
1092         case TRUNCATE_DIRECTORY:
1093         case RECURSIVE_REMOVE_PATH:
1094                 /* FIXME: we probably should use dir_cleanup() here
1095                  * instead of rm_rf() so that 'x' is honoured. */
1096                 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
1097                 if (r < 0 && r != -ENOENT)
1098                         return log_error_errno(r, "rm_rf(%s): %m", instance);
1099
1100                 break;
1101
1102         default:
1103                 assert_not_reached("wut?");
1104         }
1105
1106         return 0;
1107 }
1108
1109 static int remove_item(Item *i) {
1110         int r = 0;
1111
1112         assert(i);
1113
1114         switch (i->type) {
1115
1116         case CREATE_FILE:
1117         case TRUNCATE_FILE:
1118         case CREATE_DIRECTORY:
1119         case CREATE_SUBVOLUME:
1120         case CREATE_FIFO:
1121         case CREATE_SYMLINK:
1122         case CREATE_CHAR_DEVICE:
1123         case CREATE_BLOCK_DEVICE:
1124         case IGNORE_PATH:
1125         case IGNORE_DIRECTORY_PATH:
1126         case ADJUST_MODE:
1127         case RELABEL_PATH:
1128         case RECURSIVE_RELABEL_PATH:
1129         case WRITE_FILE:
1130         case COPY_FILES:
1131         case SET_XATTR:
1132         case RECURSIVE_SET_XATTR:
1133         case SET_ACL:
1134         case RECURSIVE_SET_ACL:
1135                 break;
1136
1137         case REMOVE_PATH:
1138         case TRUNCATE_DIRECTORY:
1139         case RECURSIVE_REMOVE_PATH:
1140                 r = glob_item(i, remove_item_instance, false);
1141                 break;
1142         }
1143
1144         return r;
1145 }
1146
1147 static int clean_item_instance(Item *i, const char* instance) {
1148         _cleanup_closedir_ DIR *d = NULL;
1149         struct stat s, ps;
1150         bool mountpoint;
1151         int r;
1152         usec_t cutoff, n;
1153
1154         assert(i);
1155
1156         if (!i->age_set)
1157                 return 0;
1158
1159         n = now(CLOCK_REALTIME);
1160         if (n < i->age)
1161                 return 0;
1162
1163         cutoff = n - i->age;
1164
1165         d = opendir(instance);
1166         if (!d) {
1167                 if (errno == ENOENT || errno == ENOTDIR)
1168                         return 0;
1169
1170                 log_error_errno(errno, "Failed to open directory %s: %m", i->path);
1171                 return -errno;
1172         }
1173
1174         if (fstat(dirfd(d), &s) < 0)
1175                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1176
1177         if (!S_ISDIR(s.st_mode)) {
1178                 log_error("%s is not a directory.", i->path);
1179                 return -ENOTDIR;
1180         }
1181
1182         if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
1183                 return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
1184
1185         mountpoint = s.st_dev != ps.st_dev ||
1186                      (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1187
1188         r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1189                         MAX_DEPTH, i->keep_first_level);
1190         return r;
1191 }
1192
1193 static int clean_item(Item *i) {
1194         int r = 0;
1195
1196         assert(i);
1197
1198         switch (i->type) {
1199         case CREATE_DIRECTORY:
1200         case CREATE_SUBVOLUME:
1201         case TRUNCATE_DIRECTORY:
1202         case IGNORE_PATH:
1203         case COPY_FILES:
1204                 clean_item_instance(i, i->path);
1205                 break;
1206         case IGNORE_DIRECTORY_PATH:
1207                 r = glob_item(i, clean_item_instance, false);
1208                 break;
1209         default:
1210                 break;
1211         }
1212
1213         return r;
1214 }
1215
1216 static int process_item_array(ItemArray *array);
1217
1218 static int process_item(Item *i) {
1219         int r, q, p, t = 0;
1220         _cleanup_free_ char *prefix = NULL;
1221
1222         assert(i);
1223
1224         if (i->done)
1225                 return 0;
1226
1227         i->done = true;
1228
1229         prefix = malloc(strlen(i->path) + 1);
1230         if (!prefix)
1231                 return log_oom();
1232
1233         PATH_FOREACH_PREFIX(prefix, i->path) {
1234                 ItemArray *j;
1235
1236                 j = hashmap_get(items, prefix);
1237                 if (j) {
1238                         int s;
1239
1240                         s = process_item_array(j);
1241                         if (s < 0 && t == 0)
1242                                 t = s;
1243                 }
1244         }
1245
1246         r = arg_create ? create_item(i) : 0;
1247         q = arg_remove ? remove_item(i) : 0;
1248         p = arg_clean ? clean_item(i) : 0;
1249
1250         return t < 0 ? t :
1251                 r < 0 ? r :
1252                 q < 0 ? q :
1253                 p;
1254 }
1255
1256 static int process_item_array(ItemArray *array) {
1257         unsigned n;
1258         int r = 0, k;
1259
1260         assert(array);
1261
1262         for (n = 0; n < array->count; n++) {
1263                 k = process_item(array->items + n);
1264                 if (k < 0 && r == 0)
1265                         r = k;
1266         }
1267
1268         return r;
1269 }
1270
1271 static void item_free_contents(Item *i) {
1272         assert(i);
1273         free(i->path);
1274         free(i->argument);
1275         strv_free(i->xattrs);
1276
1277 #ifdef HAVE_ACL
1278         acl_free(i->acl_access);
1279         acl_free(i->acl_default);
1280 #endif
1281 }
1282
1283 static void item_array_free(ItemArray *a) {
1284         unsigned n;
1285
1286         if (!a)
1287                 return;
1288
1289         for (n = 0; n < a->count; n++)
1290                 item_free_contents(a->items + n);
1291         free(a->items);
1292         free(a);
1293 }
1294
1295 static bool item_compatible(Item *a, Item *b) {
1296         assert(a);
1297         assert(b);
1298         assert(streq(a->path, b->path));
1299
1300         if (takes_ownership(a->type) && takes_ownership(b->type))
1301                 /* check if the items are the same */
1302                 return  streq_ptr(a->argument, b->argument) &&
1303
1304                         a->uid_set == b->uid_set &&
1305                         a->uid == b->uid &&
1306
1307                         a->gid_set == b->gid_set &&
1308                         a->gid == b->gid &&
1309
1310                         a->mode_set == b->mode_set &&
1311                         a->mode == b->mode &&
1312
1313                         a->age_set == b->age_set &&
1314                         a->age == b->age &&
1315
1316                         a->mask_perms == b->mask_perms &&
1317
1318                         a->keep_first_level == b->keep_first_level &&
1319
1320                         a->major_minor == b->major_minor;
1321
1322         return true;
1323 }
1324
1325 static bool should_include_path(const char *path) {
1326         char **prefix;
1327
1328         STRV_FOREACH(prefix, arg_exclude_prefixes)
1329                 if (path_startswith(path, *prefix))
1330                         return false;
1331
1332         STRV_FOREACH(prefix, arg_include_prefixes)
1333                 if (path_startswith(path, *prefix))
1334                         return true;
1335
1336         /* no matches, so we should include this path only if we
1337          * have no whitelist at all */
1338         return strv_length(arg_include_prefixes) == 0;
1339 }
1340
1341 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1342
1343         static const Specifier specifier_table[] = {
1344                 { 'm', specifier_machine_id, NULL },
1345                 { 'b', specifier_boot_id, NULL },
1346                 { 'H', specifier_host_name, NULL },
1347                 { 'v', specifier_kernel_release, NULL },
1348                 {}
1349         };
1350
1351         _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1352         _cleanup_(item_free_contents) Item i = {};
1353         ItemArray *existing;
1354         Hashmap *h;
1355         int r, c = -1, pos;
1356         bool force = false, boot = false;
1357
1358         assert(fname);
1359         assert(line >= 1);
1360         assert(buffer);
1361
1362         r = sscanf(buffer,
1363                    "%ms %ms %ms %ms %ms %ms %n",
1364                    &action,
1365                    &path,
1366                    &mode,
1367                    &user,
1368                    &group,
1369                    &age,
1370                    &c);
1371         if (r < 2) {
1372                 log_error("[%s:%u] Syntax error.", fname, line);
1373                 return -EIO;
1374         }
1375
1376         if (isempty(action)) {
1377                 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1378                 return -EINVAL;
1379         }
1380
1381         for (pos = 1; action[pos]; pos++) {
1382                 if (action[pos] == '!' && !boot)
1383                         boot = true;
1384                 else if (action[pos] == '+' && !force)
1385                         force = true;
1386                 else {
1387                         log_error("[%s:%u] Unknown modifiers in command '%s'",
1388                                   fname, line, action);
1389                         return -EINVAL;
1390                 }
1391         }
1392
1393         if (boot && !arg_boot)
1394                 return 0;
1395
1396         i.type = action[0];
1397         i.force = force;
1398
1399         r = specifier_printf(path, specifier_table, NULL, &i.path);
1400         if (r < 0) {
1401                 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1402                 return r;
1403         }
1404
1405         if (c >= 0)  {
1406                 c += strspn(buffer+c, WHITESPACE);
1407                 if (buffer[c] != 0 && (buffer[c] != '-' || buffer[c+1] != 0)) {
1408                         i.argument = unquote(buffer+c, "\"");
1409                         if (!i.argument)
1410                                 return log_oom();
1411                 }
1412         }
1413
1414         switch (i.type) {
1415
1416         case CREATE_FILE:
1417         case TRUNCATE_FILE:
1418         case CREATE_DIRECTORY:
1419         case CREATE_SUBVOLUME:
1420         case TRUNCATE_DIRECTORY:
1421         case CREATE_FIFO:
1422         case IGNORE_PATH:
1423         case IGNORE_DIRECTORY_PATH:
1424         case REMOVE_PATH:
1425         case RECURSIVE_REMOVE_PATH:
1426         case ADJUST_MODE:
1427         case RELABEL_PATH:
1428         case RECURSIVE_RELABEL_PATH:
1429                 break;
1430
1431         case CREATE_SYMLINK:
1432                 if (!i.argument) {
1433                         i.argument = strappend("/usr/share/factory/", i.path);
1434                         if (!i.argument)
1435                                 return log_oom();
1436                 }
1437                 break;
1438
1439         case WRITE_FILE:
1440                 if (!i.argument) {
1441                         log_error("[%s:%u] Write file requires argument.", fname, line);
1442                         return -EBADMSG;
1443                 }
1444                 break;
1445
1446         case COPY_FILES:
1447                 if (!i.argument) {
1448                         i.argument = strappend("/usr/share/factory/", i.path);
1449                         if (!i.argument)
1450                                 return log_oom();
1451                 } else if (!path_is_absolute(i.argument)) {
1452                         log_error("[%s:%u] Source path is not absolute.", fname, line);
1453                         return -EBADMSG;
1454                 }
1455
1456                 path_kill_slashes(i.argument);
1457                 break;
1458
1459         case CREATE_CHAR_DEVICE:
1460         case CREATE_BLOCK_DEVICE: {
1461                 unsigned major, minor;
1462
1463                 if (!i.argument) {
1464                         log_error("[%s:%u] Device file requires argument.", fname, line);
1465                         return -EBADMSG;
1466                 }
1467
1468                 if (sscanf(i.argument, "%u:%u", &major, &minor) != 2) {
1469                         log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i.argument);
1470                         return -EBADMSG;
1471                 }
1472
1473                 i.major_minor = makedev(major, minor);
1474                 break;
1475         }
1476
1477         case SET_XATTR:
1478         case RECURSIVE_SET_XATTR:
1479                 if (!i.argument) {
1480                         log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1481                         return -EBADMSG;
1482                 }
1483                 r = get_xattrs_from_arg(&i);
1484                 if (r < 0)
1485                         return r;
1486                 break;
1487
1488         case SET_ACL:
1489         case RECURSIVE_SET_ACL:
1490                 if (!i.argument) {
1491                         log_error("[%s:%u] Set ACLs requires argument.", fname, line);
1492                         return -EBADMSG;
1493                 }
1494                 r = get_acls_from_arg(&i);
1495                 if (r < 0)
1496                         return r;
1497                 break;
1498
1499         default:
1500                 log_error("[%s:%u] Unknown command type '%c'.", fname, line, i.type);
1501                 return -EBADMSG;
1502         }
1503
1504         if (!path_is_absolute(i.path)) {
1505                 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i.path);
1506                 return -EBADMSG;
1507         }
1508
1509         path_kill_slashes(i.path);
1510
1511         if (!should_include_path(i.path))
1512                 return 0;
1513
1514         if (arg_root) {
1515                 char *p;
1516
1517                 p = strappend(arg_root, i.path);
1518                 if (!p)
1519                         return log_oom();
1520
1521                 free(i.path);
1522                 i.path = p;
1523         }
1524
1525         if (user && !streq(user, "-")) {
1526                 const char *u = user;
1527
1528                 r = get_user_creds(&u, &i.uid, NULL, NULL, NULL);
1529                 if (r < 0) {
1530                         log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1531                         return r;
1532                 }
1533
1534                 i.uid_set = true;
1535         }
1536
1537         if (group && !streq(group, "-")) {
1538                 const char *g = group;
1539
1540                 r = get_group_creds(&g, &i.gid);
1541                 if (r < 0) {
1542                         log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1543                         return r;
1544                 }
1545
1546                 i.gid_set = true;
1547         }
1548
1549         if (mode && !streq(mode, "-")) {
1550                 const char *mm = mode;
1551                 unsigned m;
1552
1553                 if (*mm == '~') {
1554                         i.mask_perms = true;
1555                         mm++;
1556                 }
1557
1558                 if (sscanf(mm, "%o", &m) != 1) {
1559                         log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1560                         return -ENOENT;
1561                 }
1562
1563                 i.mode = m;
1564                 i.mode_set = true;
1565         } else
1566                 i.mode = IN_SET(i.type, CREATE_DIRECTORY, CREATE_SUBVOLUME, TRUNCATE_DIRECTORY)
1567                         ? 0755 : 0644;
1568
1569         if (age && !streq(age, "-")) {
1570                 const char *a = age;
1571
1572                 if (*a == '~') {
1573                         i.keep_first_level = true;
1574                         a++;
1575                 }
1576
1577                 if (parse_sec(a, &i.age) < 0) {
1578                         log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1579                         return -EBADMSG;
1580                 }
1581
1582                 i.age_set = true;
1583         }
1584
1585         h = needs_glob(i.type) ? globs : items;
1586
1587         existing = hashmap_get(h, i.path);
1588         if (existing) {
1589                 unsigned n;
1590
1591                 for (n = 0; n < existing->count; n++) {
1592                         if (!item_compatible(existing->items + n, &i))
1593                                 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
1594                                             fname, line, i.path);
1595                 }
1596         } else {
1597                 existing = new0(ItemArray, 1);
1598                 r = hashmap_put(h, i.path, existing);
1599                 if (r < 0)
1600                         return log_oom();
1601         }
1602
1603         if (!GREEDY_REALLOC(existing->items, existing->size, existing->count + 1))
1604                 return log_oom();
1605
1606         memcpy(existing->items + existing->count++, &i, sizeof(i));
1607         zero(i);
1608         return 0;
1609 }
1610
1611 static void help(void) {
1612         printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1613                "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1614                "  -h --help                 Show this help\n"
1615                "     --version              Show package version\n"
1616                "     --create               Create marked files/directories\n"
1617                "     --clean                Clean up marked directories\n"
1618                "     --remove               Remove marked files/directories\n"
1619                "     --boot                 Execute actions only safe at boot\n"
1620                "     --prefix=PATH          Only apply rules that apply to paths with the specified prefix\n"
1621                "     --exclude-prefix=PATH  Ignore rules that apply to paths with the specified prefix\n"
1622                "     --root=PATH            Operate on an alternate filesystem root\n",
1623                program_invocation_short_name);
1624 }
1625
1626 static int parse_argv(int argc, char *argv[]) {
1627
1628         enum {
1629                 ARG_VERSION = 0x100,
1630                 ARG_CREATE,
1631                 ARG_CLEAN,
1632                 ARG_REMOVE,
1633                 ARG_BOOT,
1634                 ARG_PREFIX,
1635                 ARG_EXCLUDE_PREFIX,
1636                 ARG_ROOT,
1637         };
1638
1639         static const struct option options[] = {
1640                 { "help",           no_argument,         NULL, 'h'                },
1641                 { "version",        no_argument,         NULL, ARG_VERSION        },
1642                 { "create",         no_argument,         NULL, ARG_CREATE         },
1643                 { "clean",          no_argument,         NULL, ARG_CLEAN          },
1644                 { "remove",         no_argument,         NULL, ARG_REMOVE         },
1645                 { "boot",           no_argument,         NULL, ARG_BOOT           },
1646                 { "prefix",         required_argument,   NULL, ARG_PREFIX         },
1647                 { "exclude-prefix", required_argument,   NULL, ARG_EXCLUDE_PREFIX },
1648                 { "root",           required_argument,   NULL, ARG_ROOT           },
1649                 {}
1650         };
1651
1652         int c;
1653
1654         assert(argc >= 0);
1655         assert(argv);
1656
1657         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1658
1659                 switch (c) {
1660
1661                 case 'h':
1662                         help();
1663                         return 0;
1664
1665                 case ARG_VERSION:
1666                         puts(PACKAGE_STRING);
1667                         puts(SYSTEMD_FEATURES);
1668                         return 0;
1669
1670                 case ARG_CREATE:
1671                         arg_create = true;
1672                         break;
1673
1674                 case ARG_CLEAN:
1675                         arg_clean = true;
1676                         break;
1677
1678                 case ARG_REMOVE:
1679                         arg_remove = true;
1680                         break;
1681
1682                 case ARG_BOOT:
1683                         arg_boot = true;
1684                         break;
1685
1686                 case ARG_PREFIX:
1687                         if (strv_push(&arg_include_prefixes, optarg) < 0)
1688                                 return log_oom();
1689                         break;
1690
1691                 case ARG_EXCLUDE_PREFIX:
1692                         if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1693                                 return log_oom();
1694                         break;
1695
1696                 case ARG_ROOT:
1697                         free(arg_root);
1698                         arg_root = path_make_absolute_cwd(optarg);
1699                         if (!arg_root)
1700                                 return log_oom();
1701
1702                         path_kill_slashes(arg_root);
1703                         break;
1704
1705                 case '?':
1706                         return -EINVAL;
1707
1708                 default:
1709                         assert_not_reached("Unhandled option");
1710                 }
1711
1712         if (!arg_clean && !arg_create && !arg_remove) {
1713                 log_error("You need to specify at least one of --clean, --create or --remove.");
1714                 return -EINVAL;
1715         }
1716
1717         return 1;
1718 }
1719
1720 static int read_config_file(const char *fn, bool ignore_enoent) {
1721         _cleanup_fclose_ FILE *f = NULL;
1722         char line[LINE_MAX];
1723         Iterator iterator;
1724         unsigned v = 0;
1725         Item *i;
1726         int r;
1727
1728         assert(fn);
1729
1730         r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1731         if (r < 0) {
1732                 if (ignore_enoent && r == -ENOENT)
1733                         return 0;
1734
1735                 return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
1736         }
1737
1738         FOREACH_LINE(line, f, break) {
1739                 char *l;
1740                 int k;
1741
1742                 v++;
1743
1744                 l = strstrip(line);
1745                 if (*l == '#' || *l == 0)
1746                         continue;
1747
1748                 k = parse_line(fn, v, l);
1749                 if (k < 0 && r == 0)
1750                         r = k;
1751         }
1752
1753         /* we have to determine age parameter for each entry of type X */
1754         HASHMAP_FOREACH(i, globs, iterator) {
1755                 Iterator iter;
1756                 Item *j, *candidate_item = NULL;
1757
1758                 if (i->type != IGNORE_DIRECTORY_PATH)
1759                         continue;
1760
1761                 HASHMAP_FOREACH(j, items, iter) {
1762                         if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME)
1763                                 continue;
1764
1765                         if (path_equal(j->path, i->path)) {
1766                                 candidate_item = j;
1767                                 break;
1768                         }
1769
1770                         if ((!candidate_item && path_startswith(i->path, j->path)) ||
1771                             (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1772                                 candidate_item = j;
1773                 }
1774
1775                 if (candidate_item && candidate_item->age_set) {
1776                         i->age = candidate_item->age;
1777                         i->age_set = true;
1778                 }
1779         }
1780
1781         if (ferror(f)) {
1782                 log_error_errno(errno, "Failed to read from file %s: %m", fn);
1783                 if (r == 0)
1784                         r = -EIO;
1785         }
1786
1787         return r;
1788 }
1789
1790 int main(int argc, char *argv[]) {
1791         int r, k;
1792         ItemArray *a;
1793         Iterator iterator;
1794
1795         r = parse_argv(argc, argv);
1796         if (r <= 0)
1797                 goto finish;
1798
1799         log_set_target(LOG_TARGET_AUTO);
1800         log_parse_environment();
1801         log_open();
1802
1803         umask(0022);
1804
1805         mac_selinux_init(NULL);
1806
1807         items = hashmap_new(&string_hash_ops);
1808         globs = hashmap_new(&string_hash_ops);
1809
1810         if (!items || !globs) {
1811                 r = log_oom();
1812                 goto finish;
1813         }
1814
1815         r = 0;
1816
1817         if (optind < argc) {
1818                 int j;
1819
1820                 for (j = optind; j < argc; j++) {
1821                         k = read_config_file(argv[j], false);
1822                         if (k < 0 && r == 0)
1823                                 r = k;
1824                 }
1825
1826         } else {
1827                 _cleanup_strv_free_ char **files = NULL;
1828                 char **f;
1829
1830                 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1831                 if (r < 0) {
1832                         log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
1833                         goto finish;
1834                 }
1835
1836                 STRV_FOREACH(f, files) {
1837                         k = read_config_file(*f, true);
1838                         if (k < 0 && r == 0)
1839                                 r = k;
1840                 }
1841         }
1842
1843         HASHMAP_FOREACH(a, globs, iterator) {
1844                 k = process_item_array(a);
1845                 if (k < 0 && r == 0)
1846                         r = k;
1847         }
1848
1849         HASHMAP_FOREACH(a, items, iterator) {
1850                 k = process_item_array(a);
1851                 if (k < 0 && r == 0)
1852                         r = k;
1853         }
1854
1855 finish:
1856         while ((a = hashmap_steal_first(items)))
1857                 item_array_free(a);
1858
1859         while ((a = hashmap_steal_first(globs)))
1860                 item_array_free(a);
1861
1862         hashmap_free(items);
1863         hashmap_free(globs);
1864
1865         free(arg_include_prefixes);
1866         free(arg_exclude_prefixes);
1867         free(arg_root);
1868
1869         set_free_free(unix_sockets);
1870
1871         mac_selinux_finish();
1872
1873         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1874 }