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