chiark / gitweb /
tmpfiles: support passing --prefix multiple times
[elogind.git] / src / tmpfiles / tmpfiles.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering, Kay Sievers
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 #include <limits.h>
28 #include <dirent.h>
29 #include <grp.h>
30 #include <pwd.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stddef.h>
34 #include <getopt.h>
35 #include <stdbool.h>
36 #include <time.h>
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <glob.h>
40 #include <fnmatch.h>
41 #include <sys/capability.h>
42
43 #include "log.h"
44 #include "util.h"
45 #include "macro.h"
46 #include "missing.h"
47 #include "mkdir.h"
48 #include "path-util.h"
49 #include "strv.h"
50 #include "label.h"
51 #include "set.h"
52 #include "conf-files.h"
53 #include "capability.h"
54
55 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
56  * them in the file system. This is intended to be used to create
57  * properly owned directories beneath /tmp, /var/tmp, /run, which are
58  * volatile and hence need to be recreated on bootup. */
59
60 typedef enum ItemType {
61         /* These ones take file names */
62         CREATE_FILE = 'f',
63         TRUNCATE_FILE = 'F',
64         WRITE_FILE = 'w',
65         CREATE_DIRECTORY = 'd',
66         TRUNCATE_DIRECTORY = 'D',
67         CREATE_FIFO = 'p',
68         CREATE_SYMLINK = 'L',
69         CREATE_CHAR_DEVICE = 'c',
70         CREATE_BLOCK_DEVICE = 'b',
71
72         /* These ones take globs */
73         IGNORE_PATH = 'x',
74         IGNORE_DIRECTORY_PATH = 'X',
75         REMOVE_PATH = 'r',
76         RECURSIVE_REMOVE_PATH = 'R',
77         RELABEL_PATH = 'z',
78         RECURSIVE_RELABEL_PATH = 'Z'
79 } ItemType;
80
81 typedef struct Item {
82         ItemType type;
83
84         char *path;
85         char *argument;
86         uid_t uid;
87         gid_t gid;
88         mode_t mode;
89         usec_t age;
90
91         dev_t major_minor;
92
93         bool uid_set:1;
94         bool gid_set:1;
95         bool mode_set:1;
96         bool age_set:1;
97
98         bool keep_first_level:1;
99 } Item;
100
101 static Hashmap *items = NULL, *globs = NULL;
102 static Set *unix_sockets = NULL;
103
104 static bool arg_create = false;
105 static bool arg_clean = false;
106 static bool arg_remove = false;
107
108 static char **include_prefixes = NULL;
109
110 static const char conf_file_dirs[] =
111         "/etc/tmpfiles.d\0"
112         "/run/tmpfiles.d\0"
113         "/usr/local/lib/tmpfiles.d\0"
114         "/usr/lib/tmpfiles.d\0"
115 #ifdef HAVE_SPLIT_USR
116         "/lib/tmpfiles.d\0"
117 #endif
118         ;
119
120 #define MAX_DEPTH 256
121
122 static bool needs_glob(ItemType t) {
123         return t == IGNORE_PATH || t == IGNORE_DIRECTORY_PATH || t == REMOVE_PATH || t == RECURSIVE_REMOVE_PATH || t == RELABEL_PATH || t == RECURSIVE_RELABEL_PATH;
124 }
125
126 static struct Item* find_glob(Hashmap *h, const char *match) {
127         Item *j;
128         Iterator i;
129
130         HASHMAP_FOREACH(j, h, i)
131                 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
132                         return j;
133
134         return NULL;
135 }
136
137 static void load_unix_sockets(void) {
138         _cleanup_fclose_ FILE *f = NULL;
139         char line[LINE_MAX];
140
141         if (unix_sockets)
142                 return;
143
144         /* We maintain a cache of the sockets we found in
145          * /proc/net/unix to speed things up a little. */
146
147         unix_sockets = set_new(string_hash_func, string_compare_func);
148         if (!unix_sockets)
149                 return;
150
151         f = fopen("/proc/net/unix", "re");
152         if (!f)
153                 return;
154
155         /* Skip header */
156         if (!fgets(line, sizeof(line), f))
157                 goto fail;
158
159         for (;;) {
160                 char *p, *s;
161                 int k;
162
163                 if (!fgets(line, sizeof(line), f))
164                         break;
165
166                 truncate_nl(line);
167
168                 p = strchr(line, ':');
169                 if (!p)
170                         continue;
171
172                 if (strlen(p) < 37)
173                         continue;
174
175                 p += 37;
176                 p += strspn(p, WHITESPACE);
177                 p += strcspn(p, WHITESPACE); /* skip one more word */
178                 p += strspn(p, WHITESPACE);
179
180                 if (*p != '/')
181                         continue;
182
183                 s = strdup(p);
184                 if (!s)
185                         goto fail;
186
187                 path_kill_slashes(s);
188
189                 k = set_consume(unix_sockets, s);
190                 if (k < 0 && k != -EEXIST)
191                         goto fail;
192         }
193
194         return;
195
196 fail:
197         set_free_free(unix_sockets);
198         unix_sockets = NULL;
199 }
200
201 static bool unix_socket_alive(const char *fn) {
202         assert(fn);
203
204         load_unix_sockets();
205
206         if (unix_sockets)
207                 return !!set_get(unix_sockets, (char*) fn);
208
209         /* We don't know, so assume yes */
210         return true;
211 }
212
213 static int dir_is_mount_point(DIR *d, const char *subdir) {
214         struct file_handle *h;
215         int mount_id_parent, mount_id;
216         int r_p, r;
217
218         h = alloca(MAX_HANDLE_SZ);
219
220         h->handle_bytes = MAX_HANDLE_SZ;
221         r_p = name_to_handle_at(dirfd(d), ".", h, &mount_id_parent, 0);
222         if (r_p < 0)
223                 r_p = -errno;
224
225         h->handle_bytes = MAX_HANDLE_SZ;
226         r = name_to_handle_at(dirfd(d), subdir, h, &mount_id, 0);
227         if (r < 0)
228                 r = -errno;
229
230         /* got no handle; make no assumptions, return error */
231         if (r_p < 0 && r < 0)
232                 return r_p;
233
234         /* got both handles; if they differ, it is a mount point */
235         if (r_p >= 0 && r >= 0)
236                 return mount_id_parent != mount_id;
237
238         /* got only one handle; assume different mount points if one
239          * of both queries was not supported by the filesystem */
240         if (r_p == -ENOSYS || r_p == -ENOTSUP || r == -ENOSYS || r == -ENOTSUP)
241                 return true;
242
243         /* return error */
244         if (r_p < 0)
245                 return r_p;
246         return r;
247 }
248
249 static int dir_cleanup(
250                 Item *i,
251                 const char *p,
252                 DIR *d,
253                 const struct stat *ds,
254                 usec_t cutoff,
255                 dev_t rootdev,
256                 bool mountpoint,
257                 int maxdepth,
258                 bool keep_this_level)
259 {
260         struct dirent *dent;
261         struct timespec times[2];
262         bool deleted = false;
263         int r = 0;
264
265         while ((dent = readdir(d))) {
266                 struct stat s;
267                 usec_t age;
268                 _cleanup_free_ char *sub_path = NULL;
269
270                 if (streq(dent->d_name, ".") ||
271                     streq(dent->d_name, ".."))
272                         continue;
273
274                 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
275
276                         if (errno != ENOENT) {
277                                 log_error("stat(%s/%s) failed: %m", p, dent->d_name);
278                                 r = -errno;
279                         }
280
281                         continue;
282                 }
283
284                 /* Stay on the same filesystem */
285                 if (s.st_dev != rootdev)
286                         continue;
287
288                 /* Try to detect bind mounts of the same filesystem instance; they
289                  * do not differ in device major/minors. This type of query is not
290                  * supported on all kernels or filesystem types though. */
291                 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
292                         continue;
293
294                 /* Do not delete read-only files owned by root */
295                 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
296                         continue;
297
298                 if (asprintf(&sub_path, "%s/%s", p, dent->d_name) < 0) {
299                         r = log_oom();
300                         goto finish;
301                 }
302
303                 /* Is there an item configured for this path? */
304                 if (hashmap_get(items, sub_path))
305                         continue;
306
307                 if (find_glob(globs, sub_path))
308                         continue;
309
310                 if (S_ISDIR(s.st_mode)) {
311
312                         if (mountpoint &&
313                             streq(dent->d_name, "lost+found") &&
314                             s.st_uid == 0)
315                                 continue;
316
317                         if (maxdepth <= 0)
318                                 log_warning("Reached max depth on %s.", sub_path);
319                         else {
320                                 _cleanup_closedir_ DIR *sub_dir;
321                                 int q;
322
323                                 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
324                                 if (sub_dir == NULL) {
325                                         if (errno != ENOENT) {
326                                                 log_error("opendir(%s/%s) failed: %m", p, dent->d_name);
327                                                 r = -errno;
328                                         }
329
330                                         continue;
331                                 }
332
333                                 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
334
335                                 if (q < 0)
336                                         r = q;
337                         }
338
339                         /* Note: if you are wondering why we don't
340                          * support the sticky bit for excluding
341                          * directories from cleaning like we do it for
342                          * other file system objects: well, the sticky
343                          * bit already has a meaning for directories,
344                          * so we don't want to overload that. */
345
346                         if (keep_this_level)
347                                 continue;
348
349                         /* Ignore ctime, we change it when deleting */
350                         age = MAX(timespec_load(&s.st_mtim),
351                                   timespec_load(&s.st_atim));
352                         if (age >= cutoff)
353                                 continue;
354
355                         if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
356                                 log_debug("rmdir '%s'\n", sub_path);
357
358                                 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
359                                         if (errno != ENOENT && errno != ENOTEMPTY) {
360                                                 log_error("rmdir(%s): %m", sub_path);
361                                                 r = -errno;
362                                         }
363                                 }
364                         }
365
366                 } else {
367                         /* Skip files for which the sticky bit is
368                          * set. These are semantics we define, and are
369                          * unknown elsewhere. See XDG_RUNTIME_DIR
370                          * specification for details. */
371                         if (s.st_mode & S_ISVTX)
372                                 continue;
373
374                         if (mountpoint && S_ISREG(s.st_mode)) {
375                                 if (streq(dent->d_name, ".journal") &&
376                                     s.st_uid == 0)
377                                         continue;
378
379                                 if (streq(dent->d_name, "aquota.user") ||
380                                     streq(dent->d_name, "aquota.group"))
381                                         continue;
382                         }
383
384                         /* Ignore sockets that are listed in /proc/net/unix */
385                         if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
386                                 continue;
387
388                         /* Ignore device nodes */
389                         if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
390                                 continue;
391
392                         /* Keep files on this level around if this is
393                          * requested */
394                         if (keep_this_level)
395                                 continue;
396
397                         age = MAX3(timespec_load(&s.st_mtim),
398                                    timespec_load(&s.st_atim),
399                                    timespec_load(&s.st_ctim));
400
401                         if (age >= cutoff)
402                                 continue;
403
404                         log_debug("unlink '%s'\n", sub_path);
405
406                         if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
407                                 if (errno != ENOENT) {
408                                         log_error("unlink(%s): %m", sub_path);
409                                         r = -errno;
410                                 }
411                         }
412
413                         deleted = true;
414                 }
415         }
416
417 finish:
418         if (deleted) {
419                 /* Restore original directory timestamps */
420                 times[0] = ds->st_atim;
421                 times[1] = ds->st_mtim;
422
423                 if (futimens(dirfd(d), times) < 0)
424                         log_error("utimensat(%s): %m", p);
425         }
426
427         return r;
428 }
429
430 static int item_set_perms(Item *i, const char *path) {
431         /* not using i->path directly because it may be a glob */
432         if (i->mode_set)
433                 if (chmod(path, i->mode) < 0) {
434                         log_error("chmod(%s) failed: %m", path);
435                         return -errno;
436                 }
437
438         if (i->uid_set || i->gid_set)
439                 if (chown(path,
440                           i->uid_set ? i->uid : (uid_t) -1,
441                           i->gid_set ? i->gid : (gid_t) -1) < 0) {
442
443                         log_error("chown(%s) failed: %m", path);
444                         return -errno;
445                 }
446
447         return label_fix(path, false, false);
448 }
449
450 static int write_one_file(Item *i, const char *path) {
451         int r, e, fd, flags;
452         struct stat st;
453
454         flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
455                 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;
456
457         RUN_WITH_UMASK(0) {
458                 label_context_set(path, S_IFREG);
459                 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
460                 e = errno;
461                 label_context_clear();
462                 errno = e;
463         }
464
465         if (fd < 0) {
466                 if (i->type == WRITE_FILE && errno == ENOENT)
467                         return 0;
468
469                 log_error("Failed to create file %s: %m", path);
470                 return -errno;
471         }
472
473         if (i->argument) {
474                 ssize_t n;
475                 size_t l;
476                 _cleanup_free_ char *unescaped;
477
478                 unescaped = cunescape(i->argument);
479                 if (unescaped == NULL) {
480                         close_nointr_nofail(fd);
481                         return log_oom();
482                 }
483
484                 l = strlen(unescaped);
485                 n = write(fd, unescaped, l);
486
487                 if (n < 0 || (size_t) n < l) {
488                         log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
489                         close_nointr_nofail(fd);
490                         return n < 0 ? n : -EIO;
491                 }
492         }
493
494         close_nointr_nofail(fd);
495
496         if (stat(path, &st) < 0) {
497                 log_error("stat(%s) failed: %m", path);
498                 return -errno;
499         }
500
501         if (!S_ISREG(st.st_mode)) {
502                 log_error("%s is not a file.", path);
503                 return -EEXIST;
504         }
505
506         r = item_set_perms(i, path);
507         if (r < 0)
508                 return r;
509
510         return 0;
511 }
512
513 static int recursive_relabel_children(Item *i, const char *path) {
514         _cleanup_closedir_ DIR *d;
515         int ret = 0;
516
517         /* This returns the first error we run into, but nevertheless
518          * tries to go on */
519
520         d = opendir(path);
521         if (!d)
522                 return errno == ENOENT ? 0 : -errno;
523
524         for (;;) {
525                 struct dirent *de;
526                 union dirent_storage buf;
527                 bool is_dir;
528                 int r;
529                 _cleanup_free_ char *entry_path = NULL;
530
531                 r = readdir_r(d, &buf.de, &de);
532                 if (r != 0) {
533                         if (ret == 0)
534                                 ret = -r;
535                         break;
536                 }
537
538                 if (!de)
539                         break;
540
541                 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
542                         continue;
543
544                 if (asprintf(&entry_path, "%s/%s", path, de->d_name) < 0) {
545                         if (ret == 0)
546                                 ret = -ENOMEM;
547                         continue;
548                 }
549
550                 if (de->d_type == DT_UNKNOWN) {
551                         struct stat st;
552
553                         if (lstat(entry_path, &st) < 0) {
554                                 if (ret == 0 && errno != ENOENT)
555                                         ret = -errno;
556                                 continue;
557                         }
558
559                         is_dir = S_ISDIR(st.st_mode);
560
561                 } else
562                         is_dir = de->d_type == DT_DIR;
563
564                 r = item_set_perms(i, entry_path);
565                 if (r < 0) {
566                         if (ret == 0 && r != -ENOENT)
567                                 ret = r;
568                         continue;
569                 }
570
571                 if (is_dir) {
572                         r = recursive_relabel_children(i, entry_path);
573                         if (r < 0 && ret == 0)
574                                 ret = r;
575                 }
576         }
577
578         return ret;
579 }
580
581 static int recursive_relabel(Item *i, const char *path) {
582         int r;
583         struct stat st;
584
585         r = item_set_perms(i, path);
586         if (r < 0)
587                 return r;
588
589         if (lstat(path, &st) < 0)
590                 return -errno;
591
592         if (S_ISDIR(st.st_mode))
593                 r = recursive_relabel_children(i, path);
594
595         return r;
596 }
597
598 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
599         int r = 0, k;
600         _cleanup_globfree_ glob_t g = {};
601         char **fn;
602
603         errno = 0;
604         k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
605         if (k != 0)
606                 if (k != GLOB_NOMATCH) {
607                         if (errno > 0)
608                                 errno = EIO;
609
610                         log_error("glob(%s) failed: %m", i->path);
611                         return -errno;
612                 }
613
614         STRV_FOREACH(fn, g.gl_pathv) {
615                 k = action(i, *fn);
616                 if (k < 0)
617                         r = k;
618         }
619
620         return r;
621 }
622
623 static int create_item(Item *i) {
624         int r, e;
625         struct stat st;
626
627         assert(i);
628
629         switch (i->type) {
630
631         case IGNORE_PATH:
632         case IGNORE_DIRECTORY_PATH:
633         case REMOVE_PATH:
634         case RECURSIVE_REMOVE_PATH:
635                 return 0;
636
637         case CREATE_FILE:
638         case TRUNCATE_FILE:
639                 r = write_one_file(i, i->path);
640                 if (r < 0)
641                         return r;
642                 break;
643         case WRITE_FILE:
644                 r = glob_item(i, write_one_file);
645                 if (r < 0)
646                         return r;
647
648                 break;
649
650         case TRUNCATE_DIRECTORY:
651         case CREATE_DIRECTORY:
652
653                 RUN_WITH_UMASK(0000) {
654                         mkdir_parents_label(i->path, 0755);
655                         r = mkdir(i->path, i->mode);
656                 }
657
658                 if (r < 0 && errno != EEXIST) {
659                         log_error("Failed to create directory %s: %m", i->path);
660                         return -errno;
661                 }
662
663                 if (stat(i->path, &st) < 0) {
664                         log_error("stat(%s) failed: %m", i->path);
665                         return -errno;
666                 }
667
668                 if (!S_ISDIR(st.st_mode)) {
669                         log_error("%s is not a directory.", i->path);
670                         return -EEXIST;
671                 }
672
673                 r = item_set_perms(i, i->path);
674                 if (r < 0)
675                         return r;
676
677                 break;
678
679         case CREATE_FIFO:
680
681                 RUN_WITH_UMASK(0000) {
682                         r = mkfifo(i->path, i->mode);
683                 }
684
685                 if (r < 0 && errno != EEXIST) {
686                         log_error("Failed to create fifo %s: %m", i->path);
687                         return -errno;
688                 }
689
690                 if (stat(i->path, &st) < 0) {
691                         log_error("stat(%s) failed: %m", i->path);
692                         return -errno;
693                 }
694
695                 if (!S_ISFIFO(st.st_mode)) {
696                         log_error("%s is not a fifo.", i->path);
697                         return -EEXIST;
698                 }
699
700                 r = item_set_perms(i, i->path);
701                 if (r < 0)
702                         return r;
703
704                 break;
705
706         case CREATE_SYMLINK: {
707                 char *x;
708
709                 label_context_set(i->path, S_IFLNK);
710                 r = symlink(i->argument, i->path);
711                 e = errno;
712                 label_context_clear();
713                 errno = e;
714
715                 if (r < 0 && errno != EEXIST) {
716                         log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
717                         return -errno;
718                 }
719
720                 r = readlink_malloc(i->path, &x);
721                 if (r < 0) {
722                         log_error("readlink(%s) failed: %s", i->path, strerror(-r));
723                         return -errno;
724                 }
725
726                 if (!streq(i->argument, x)) {
727                         free(x);
728                         log_error("%s is not the right symlinks.", i->path);
729                         return -EEXIST;
730                 }
731
732                 free(x);
733                 break;
734         }
735
736         case CREATE_BLOCK_DEVICE:
737         case CREATE_CHAR_DEVICE: {
738                 mode_t file_type;
739
740                 if (have_effective_cap(CAP_MKNOD) == 0) {
741                         /* In a container we lack CAP_MKNOD. We
742                         shouldn't attempt to create the device node in
743                         that case to avoid noise, and we don't support
744                         virtualized devices in containers anyway. */
745
746                         log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
747                         return 0;
748                 }
749
750                 file_type = (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);
751
752                 RUN_WITH_UMASK(0000) {
753                         label_context_set(i->path, file_type);
754                         r = mknod(i->path, i->mode | file_type, i->major_minor);
755                         e = errno;
756                         label_context_clear();
757                         errno = e;
758                 }
759
760                 if (r < 0 && errno != EEXIST) {
761                         log_error("Failed to create device node %s: %m", i->path);
762                         return -errno;
763                 }
764
765                 if (stat(i->path, &st) < 0) {
766                         log_error("stat(%s) failed: %m", i->path);
767                         return -errno;
768                 }
769
770                 if ((st.st_mode & S_IFMT) != file_type) {
771                         log_error("%s is not a device node.", i->path);
772                         return -EEXIST;
773                 }
774
775                 r = item_set_perms(i, i->path);
776                 if (r < 0)
777                         return r;
778
779                 break;
780         }
781
782         case RELABEL_PATH:
783
784                 r = glob_item(i, item_set_perms);
785                 if (r < 0)
786                         return r;
787                 break;
788
789         case RECURSIVE_RELABEL_PATH:
790
791                 r = glob_item(i, recursive_relabel);
792                 if (r < 0)
793                         return r;
794         }
795
796         log_debug("%s created successfully.", i->path);
797
798         return 0;
799 }
800
801 static int remove_item_instance(Item *i, const char *instance) {
802         int r;
803
804         assert(i);
805
806         switch (i->type) {
807
808         case CREATE_FILE:
809         case TRUNCATE_FILE:
810         case CREATE_DIRECTORY:
811         case CREATE_FIFO:
812         case CREATE_SYMLINK:
813         case CREATE_BLOCK_DEVICE:
814         case CREATE_CHAR_DEVICE:
815         case IGNORE_PATH:
816         case IGNORE_DIRECTORY_PATH:
817         case RELABEL_PATH:
818         case RECURSIVE_RELABEL_PATH:
819         case WRITE_FILE:
820                 break;
821
822         case REMOVE_PATH:
823                 if (remove(instance) < 0 && errno != ENOENT) {
824                         log_error("remove(%s): %m", instance);
825                         return -errno;
826                 }
827
828                 break;
829
830         case TRUNCATE_DIRECTORY:
831         case RECURSIVE_REMOVE_PATH:
832                 /* FIXME: we probably should use dir_cleanup() here
833                  * instead of rm_rf() so that 'x' is honoured. */
834                 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
835                 if (r < 0 && r != -ENOENT) {
836                         log_error("rm_rf(%s): %s", instance, strerror(-r));
837                         return r;
838                 }
839
840                 break;
841         }
842
843         return 0;
844 }
845
846 static int remove_item(Item *i) {
847         int r = 0;
848
849         assert(i);
850
851         switch (i->type) {
852
853         case CREATE_FILE:
854         case TRUNCATE_FILE:
855         case CREATE_DIRECTORY:
856         case CREATE_FIFO:
857         case CREATE_SYMLINK:
858         case CREATE_CHAR_DEVICE:
859         case CREATE_BLOCK_DEVICE:
860         case IGNORE_PATH:
861         case IGNORE_DIRECTORY_PATH:
862         case RELABEL_PATH:
863         case RECURSIVE_RELABEL_PATH:
864         case WRITE_FILE:
865                 break;
866
867         case REMOVE_PATH:
868         case TRUNCATE_DIRECTORY:
869         case RECURSIVE_REMOVE_PATH:
870                 r = glob_item(i, remove_item_instance);
871                 break;
872         }
873
874         return r;
875 }
876
877 static int clean_item_instance(Item *i, const char* instance) {
878         _cleanup_closedir_ DIR *d = NULL;
879         struct stat s, ps;
880         bool mountpoint;
881         int r;
882         usec_t cutoff, n;
883
884         assert(i);
885
886         if (!i->age_set)
887                 return 0;
888
889         n = now(CLOCK_REALTIME);
890         if (n < i->age)
891                 return 0;
892
893         cutoff = n - i->age;
894
895         d = opendir(instance);
896         if (!d) {
897                 if (errno == ENOENT || errno == ENOTDIR)
898                         return 0;
899
900                 log_error("Failed to open directory %s: %m", i->path);
901                 return -errno;
902         }
903
904         if (fstat(dirfd(d), &s) < 0) {
905                 log_error("stat(%s) failed: %m", i->path);
906                 return -errno;
907         }
908
909         if (!S_ISDIR(s.st_mode)) {
910                 log_error("%s is not a directory.", i->path);
911                 return -ENOTDIR;
912         }
913
914         if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) {
915                 log_error("stat(%s/..) failed: %m", i->path);
916                 return -errno;
917         }
918
919         mountpoint = s.st_dev != ps.st_dev ||
920                      (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
921
922         r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
923                         MAX_DEPTH, i->keep_first_level);
924         return r;
925 }
926
927 static int clean_item(Item *i) {
928         int r = 0;
929
930         assert(i);
931
932         switch (i->type) {
933         case CREATE_DIRECTORY:
934         case TRUNCATE_DIRECTORY:
935         case IGNORE_PATH:
936                 clean_item_instance(i, i->path);
937                 break;
938         case IGNORE_DIRECTORY_PATH:
939                 r = glob_item(i, clean_item_instance);
940                 break;
941         default:
942                 break;
943         }
944
945         return r;
946 }
947
948 static int process_item(Item *i) {
949         int r, q, p;
950
951         assert(i);
952
953         r = arg_create ? create_item(i) : 0;
954         q = arg_remove ? remove_item(i) : 0;
955         p = arg_clean ? clean_item(i) : 0;
956
957         if (r < 0)
958                 return r;
959
960         if (q < 0)
961                 return q;
962
963         return p;
964 }
965
966 static void item_free(Item *i) {
967         assert(i);
968
969         free(i->path);
970         free(i->argument);
971         free(i);
972 }
973
974 static inline void item_freep(Item **i) {
975         if (*i)
976                 item_free(*i);
977 }
978 #define _cleanup_item_free_ _cleanup_(item_freep)
979
980 static bool item_equal(Item *a, Item *b) {
981         assert(a);
982         assert(b);
983
984         if (!streq_ptr(a->path, b->path))
985                 return false;
986
987         if (a->type != b->type)
988                 return false;
989
990         if (a->uid_set != b->uid_set ||
991             (a->uid_set && a->uid != b->uid))
992             return false;
993
994         if (a->gid_set != b->gid_set ||
995             (a->gid_set && a->gid != b->gid))
996             return false;
997
998         if (a->mode_set != b->mode_set ||
999             (a->mode_set && a->mode != b->mode))
1000             return false;
1001
1002         if (a->age_set != b->age_set ||
1003             (a->age_set && a->age != b->age))
1004             return false;
1005
1006         if ((a->type == CREATE_FILE ||
1007              a->type == TRUNCATE_FILE ||
1008              a->type == WRITE_FILE ||
1009              a->type == CREATE_SYMLINK) &&
1010             !streq_ptr(a->argument, b->argument))
1011                 return false;
1012
1013         if ((a->type == CREATE_CHAR_DEVICE ||
1014              a->type == CREATE_BLOCK_DEVICE) &&
1015             a->major_minor != b->major_minor)
1016                 return false;
1017
1018         return true;
1019 }
1020
1021 static bool should_include_path(const char *path) {
1022         char **prefix;
1023
1024         /* no explicit paths specified for inclusion, so everything is valid */
1025         if (strv_length(include_prefixes) == 0)
1026                 return true;
1027
1028         STRV_FOREACH(prefix, include_prefixes) {
1029                 if (path_startswith(path, *prefix))
1030                         return true;
1031         }
1032
1033         return false;
1034 }
1035
1036 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1037         _cleanup_item_free_ Item *i = NULL;
1038         Item *existing;
1039         _cleanup_free_ char
1040                 *mode = NULL, *user = NULL, *group = NULL, *age = NULL;
1041         char type;
1042         Hashmap *h;
1043         int r, n = -1;
1044
1045         assert(fname);
1046         assert(line >= 1);
1047         assert(buffer);
1048
1049         i = new0(Item, 1);
1050         if (!i)
1051                 return log_oom();
1052
1053         r = sscanf(buffer,
1054                    "%c %ms %ms %ms %ms %ms %n",
1055                    &type,
1056                    &i->path,
1057                    &mode,
1058                    &user,
1059                    &group,
1060                    &age,
1061                    &n);
1062         if (r < 2) {
1063                 log_error("[%s:%u] Syntax error.", fname, line);
1064                 return -EIO;
1065         }
1066
1067         if (n >= 0)  {
1068                 n += strspn(buffer+n, WHITESPACE);
1069                 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1070                         i->argument = unquote(buffer+n, "\"");
1071                         if (!i->argument)
1072                                 return log_oom();
1073                 }
1074         }
1075
1076         switch(type) {
1077
1078         case CREATE_FILE:
1079         case TRUNCATE_FILE:
1080         case CREATE_DIRECTORY:
1081         case TRUNCATE_DIRECTORY:
1082         case CREATE_FIFO:
1083         case IGNORE_PATH:
1084         case IGNORE_DIRECTORY_PATH:
1085         case REMOVE_PATH:
1086         case RECURSIVE_REMOVE_PATH:
1087         case RELABEL_PATH:
1088         case RECURSIVE_RELABEL_PATH:
1089                 break;
1090
1091         case CREATE_SYMLINK:
1092                 if (!i->argument) {
1093                         log_error("[%s:%u] Symlink file requires argument.", fname, line);
1094                         return -EBADMSG;
1095                 }
1096                 break;
1097
1098         case WRITE_FILE:
1099                 if (!i->argument) {
1100                         log_error("[%s:%u] Write file requires argument.", fname, line);
1101                         return -EBADMSG;
1102                 }
1103                 break;
1104
1105         case CREATE_CHAR_DEVICE:
1106         case CREATE_BLOCK_DEVICE: {
1107                 unsigned major, minor;
1108
1109                 if (!i->argument) {
1110                         log_error("[%s:%u] Device file requires argument.", fname, line);
1111                         return -EBADMSG;
1112                 }
1113
1114                 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1115                         log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1116                         return -EBADMSG;
1117                 }
1118
1119                 i->major_minor = makedev(major, minor);
1120                 break;
1121         }
1122
1123         default:
1124                 log_error("[%s:%u] Unknown file type '%c'.", fname, line, type);
1125                 return -EBADMSG;
1126         }
1127
1128         i->type = type;
1129
1130         if (!path_is_absolute(i->path)) {
1131                 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1132                 return -EBADMSG;
1133         }
1134
1135         path_kill_slashes(i->path);
1136
1137         if (!should_include_path(i->path))
1138                 return 0;
1139
1140         if (user && !streq(user, "-")) {
1141                 const char *u = user;
1142
1143                 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1144                 if (r < 0) {
1145                         log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1146                         return r;
1147                 }
1148
1149                 i->uid_set = true;
1150         }
1151
1152         if (group && !streq(group, "-")) {
1153                 const char *g = group;
1154
1155                 r = get_group_creds(&g, &i->gid);
1156                 if (r < 0) {
1157                         log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1158                         return r;
1159                 }
1160
1161                 i->gid_set = true;
1162         }
1163
1164         if (mode && !streq(mode, "-")) {
1165                 unsigned m;
1166
1167                 if (sscanf(mode, "%o", &m) != 1) {
1168                         log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1169                         return -ENOENT;
1170                 }
1171
1172                 i->mode = m;
1173                 i->mode_set = true;
1174         } else
1175                 i->mode =
1176                         i->type == CREATE_DIRECTORY ||
1177                         i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1178
1179         if (age && !streq(age, "-")) {
1180                 const char *a = age;
1181
1182                 if (*a == '~') {
1183                         i->keep_first_level = true;
1184                         a++;
1185                 }
1186
1187                 if (parse_sec(a, &i->age) < 0) {
1188                         log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1189                         return -EBADMSG;
1190                 }
1191
1192                 i->age_set = true;
1193         }
1194
1195         h = needs_glob(i->type) ? globs : items;
1196
1197         existing = hashmap_get(h, i->path);
1198         if (existing) {
1199
1200                 /* Two identical items are fine */
1201                 if (!item_equal(existing, i))
1202                         log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1203
1204                 return 0;
1205         }
1206
1207         r = hashmap_put(h, i->path, i);
1208         if (r < 0) {
1209                 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1210                 return r;
1211         }
1212
1213         i = NULL; /* avoid cleanup */
1214
1215         return 0;
1216 }
1217
1218 static int help(void) {
1219
1220         printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1221                "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1222                "  -h --help             Show this help\n"
1223                "     --create           Create marked files/directories\n"
1224                "     --clean            Clean up marked directories\n"
1225                "     --remove           Remove marked files/directories\n"
1226                "     --prefix=PATH      Only apply rules that apply to paths with the specified prefix\n",
1227                program_invocation_short_name);
1228
1229         return 0;
1230 }
1231
1232 static int parse_argv(int argc, char *argv[]) {
1233
1234         enum {
1235                 ARG_CREATE,
1236                 ARG_CLEAN,
1237                 ARG_REMOVE,
1238                 ARG_PREFIX
1239         };
1240
1241         static const struct option options[] = {
1242                 { "help",      no_argument,       NULL, 'h'           },
1243                 { "create",    no_argument,       NULL, ARG_CREATE    },
1244                 { "clean",     no_argument,       NULL, ARG_CLEAN     },
1245                 { "remove",    no_argument,       NULL, ARG_REMOVE    },
1246                 { "prefix",    required_argument, NULL, ARG_PREFIX    },
1247                 { NULL,        0,                 NULL, 0             }
1248         };
1249
1250         int c;
1251
1252         assert(argc >= 0);
1253         assert(argv);
1254
1255         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
1256
1257                 switch (c) {
1258
1259                 case 'h':
1260                         help();
1261                         return 0;
1262
1263                 case ARG_CREATE:
1264                         arg_create = true;
1265                         break;
1266
1267                 case ARG_CLEAN:
1268                         arg_clean = true;
1269                         break;
1270
1271                 case ARG_REMOVE:
1272                         arg_remove = true;
1273                         break;
1274
1275                 case ARG_PREFIX:
1276                         if (strv_extend(&include_prefixes, optarg) < 0)
1277                                 return log_oom();
1278                         break;
1279
1280                 case '?':
1281                         return -EINVAL;
1282
1283                 default:
1284                         log_error("Unknown option code %c", c);
1285                         return -EINVAL;
1286                 }
1287         }
1288
1289         if (!arg_clean && !arg_create && !arg_remove) {
1290                 log_error("You need to specify at least one of --clean, --create or --remove.");
1291                 return -EINVAL;
1292         }
1293
1294         return 1;
1295 }
1296
1297 static int read_config_file(const char *fn, bool ignore_enoent) {
1298         FILE *f;
1299         unsigned v = 0;
1300         int r;
1301         Iterator iterator;
1302         Item *i;
1303
1304         assert(fn);
1305
1306         r = search_and_fopen_nulstr(fn, "re", conf_file_dirs, &f);
1307         if (r < 0) {
1308                 if (ignore_enoent && r == -ENOENT)
1309                         return 0;
1310
1311                 log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
1312                 return r;
1313         }
1314
1315         log_debug("apply: %s\n", fn);
1316         for (;;) {
1317                 char line[LINE_MAX], *l;
1318                 int k;
1319
1320                 if (!(fgets(line, sizeof(line), f)))
1321                         break;
1322
1323                 v++;
1324
1325                 l = strstrip(line);
1326                 if (*l == '#' || *l == 0)
1327                         continue;
1328
1329                 if ((k = parse_line(fn, v, l)) < 0)
1330                         if (r == 0)
1331                                 r = k;
1332         }
1333
1334         /* we have to determine age parameter for each entry of type X */
1335         HASHMAP_FOREACH(i, globs, iterator) {
1336                 Iterator iter;
1337                 Item *j, *candidate_item = NULL;
1338
1339                 if (i->type != IGNORE_DIRECTORY_PATH)
1340                         continue;
1341
1342                 HASHMAP_FOREACH(j, items, iter) {
1343                         if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY)
1344                                 continue;
1345
1346                         if (path_equal(j->path, i->path)) {
1347                                 candidate_item = j;
1348                                 break;
1349                         }
1350
1351                         if ((!candidate_item && path_startswith(i->path, j->path)) ||
1352                             (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1353                                 candidate_item = j;
1354                 }
1355
1356                 if (candidate_item) {
1357                         i->age = candidate_item->age;
1358                         i->age_set = true;
1359                 }
1360         }
1361
1362         if (ferror(f)) {
1363                 log_error("Failed to read from file %s: %m", fn);
1364                 if (r == 0)
1365                         r = -EIO;
1366         }
1367
1368         fclose(f);
1369
1370         return r;
1371 }
1372
1373 int main(int argc, char *argv[]) {
1374         int r, k;
1375         Item *i;
1376         Iterator iterator;
1377
1378         r = parse_argv(argc, argv);
1379         if (r <= 0)
1380                 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1381
1382         log_set_target(LOG_TARGET_AUTO);
1383         log_parse_environment();
1384         log_open();
1385
1386         umask(0022);
1387
1388         label_init(NULL);
1389
1390         items = hashmap_new(string_hash_func, string_compare_func);
1391         globs = hashmap_new(string_hash_func, string_compare_func);
1392
1393         if (!items || !globs) {
1394                 r = log_oom();
1395                 goto finish;
1396         }
1397
1398         r = 0;
1399
1400         if (optind < argc) {
1401                 int j;
1402
1403                 for (j = optind; j < argc; j++) {
1404                         k = read_config_file(argv[j], false);
1405                         if (k < 0 && r == 0)
1406                                 r = k;
1407                 }
1408
1409         } else {
1410                 _cleanup_strv_free_ char **files = NULL;
1411                 char **f;
1412
1413                 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
1414                 if (r < 0) {
1415                         log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1416                         goto finish;
1417                 }
1418
1419                 STRV_FOREACH(f, files) {
1420                         k = read_config_file(*f, true);
1421                         if (k < 0 && r == 0)
1422                                 r = k;
1423                 }
1424         }
1425
1426         HASHMAP_FOREACH(i, globs, iterator)
1427                 process_item(i);
1428
1429         HASHMAP_FOREACH(i, items, iterator)
1430                 process_item(i);
1431
1432 finish:
1433         while ((i = hashmap_steal_first(items)))
1434                 item_free(i);
1435
1436         while ((i = hashmap_steal_first(globs)))
1437                 item_free(i);
1438
1439         hashmap_free(items);
1440         hashmap_free(globs);
1441
1442         strv_free(include_prefixes);
1443
1444         set_free_free(unix_sockets);
1445
1446         label_finish();
1447
1448         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1449 }