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