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