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