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