chiark / gitweb /
332ddcea766c7a3b01ef4d178841c8d451c05478
[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 <sys/stat.h>
27 #include <limits.h>
28 #include <dirent.h>
29 #include <grp.h>
30 #include <pwd.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stddef.h>
34 #include <getopt.h>
35 #include <stdbool.h>
36 #include <time.h>
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <glob.h>
40 #include <fnmatch.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                         log_error_errno(errno, "chown(%s) failed: %m", path);
486                         return -errno;
487                 }
488
489         return label_fix(path, false, false);
490 }
491
492 static int get_xattrs_from_arg(Item *i) {
493         char *xattr;
494         const char *p;
495         int r;
496
497         assert(i);
498
499         if (!i->argument) {
500                 log_error("%s: Argument can't be empty!", i->path);
501                 return -EBADMSG;
502         }
503         p = i->argument;
504
505         while ((r = unquote_first_word(&p, &xattr, false)) > 0) {
506                 _cleanup_free_ char *tmp = NULL, *name = NULL, *value = NULL;
507                 r = split_pair(xattr, "=", &name, &value);
508                 if (r < 0) {
509                         log_warning("Illegal xattr found: \"%s\" - ignoring.", xattr);
510                         free(xattr);
511                         continue;
512                 }
513                 free(xattr);
514                 if (streq(name, "") || streq(value, "")) {
515                         log_warning("Malformed xattr found: \"%s=%s\" - ignoring.", name, value);
516                         continue;
517                 }
518                 tmp = unquote(value, "\"");
519                 if (!tmp)
520                         return log_oom();
521                 free(value);
522                 value = cunescape(tmp);
523                 if (!value)
524                         return log_oom();
525                 if (strv_consume_pair(&i->xattrs, name, value) < 0)
526                         return log_oom();
527                 name = value = NULL;
528         }
529
530         return r;
531 }
532
533 static int item_set_xattrs(Item *i, const char *path) {
534         char **name, **value;
535
536         assert(i);
537         assert(path);
538
539         if (strv_isempty(i->xattrs))
540                 return 0;
541
542         STRV_FOREACH_PAIR(name, value, i->xattrs) {
543                 int n;
544                 n = strlen(*value);
545                 if (lsetxattr(path, *name, *value, n, 0) < 0) {
546                         log_error("Setting extended attribute %s=%s on %s failed: %m", *name, *value, path);
547                         return -errno;
548                 }
549         }
550         return 0;
551 }
552
553 static int write_one_file(Item *i, const char *path) {
554         _cleanup_close_ int fd = -1;
555         int flags, r = 0;
556         struct stat st;
557
558         assert(i);
559         assert(path);
560
561         flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND|O_NOFOLLOW :
562                 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
563
564         RUN_WITH_UMASK(0000) {
565                 mac_selinux_create_file_prepare(path, S_IFREG);
566                 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
567                 mac_selinux_create_file_clear();
568         }
569
570         if (fd < 0) {
571                 if (i->type == WRITE_FILE && errno == ENOENT)
572                         return 0;
573
574                 log_error_errno(errno, "Failed to create file %s: %m", path);
575                 return -errno;
576         }
577
578         if (i->argument) {
579                 _cleanup_free_ char *unescaped;
580                 ssize_t n;
581                 size_t l;
582
583                 unescaped = cunescape(i->argument);
584                 if (!unescaped)
585                         return log_oom();
586
587                 l = strlen(unescaped);
588                 n = write(fd, unescaped, l);
589
590                 if (n < 0 || (size_t) n < l) {
591                         log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
592                         return n < 0 ? n : -EIO;
593                 }
594         }
595
596         fd = safe_close(fd);
597
598         if (stat(path, &st) < 0)
599                 return log_error_errno(errno, "stat(%s) failed: %m", path);
600
601         if (!S_ISREG(st.st_mode)) {
602                 log_error("%s is not a file.", path);
603                 return -EEXIST;
604         }
605
606         r = item_set_perms(i, path);
607         if (r < 0)
608                 return r;
609
610         r = item_set_xattrs(i, i->path);
611         if (r < 0)
612                 return r;
613
614         return 0;
615 }
616
617 static int item_set_perms_children(Item *i, const char *path) {
618         _cleanup_closedir_ DIR *d;
619         int r = 0;
620
621         assert(i);
622         assert(path);
623
624         /* This returns the first error we run into, but nevertheless
625          * tries to go on */
626
627         d = opendir(path);
628         if (!d)
629                 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
630
631         for (;;) {
632                 _cleanup_free_ char *p = NULL;
633                 struct dirent *de;
634                 int q;
635
636                 errno = 0;
637                 de = readdir(d);
638                 if (!de) {
639                         if (errno != 0 && r == 0)
640                                 r = -errno;
641
642                         break;
643                 }
644
645                 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
646                         continue;
647
648                 p = strjoin(path, "/", de->d_name, NULL);
649                 if (!p)
650                         return -ENOMEM;
651
652                 q = item_set_perms(i, p);
653                 if (q < 0 && q != -ENOENT && r == 0)
654                         r = q;
655
656                 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
657                         q = item_set_perms_children(i, p);
658                         if (q < 0 && r == 0)
659                                 r = q;
660                 }
661         }
662
663         return r;
664 }
665
666 static int item_set_perms_recursive(Item *i, const char *path) {
667         int r, q;
668
669         assert(i);
670         assert(path);
671
672         r = item_set_perms(i, path);
673         if (r < 0)
674                 return r;
675
676         q = item_set_perms_children(i, path);
677         if (q < 0 && r == 0)
678                 r = q;
679
680         return r;
681 }
682
683 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
684         _cleanup_globfree_ glob_t g = {};
685         int r = 0, k;
686         char **fn;
687
688         errno = 0;
689         k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
690         if (k != 0 && k != GLOB_NOMATCH) {
691                 if (errno == 0)
692                         errno = EIO;
693
694                 log_error_errno(errno, "glob(%s) failed: %m", i->path);
695                 return -errno;
696         }
697
698         STRV_FOREACH(fn, g.gl_pathv) {
699                 k = action(i, *fn);
700                 if (k < 0 && r == 0)
701                         r = k;
702         }
703
704         return r;
705 }
706
707 static int create_item(Item *i) {
708         struct stat st;
709         int r = 0;
710
711         assert(i);
712
713         switch (i->type) {
714
715         case IGNORE_PATH:
716         case IGNORE_DIRECTORY_PATH:
717         case REMOVE_PATH:
718         case RECURSIVE_REMOVE_PATH:
719                 return 0;
720
721         case CREATE_FILE:
722         case TRUNCATE_FILE:
723                 r = write_one_file(i, i->path);
724                 if (r < 0)
725                         return r;
726                 break;
727
728         case COPY_FILES:
729                 r = copy_tree(i->argument, i->path, false);
730                 if (r < 0) {
731                         struct stat a, b;
732
733                         if (r != -EEXIST)
734                                 return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
735
736                         if (stat(i->argument, &a) < 0)
737                                 return log_error_errno(errno, "stat(%s) failed: %m", i->argument);
738
739                         if (stat(i->path, &b) < 0)
740                                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
741
742                         if ((a.st_mode ^ b.st_mode) & S_IFMT) {
743                                 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
744                                 return 0;
745                         }
746                 }
747
748                 r = item_set_perms(i, i->path);
749                 if (r < 0)
750                         return r;
751
752                 break;
753
754         case WRITE_FILE:
755                 r = glob_item(i, write_one_file);
756                 if (r < 0)
757                         return r;
758
759                 break;
760
761         case CREATE_DIRECTORY:
762         case TRUNCATE_DIRECTORY:
763         case CREATE_SUBVOLUME:
764
765                 RUN_WITH_UMASK(0000)
766                         mkdir_parents_label(i->path, 0755);
767
768                 if (i->type == CREATE_SUBVOLUME) {
769                         RUN_WITH_UMASK((~i->mode) & 0777)
770                                 r = btrfs_subvol_make(i->path);
771                 } else
772                         r = 0;
773
774                 if (i->type == CREATE_DIRECTORY || i->type == TRUNCATE_DIRECTORY || r == -ENOTTY) {
775                         RUN_WITH_UMASK(0000)
776                                 r = mkdir_label(i->path, i->mode);
777                 }
778
779                 if (r < 0) {
780                         if (r != -EEXIST)
781                                 return log_error_errno(r, "Failed to create directory or subvolume %s: %m", i->path);
782
783                         if (stat(i->path, &st) < 0)
784                                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
785
786                         if (!S_ISDIR(st.st_mode)) {
787                                 log_debug("%s already exists and is not a directory.", i->path);
788                                 return 0;
789                         }
790                 }
791
792                 r = item_set_perms(i, i->path);
793                 if (r < 0)
794                         return r;
795
796                 r = item_set_xattrs(i, i->path);
797                 if (r < 0)
798                         return r;
799
800                 break;
801
802         case CREATE_FIFO:
803
804                 RUN_WITH_UMASK(0000) {
805                         mac_selinux_create_file_prepare(i->path, S_IFIFO);
806                         r = mkfifo(i->path, i->mode);
807                         mac_selinux_create_file_clear();
808                 }
809
810                 if (r < 0) {
811                         if (errno != EEXIST)
812                                 return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
813
814                         if (stat(i->path, &st) < 0)
815                                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
816
817                         if (!S_ISFIFO(st.st_mode)) {
818
819                                 if (i->force) {
820
821                                         RUN_WITH_UMASK(0000) {
822                                                 mac_selinux_create_file_prepare(i->path, S_IFIFO);
823                                                 r = mkfifo_atomic(i->path, i->mode);
824                                                 mac_selinux_create_file_clear();
825                                         }
826
827                                         if (r < 0)
828                                                 return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
829                                 } else {
830                                         log_debug("%s is not a fifo.", i->path);
831                                         return 0;
832                                 }
833                         }
834                 }
835
836                 r = item_set_perms(i, i->path);
837                 if (r < 0)
838                         return r;
839
840                 r = item_set_xattrs(i, i->path);
841                 if (r < 0)
842                         return r;
843
844                 break;
845
846         case CREATE_SYMLINK:
847
848                 mac_selinux_create_file_prepare(i->path, S_IFLNK);
849                 r = symlink(i->argument, i->path);
850                 mac_selinux_create_file_clear();
851
852                 if (r < 0) {
853                         _cleanup_free_ char *x = NULL;
854
855                         if (errno != EEXIST)
856                                 return log_error_errno(errno, "symlink(%s, %s) failed: %m", i->argument, i->path);
857
858                         r = readlink_malloc(i->path, &x);
859                         if (r < 0 || !streq(i->argument, x)) {
860
861                                 if (i->force) {
862                                         mac_selinux_create_file_prepare(i->path, S_IFLNK);
863                                         r = symlink_atomic(i->argument, i->path);
864                                         mac_selinux_create_file_clear();
865
866                                         if (r < 0)
867                                                 return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
868                                 } else {
869                                         log_debug("%s is not a symlink or does not point to the correct path.", i->path);
870                                         return 0;
871                                 }
872                         }
873                 }
874
875                 r = item_set_xattrs(i, i->path);
876                 if (r < 0)
877                        return r;
878
879                 break;
880
881         case CREATE_BLOCK_DEVICE:
882         case CREATE_CHAR_DEVICE: {
883                 mode_t file_type;
884
885                 if (have_effective_cap(CAP_MKNOD) == 0) {
886                         /* In a container we lack CAP_MKNOD. We
887                         shouldn't attempt to create the device node in
888                         that case to avoid noise, and we don't support
889                         virtualized devices in containers anyway. */
890
891                         log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
892                         return 0;
893                 }
894
895                 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
896
897                 RUN_WITH_UMASK(0000) {
898                         mac_selinux_create_file_prepare(i->path, file_type);
899                         r = mknod(i->path, i->mode | file_type, i->major_minor);
900                         mac_selinux_create_file_clear();
901                 }
902
903                 if (r < 0) {
904                         if (errno == EPERM) {
905                                 log_debug("We lack permissions, possibly because of cgroup configuration; "
906                                           "skipping creation of device node %s.", i->path);
907                                 return 0;
908                         }
909
910                         if (errno != EEXIST)
911                                 return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
912
913                         if (stat(i->path, &st) < 0)
914                                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
915
916                         if ((st.st_mode & S_IFMT) != file_type) {
917
918                                 if (i->force) {
919
920                                         RUN_WITH_UMASK(0000) {
921                                                 mac_selinux_create_file_prepare(i->path, file_type);
922                                                 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
923                                                 mac_selinux_create_file_clear();
924                                         }
925
926                                         if (r < 0)
927                                                 return log_error_errno(r, "Failed to create device node %s: %m", i->path);
928                                 } else {
929                                         log_debug("%s is not a device node.", i->path);
930                                         return 0;
931                                 }
932                         }
933                 }
934
935                 r = item_set_perms(i, i->path);
936                 if (r < 0)
937                         return r;
938
939                 r = item_set_xattrs(i, i->path);
940                 if (r < 0)
941                         return r;
942
943                 break;
944         }
945
946         case ADJUST_MODE:
947         case RELABEL_PATH:
948
949                 r = glob_item(i, item_set_perms);
950                 if (r < 0)
951                         return r;
952                 break;
953
954         case RECURSIVE_RELABEL_PATH:
955
956                 r = glob_item(i, item_set_perms_recursive);
957                 if (r < 0)
958                         return r;
959                 break;
960
961         case SET_XATTR:
962                 r = item_set_xattrs(i, i->path);
963                 if (r < 0)
964                         return r;
965                 break;
966         }
967
968         log_debug("%s created successfully.", i->path);
969
970         return 0;
971 }
972
973 static int remove_item_instance(Item *i, const char *instance) {
974         int r;
975
976         assert(i);
977
978         switch (i->type) {
979
980         case CREATE_FILE:
981         case TRUNCATE_FILE:
982         case CREATE_DIRECTORY:
983         case CREATE_SUBVOLUME:
984         case CREATE_FIFO:
985         case CREATE_SYMLINK:
986         case CREATE_BLOCK_DEVICE:
987         case CREATE_CHAR_DEVICE:
988         case IGNORE_PATH:
989         case IGNORE_DIRECTORY_PATH:
990         case ADJUST_MODE:
991         case RELABEL_PATH:
992         case RECURSIVE_RELABEL_PATH:
993         case WRITE_FILE:
994         case COPY_FILES:
995         case SET_XATTR:
996                 break;
997
998         case REMOVE_PATH:
999                 if (remove(instance) < 0 && errno != ENOENT)
1000                         return log_error_errno(errno, "remove(%s): %m", instance);
1001
1002                 break;
1003
1004         case TRUNCATE_DIRECTORY:
1005         case RECURSIVE_REMOVE_PATH:
1006                 /* FIXME: we probably should use dir_cleanup() here
1007                  * instead of rm_rf() so that 'x' is honoured. */
1008                 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
1009                 if (r < 0 && r != -ENOENT)
1010                         return log_error_errno(r, "rm_rf(%s): %m", instance);
1011
1012                 break;
1013         }
1014
1015         return 0;
1016 }
1017
1018 static int remove_item(Item *i) {
1019         int r = 0;
1020
1021         assert(i);
1022
1023         switch (i->type) {
1024
1025         case CREATE_FILE:
1026         case TRUNCATE_FILE:
1027         case CREATE_DIRECTORY:
1028         case CREATE_SUBVOLUME:
1029         case CREATE_FIFO:
1030         case CREATE_SYMLINK:
1031         case CREATE_CHAR_DEVICE:
1032         case CREATE_BLOCK_DEVICE:
1033         case IGNORE_PATH:
1034         case IGNORE_DIRECTORY_PATH:
1035         case ADJUST_MODE:
1036         case RELABEL_PATH:
1037         case RECURSIVE_RELABEL_PATH:
1038         case WRITE_FILE:
1039         case COPY_FILES:
1040         case SET_XATTR:
1041                 break;
1042
1043         case REMOVE_PATH:
1044         case TRUNCATE_DIRECTORY:
1045         case RECURSIVE_REMOVE_PATH:
1046                 r = glob_item(i, remove_item_instance);
1047                 break;
1048         }
1049
1050         return r;
1051 }
1052
1053 static int clean_item_instance(Item *i, const char* instance) {
1054         _cleanup_closedir_ DIR *d = NULL;
1055         struct stat s, ps;
1056         bool mountpoint;
1057         int r;
1058         usec_t cutoff, n;
1059
1060         assert(i);
1061
1062         if (!i->age_set)
1063                 return 0;
1064
1065         n = now(CLOCK_REALTIME);
1066         if (n < i->age)
1067                 return 0;
1068
1069         cutoff = n - i->age;
1070
1071         d = opendir(instance);
1072         if (!d) {
1073                 if (errno == ENOENT || errno == ENOTDIR)
1074                         return 0;
1075
1076                 log_error_errno(errno, "Failed to open directory %s: %m", i->path);
1077                 return -errno;
1078         }
1079
1080         if (fstat(dirfd(d), &s) < 0)
1081                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1082
1083         if (!S_ISDIR(s.st_mode)) {
1084                 log_error("%s is not a directory.", i->path);
1085                 return -ENOTDIR;
1086         }
1087
1088         if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
1089                 return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
1090
1091         mountpoint = s.st_dev != ps.st_dev ||
1092                      (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1093
1094         r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1095                         MAX_DEPTH, i->keep_first_level);
1096         return r;
1097 }
1098
1099 static int clean_item(Item *i) {
1100         int r = 0;
1101
1102         assert(i);
1103
1104         switch (i->type) {
1105         case CREATE_DIRECTORY:
1106         case CREATE_SUBVOLUME:
1107         case TRUNCATE_DIRECTORY:
1108         case IGNORE_PATH:
1109         case COPY_FILES:
1110                 clean_item_instance(i, i->path);
1111                 break;
1112         case IGNORE_DIRECTORY_PATH:
1113                 r = glob_item(i, clean_item_instance);
1114                 break;
1115         default:
1116                 break;
1117         }
1118
1119         return r;
1120 }
1121
1122 static int process_item(Item *i) {
1123         int r, q, p, t = 0;
1124         _cleanup_free_ char *prefix = NULL;
1125
1126         assert(i);
1127
1128         if (i->done)
1129                 return 0;
1130
1131         i->done = true;
1132
1133         prefix = malloc(strlen(i->path) + 1);
1134         if (!prefix)
1135                 return log_oom();
1136
1137         PATH_FOREACH_PREFIX(prefix, i->path) {
1138                 Item *j;
1139
1140                 j = hashmap_get(items, prefix);
1141                 if (j) {
1142                         int s;
1143
1144                         s = process_item(j);
1145                         if (s < 0 && t == 0)
1146                                 t = s;
1147                 }
1148         }
1149
1150         r = arg_create ? create_item(i) : 0;
1151         q = arg_remove ? remove_item(i) : 0;
1152         p = arg_clean ? clean_item(i) : 0;
1153
1154         return t < 0 ? t :
1155                 r < 0 ? r :
1156                 q < 0 ? q :
1157                 p;
1158 }
1159
1160 static void item_free(Item *i) {
1161
1162         if (!i)
1163                 return;
1164
1165         free(i->path);
1166         free(i->argument);
1167         strv_free(i->xattrs);
1168         free(i);
1169 }
1170
1171 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1172
1173 static bool item_equal(Item *a, Item *b) {
1174         assert(a);
1175         assert(b);
1176
1177         if (!streq_ptr(a->path, b->path))
1178                 return false;
1179
1180         if (a->type != b->type)
1181                 return false;
1182
1183         if (a->uid_set != b->uid_set ||
1184             (a->uid_set && a->uid != b->uid))
1185             return false;
1186
1187         if (a->gid_set != b->gid_set ||
1188             (a->gid_set && a->gid != b->gid))
1189             return false;
1190
1191         if (a->mode_set != b->mode_set ||
1192             (a->mode_set && a->mode != b->mode))
1193             return false;
1194
1195         if (a->age_set != b->age_set ||
1196             (a->age_set && a->age != b->age))
1197             return false;
1198
1199         if ((a->type == CREATE_FILE ||
1200              a->type == TRUNCATE_FILE ||
1201              a->type == WRITE_FILE ||
1202              a->type == CREATE_SYMLINK ||
1203              a->type == COPY_FILES) &&
1204             !streq_ptr(a->argument, b->argument))
1205                 return false;
1206
1207         if ((a->type == CREATE_CHAR_DEVICE ||
1208              a->type == CREATE_BLOCK_DEVICE) &&
1209             a->major_minor != b->major_minor)
1210                 return false;
1211
1212         return true;
1213 }
1214
1215 static bool should_include_path(const char *path) {
1216         char **prefix;
1217
1218         STRV_FOREACH(prefix, arg_exclude_prefixes)
1219                 if (path_startswith(path, *prefix))
1220                         return false;
1221
1222         STRV_FOREACH(prefix, arg_include_prefixes)
1223                 if (path_startswith(path, *prefix))
1224                         return true;
1225
1226         /* no matches, so we should include this path only if we
1227          * have no whitelist at all */
1228         return strv_length(arg_include_prefixes) == 0;
1229 }
1230
1231 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1232
1233         static const Specifier specifier_table[] = {
1234                 { 'm', specifier_machine_id, NULL },
1235                 { 'b', specifier_boot_id, NULL },
1236                 { 'H', specifier_host_name, NULL },
1237                 { 'v', specifier_kernel_release, NULL },
1238                 {}
1239         };
1240
1241         _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1242         _cleanup_(item_freep) Item *i = NULL;
1243         Item *existing;
1244         char type;
1245         Hashmap *h;
1246         int r, n = -1;
1247
1248         assert(fname);
1249         assert(line >= 1);
1250         assert(buffer);
1251
1252         r = sscanf(buffer,
1253                    "%ms %ms %ms %ms %ms %ms %n",
1254                    &action,
1255                    &path,
1256                    &mode,
1257                    &user,
1258                    &group,
1259                    &age,
1260                    &n);
1261         if (r < 2) {
1262                 log_error("[%s:%u] Syntax error.", fname, line);
1263                 return -EIO;
1264         }
1265
1266         if (isempty(action)) {
1267                 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1268                 return -EINVAL;
1269         }
1270
1271         if (strlen(action) > 1 && !in_charset(action+1, "!+")) {
1272                 log_error("[%s:%u] Unknown modifiers in command '%s'", fname, line, action);
1273                 return -EINVAL;
1274         }
1275
1276         if (strchr(action+1, '!') && !arg_boot)
1277                 return 0;
1278
1279         type = action[0];
1280
1281         i = new0(Item, 1);
1282         if (!i)
1283                 return log_oom();
1284
1285         i->force = !!strchr(action+1, '+');
1286
1287         r = specifier_printf(path, specifier_table, NULL, &i->path);
1288         if (r < 0) {
1289                 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1290                 return r;
1291         }
1292
1293         if (n >= 0)  {
1294                 n += strspn(buffer+n, WHITESPACE);
1295                 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1296                         i->argument = unquote(buffer+n, "\"");
1297                         if (!i->argument)
1298                                 return log_oom();
1299                 }
1300         }
1301
1302         switch (type) {
1303
1304         case CREATE_FILE:
1305         case TRUNCATE_FILE:
1306         case CREATE_DIRECTORY:
1307         case CREATE_SUBVOLUME:
1308         case TRUNCATE_DIRECTORY:
1309         case CREATE_FIFO:
1310         case IGNORE_PATH:
1311         case IGNORE_DIRECTORY_PATH:
1312         case REMOVE_PATH:
1313         case RECURSIVE_REMOVE_PATH:
1314         case ADJUST_MODE:
1315         case RELABEL_PATH:
1316         case RECURSIVE_RELABEL_PATH:
1317                 break;
1318
1319         case CREATE_SYMLINK:
1320                 if (!i->argument) {
1321                         i->argument = strappend("/usr/share/factory", i->path);
1322                         if (!i->argument)
1323                                 return log_oom();
1324                 }
1325                 break;
1326
1327         case WRITE_FILE:
1328                 if (!i->argument) {
1329                         log_error("[%s:%u] Write file requires argument.", fname, line);
1330                         return -EBADMSG;
1331                 }
1332                 break;
1333
1334         case COPY_FILES:
1335                 if (!i->argument) {
1336                         i->argument = strappend("/usr/share/factory", i->path);
1337                         if (!i->argument)
1338                                 return log_oom();
1339                 }
1340
1341                 if (!path_is_absolute(i->argument)) {
1342                         log_error("[%s:%u] Source path is not absolute.", fname, line);
1343                         return -EBADMSG;
1344                 }
1345
1346                 path_kill_slashes(i->argument);
1347                 break;
1348
1349         case CREATE_CHAR_DEVICE:
1350         case CREATE_BLOCK_DEVICE: {
1351                 unsigned major, minor;
1352
1353                 if (!i->argument) {
1354                         log_error("[%s:%u] Device file requires argument.", fname, line);
1355                         return -EBADMSG;
1356                 }
1357
1358                 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1359                         log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1360                         return -EBADMSG;
1361                 }
1362
1363                 i->major_minor = makedev(major, minor);
1364                 break;
1365         }
1366
1367         case SET_XATTR:
1368                 if (!i->argument) {
1369                         log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1370                         return -EBADMSG;
1371                 }
1372                 r = get_xattrs_from_arg(i);
1373                 if (r < 0)
1374                         return r;
1375                 break;
1376
1377         default:
1378                 log_error("[%s:%u] Unknown command type '%c'.", fname, line, type);
1379                 return -EBADMSG;
1380         }
1381
1382         i->type = type;
1383
1384         if (!path_is_absolute(i->path)) {
1385                 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1386                 return -EBADMSG;
1387         }
1388
1389         path_kill_slashes(i->path);
1390
1391         if (!should_include_path(i->path))
1392                 return 0;
1393
1394         if (arg_root) {
1395                 char *p;
1396
1397                 p = strappend(arg_root, i->path);
1398                 if (!p)
1399                         return log_oom();
1400
1401                 free(i->path);
1402                 i->path = p;
1403         }
1404
1405         if (user && !streq(user, "-")) {
1406                 const char *u = user;
1407
1408                 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1409                 if (r < 0) {
1410                         log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1411                         return r;
1412                 }
1413
1414                 i->uid_set = true;
1415         }
1416
1417         if (group && !streq(group, "-")) {
1418                 const char *g = group;
1419
1420                 r = get_group_creds(&g, &i->gid);
1421                 if (r < 0) {
1422                         log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1423                         return r;
1424                 }
1425
1426                 i->gid_set = true;
1427         }
1428
1429         if (mode && !streq(mode, "-")) {
1430                 const char *mm = mode;
1431                 unsigned m;
1432
1433                 if (*mm == '~') {
1434                         i->mask_perms = true;
1435                         mm++;
1436                 }
1437
1438                 if (sscanf(mm, "%o", &m) != 1) {
1439                         log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1440                         return -ENOENT;
1441                 }
1442
1443                 i->mode = m;
1444                 i->mode_set = true;
1445         } else
1446                 i->mode =
1447                         i->type == CREATE_DIRECTORY ||
1448                         i->type == CREATE_SUBVOLUME ||
1449                         i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1450
1451         if (age && !streq(age, "-")) {
1452                 const char *a = age;
1453
1454                 if (*a == '~') {
1455                         i->keep_first_level = true;
1456                         a++;
1457                 }
1458
1459                 if (parse_sec(a, &i->age) < 0) {
1460                         log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1461                         return -EBADMSG;
1462                 }
1463
1464                 i->age_set = true;
1465         }
1466
1467         h = needs_glob(i->type) ? globs : items;
1468
1469         existing = hashmap_get(h, i->path);
1470         if (existing) {
1471                 if (i->type == SET_XATTR) {
1472                         r = strv_extend_strv(&existing->xattrs, i->xattrs);
1473                         if (r < 0)
1474                                 return log_oom();
1475                         return 0;
1476                 } else if (existing->type == SET_XATTR) {
1477                         r = strv_extend_strv(&i->xattrs, existing->xattrs);
1478                         if (r < 0)
1479                                 return log_oom();
1480                         r = hashmap_replace(h, i->path, i);
1481                         if (r < 0) {
1482                                 log_error("Failed to replace item for %s.", i->path);
1483                                 return r;
1484                         }
1485                         item_free(existing);
1486                 } else {
1487                         /* Two identical items are fine */
1488                         if (!item_equal(existing, i))
1489                                 log_warning("Two or more conflicting lines for %s configured, ignoring.", 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 }