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