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