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