chiark / gitweb /
tmpfiles: make sure not to concatenate non-absolute path
[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         Hashmap *h;
1242         int r, n = -1, pos;
1243         bool force = false, boot = false;
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         for (pos = 1; action[pos]; pos++) {
1269                 if (action[pos] == '!' && !boot)
1270                         boot = true;
1271                 else if (action[pos] == '+' && !force)
1272                         force = true;
1273                 else {
1274                         log_error("[%s:%u] Unknown modifiers in command '%s'",
1275                                   fname, line, action);
1276                         return -EINVAL;
1277                 }
1278         }
1279
1280         if (boot && !arg_boot)
1281                 return 0;
1282
1283         i = new0(Item, 1);
1284         if (!i)
1285                 return log_oom();
1286
1287         i->type = action[0];
1288         i->force = force;
1289
1290         r = specifier_printf(path, specifier_table, NULL, &i->path);
1291         if (r < 0) {
1292                 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1293                 return r;
1294         }
1295
1296         if (n >= 0)  {
1297                 n += strspn(buffer+n, WHITESPACE);
1298                 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1299                         i->argument = unquote(buffer+n, "\"");
1300                         if (!i->argument)
1301                                 return log_oom();
1302                 }
1303         }
1304
1305         switch (i->type) {
1306
1307         case CREATE_FILE:
1308         case TRUNCATE_FILE:
1309         case CREATE_DIRECTORY:
1310         case CREATE_SUBVOLUME:
1311         case TRUNCATE_DIRECTORY:
1312         case CREATE_FIFO:
1313         case IGNORE_PATH:
1314         case IGNORE_DIRECTORY_PATH:
1315         case REMOVE_PATH:
1316         case RECURSIVE_REMOVE_PATH:
1317         case ADJUST_MODE:
1318         case RELABEL_PATH:
1319         case RECURSIVE_RELABEL_PATH:
1320                 break;
1321
1322         case CREATE_SYMLINK:
1323                 if (!i->argument) {
1324                         i->argument = strappend("/usr/share/factory/", i->path);
1325                         if (!i->argument)
1326                                 return log_oom();
1327                 }
1328                 break;
1329
1330         case WRITE_FILE:
1331                 if (!i->argument) {
1332                         log_error("[%s:%u] Write file requires argument.", fname, line);
1333                         return -EBADMSG;
1334                 }
1335                 break;
1336
1337         case COPY_FILES:
1338                 if (!i->argument) {
1339                         i->argument = strappend("/usr/share/factory/", i->path);
1340                         if (!i->argument)
1341                                 return log_oom();
1342                 } else if (!path_is_absolute(i->argument)) {
1343                         log_error("[%s:%u] Source path is not absolute.", fname, line);
1344                         return -EBADMSG;
1345                 }
1346
1347                 path_kill_slashes(i->argument);
1348                 break;
1349
1350         case CREATE_CHAR_DEVICE:
1351         case CREATE_BLOCK_DEVICE: {
1352                 unsigned major, minor;
1353
1354                 if (!i->argument) {
1355                         log_error("[%s:%u] Device file requires argument.", fname, line);
1356                         return -EBADMSG;
1357                 }
1358
1359                 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1360                         log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1361                         return -EBADMSG;
1362                 }
1363
1364                 i->major_minor = makedev(major, minor);
1365                 break;
1366         }
1367
1368         case SET_XATTR:
1369                 if (!i->argument) {
1370                         log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1371                         return -EBADMSG;
1372                 }
1373                 r = get_xattrs_from_arg(i);
1374                 if (r < 0)
1375                         return r;
1376                 break;
1377
1378         default:
1379                 log_error("[%s:%u] Unknown command type '%c'.", fname, line, i->type);
1380                 return -EBADMSG;
1381         }
1382
1383         if (!path_is_absolute(i->path)) {
1384                 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1385                 return -EBADMSG;
1386         }
1387
1388         path_kill_slashes(i->path);
1389
1390         if (!should_include_path(i->path))
1391                 return 0;
1392
1393         if (arg_root) {
1394                 char *p;
1395
1396                 p = strappend(arg_root, i->path);
1397                 if (!p)
1398                         return log_oom();
1399
1400                 free(i->path);
1401                 i->path = p;
1402         }
1403
1404         if (user && !streq(user, "-")) {
1405                 const char *u = user;
1406
1407                 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1408                 if (r < 0) {
1409                         log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1410                         return r;
1411                 }
1412
1413                 i->uid_set = true;
1414         }
1415
1416         if (group && !streq(group, "-")) {
1417                 const char *g = group;
1418
1419                 r = get_group_creds(&g, &i->gid);
1420                 if (r < 0) {
1421                         log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1422                         return r;
1423                 }
1424
1425                 i->gid_set = true;
1426         }
1427
1428         if (mode && !streq(mode, "-")) {
1429                 const char *mm = mode;
1430                 unsigned m;
1431
1432                 if (*mm == '~') {
1433                         i->mask_perms = true;
1434                         mm++;
1435                 }
1436
1437                 if (sscanf(mm, "%o", &m) != 1) {
1438                         log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1439                         return -ENOENT;
1440                 }
1441
1442                 i->mode = m;
1443                 i->mode_set = true;
1444         } else
1445                 i->mode =
1446                         i->type == CREATE_DIRECTORY ||
1447                         i->type == CREATE_SUBVOLUME ||
1448                         i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1449
1450         if (age && !streq(age, "-")) {
1451                 const char *a = age;
1452
1453                 if (*a == '~') {
1454                         i->keep_first_level = true;
1455                         a++;
1456                 }
1457
1458                 if (parse_sec(a, &i->age) < 0) {
1459                         log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1460                         return -EBADMSG;
1461                 }
1462
1463                 i->age_set = true;
1464         }
1465
1466         h = needs_glob(i->type) ? globs : items;
1467
1468         existing = hashmap_get(h, i->path);
1469         if (existing) {
1470                 if (i->type == SET_XATTR) {
1471                         r = strv_extend_strv(&existing->xattrs, i->xattrs);
1472                         if (r < 0)
1473                                 return log_oom();
1474                         return 0;
1475                 } else if (existing->type == SET_XATTR) {
1476                         r = strv_extend_strv(&i->xattrs, existing->xattrs);
1477                         if (r < 0)
1478                                 return log_oom();
1479                         r = hashmap_replace(h, i->path, i);
1480                         if (r < 0) {
1481                                 log_error("Failed to replace item for %s.", i->path);
1482                                 return r;
1483                         }
1484                         item_free(existing);
1485                 } else {
1486                         /* Two identical items are fine */
1487                         if (!item_equal(existing, i))
1488                                 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
1489                                             fname, line, i->path);
1490                         return 0;
1491                 }
1492         } else {
1493                 r = hashmap_put(h, i->path, i);
1494                 if (r < 0) {
1495                         log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1496                         return r;
1497                 }
1498         }
1499
1500         i = NULL; /* avoid cleanup */
1501
1502         return 0;
1503 }
1504
1505 static void help(void) {
1506         printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1507                "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1508                "  -h --help                 Show this help\n"
1509                "     --version              Show package version\n"
1510                "     --create               Create marked files/directories\n"
1511                "     --clean                Clean up marked directories\n"
1512                "     --remove               Remove marked files/directories\n"
1513                "     --boot                 Execute actions only safe at boot\n"
1514                "     --prefix=PATH          Only apply rules that apply to paths with the specified prefix\n"
1515                "     --exclude-prefix=PATH  Ignore rules that apply to paths with the specified prefix\n"
1516                "     --root=PATH            Operate on an alternate filesystem root\n",
1517                program_invocation_short_name);
1518 }
1519
1520 static int parse_argv(int argc, char *argv[]) {
1521
1522         enum {
1523                 ARG_VERSION = 0x100,
1524                 ARG_CREATE,
1525                 ARG_CLEAN,
1526                 ARG_REMOVE,
1527                 ARG_BOOT,
1528                 ARG_PREFIX,
1529                 ARG_EXCLUDE_PREFIX,
1530                 ARG_ROOT,
1531         };
1532
1533         static const struct option options[] = {
1534                 { "help",           no_argument,         NULL, 'h'                },
1535                 { "version",        no_argument,         NULL, ARG_VERSION        },
1536                 { "create",         no_argument,         NULL, ARG_CREATE         },
1537                 { "clean",          no_argument,         NULL, ARG_CLEAN          },
1538                 { "remove",         no_argument,         NULL, ARG_REMOVE         },
1539                 { "boot",           no_argument,         NULL, ARG_BOOT           },
1540                 { "prefix",         required_argument,   NULL, ARG_PREFIX         },
1541                 { "exclude-prefix", required_argument,   NULL, ARG_EXCLUDE_PREFIX },
1542                 { "root",           required_argument,   NULL, ARG_ROOT           },
1543                 {}
1544         };
1545
1546         int c;
1547
1548         assert(argc >= 0);
1549         assert(argv);
1550
1551         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1552
1553                 switch (c) {
1554
1555                 case 'h':
1556                         help();
1557                         return 0;
1558
1559                 case ARG_VERSION:
1560                         puts(PACKAGE_STRING);
1561                         puts(SYSTEMD_FEATURES);
1562                         return 0;
1563
1564                 case ARG_CREATE:
1565                         arg_create = true;
1566                         break;
1567
1568                 case ARG_CLEAN:
1569                         arg_clean = true;
1570                         break;
1571
1572                 case ARG_REMOVE:
1573                         arg_remove = true;
1574                         break;
1575
1576                 case ARG_BOOT:
1577                         arg_boot = true;
1578                         break;
1579
1580                 case ARG_PREFIX:
1581                         if (strv_push(&arg_include_prefixes, optarg) < 0)
1582                                 return log_oom();
1583                         break;
1584
1585                 case ARG_EXCLUDE_PREFIX:
1586                         if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1587                                 return log_oom();
1588                         break;
1589
1590                 case ARG_ROOT:
1591                         free(arg_root);
1592                         arg_root = path_make_absolute_cwd(optarg);
1593                         if (!arg_root)
1594                                 return log_oom();
1595
1596                         path_kill_slashes(arg_root);
1597                         break;
1598
1599                 case '?':
1600                         return -EINVAL;
1601
1602                 default:
1603                         assert_not_reached("Unhandled option");
1604                 }
1605
1606         if (!arg_clean && !arg_create && !arg_remove) {
1607                 log_error("You need to specify at least one of --clean, --create or --remove.");
1608                 return -EINVAL;
1609         }
1610
1611         return 1;
1612 }
1613
1614 static int read_config_file(const char *fn, bool ignore_enoent) {
1615         _cleanup_fclose_ FILE *f = NULL;
1616         char line[LINE_MAX];
1617         Iterator iterator;
1618         unsigned v = 0;
1619         Item *i;
1620         int r;
1621
1622         assert(fn);
1623
1624         r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1625         if (r < 0) {
1626                 if (ignore_enoent && r == -ENOENT)
1627                         return 0;
1628
1629                 return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
1630         }
1631
1632         FOREACH_LINE(line, f, break) {
1633                 char *l;
1634                 int k;
1635
1636                 v++;
1637
1638                 l = strstrip(line);
1639                 if (*l == '#' || *l == 0)
1640                         continue;
1641
1642                 k = parse_line(fn, v, l);
1643                 if (k < 0 && r == 0)
1644                         r = k;
1645         }
1646
1647         /* we have to determine age parameter for each entry of type X */
1648         HASHMAP_FOREACH(i, globs, iterator) {
1649                 Iterator iter;
1650                 Item *j, *candidate_item = NULL;
1651
1652                 if (i->type != IGNORE_DIRECTORY_PATH)
1653                         continue;
1654
1655                 HASHMAP_FOREACH(j, items, iter) {
1656                         if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME)
1657                                 continue;
1658
1659                         if (path_equal(j->path, i->path)) {
1660                                 candidate_item = j;
1661                                 break;
1662                         }
1663
1664                         if ((!candidate_item && path_startswith(i->path, j->path)) ||
1665                             (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1666                                 candidate_item = j;
1667                 }
1668
1669                 if (candidate_item && candidate_item->age_set) {
1670                         i->age = candidate_item->age;
1671                         i->age_set = true;
1672                 }
1673         }
1674
1675         if (ferror(f)) {
1676                 log_error_errno(errno, "Failed to read from file %s: %m", fn);
1677                 if (r == 0)
1678                         r = -EIO;
1679         }
1680
1681         return r;
1682 }
1683
1684 int main(int argc, char *argv[]) {
1685         int r, k;
1686         Item *i;
1687         Iterator iterator;
1688
1689         r = parse_argv(argc, argv);
1690         if (r <= 0)
1691                 goto finish;
1692
1693         log_set_target(LOG_TARGET_AUTO);
1694         log_parse_environment();
1695         log_open();
1696
1697         umask(0022);
1698
1699         mac_selinux_init(NULL);
1700
1701         items = hashmap_new(&string_hash_ops);
1702         globs = hashmap_new(&string_hash_ops);
1703
1704         if (!items || !globs) {
1705                 r = log_oom();
1706                 goto finish;
1707         }
1708
1709         r = 0;
1710
1711         if (optind < argc) {
1712                 int j;
1713
1714                 for (j = optind; j < argc; j++) {
1715                         k = read_config_file(argv[j], false);
1716                         if (k < 0 && r == 0)
1717                                 r = k;
1718                 }
1719
1720         } else {
1721                 _cleanup_strv_free_ char **files = NULL;
1722                 char **f;
1723
1724                 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1725                 if (r < 0) {
1726                         log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
1727                         goto finish;
1728                 }
1729
1730                 STRV_FOREACH(f, files) {
1731                         k = read_config_file(*f, true);
1732                         if (k < 0 && r == 0)
1733                                 r = k;
1734                 }
1735         }
1736
1737         HASHMAP_FOREACH(i, globs, iterator) {
1738                 k = process_item(i);
1739                 if (k < 0 && r == 0)
1740                         r = k;
1741         }
1742
1743         HASHMAP_FOREACH(i, items, iterator) {
1744                 k = process_item(i);
1745                 if (k < 0 && r == 0)
1746                         r = k;
1747         }
1748
1749 finish:
1750         while ((i = hashmap_steal_first(items)))
1751                 item_free(i);
1752
1753         while ((i = hashmap_steal_first(globs)))
1754                 item_free(i);
1755
1756         hashmap_free(items);
1757         hashmap_free(globs);
1758
1759         free(arg_include_prefixes);
1760         free(arg_exclude_prefixes);
1761         free(arg_root);
1762
1763         set_free_free(unix_sockets);
1764
1765         mac_selinux_finish();
1766
1767         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1768 }