chiark / gitweb /
shared: add root argument to search_and_fopen
[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
115 static const char conf_file_dirs[] =
116         "/etc/tmpfiles.d\0"
117         "/run/tmpfiles.d\0"
118         "/usr/local/lib/tmpfiles.d\0"
119         "/usr/lib/tmpfiles.d\0"
120 #ifdef HAVE_SPLIT_USR
121         "/lib/tmpfiles.d\0"
122 #endif
123         ;
124
125 #define MAX_DEPTH 256
126
127 static bool needs_glob(ItemType t) {
128         return t == IGNORE_PATH || t == IGNORE_DIRECTORY_PATH || t == REMOVE_PATH || t == RECURSIVE_REMOVE_PATH || t == RELABEL_PATH || t == RECURSIVE_RELABEL_PATH;
129 }
130
131 static struct Item* find_glob(Hashmap *h, const char *match) {
132         Item *j;
133         Iterator i;
134
135         HASHMAP_FOREACH(j, h, i)
136                 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
137                         return j;
138
139         return NULL;
140 }
141
142 static void load_unix_sockets(void) {
143         _cleanup_fclose_ FILE *f = NULL;
144         char line[LINE_MAX];
145
146         if (unix_sockets)
147                 return;
148
149         /* We maintain a cache of the sockets we found in
150          * /proc/net/unix to speed things up a little. */
151
152         unix_sockets = set_new(string_hash_func, string_compare_func);
153         if (!unix_sockets)
154                 return;
155
156         f = fopen("/proc/net/unix", "re");
157         if (!f)
158                 return;
159
160         /* Skip header */
161         if (!fgets(line, sizeof(line), f))
162                 goto fail;
163
164         for (;;) {
165                 char *p, *s;
166                 int k;
167
168                 if (!fgets(line, sizeof(line), f))
169                         break;
170
171                 truncate_nl(line);
172
173                 p = strchr(line, ':');
174                 if (!p)
175                         continue;
176
177                 if (strlen(p) < 37)
178                         continue;
179
180                 p += 37;
181                 p += strspn(p, WHITESPACE);
182                 p += strcspn(p, WHITESPACE); /* skip one more word */
183                 p += strspn(p, WHITESPACE);
184
185                 if (*p != '/')
186                         continue;
187
188                 s = strdup(p);
189                 if (!s)
190                         goto fail;
191
192                 path_kill_slashes(s);
193
194                 k = set_consume(unix_sockets, s);
195                 if (k < 0 && k != -EEXIST)
196                         goto fail;
197         }
198
199         return;
200
201 fail:
202         set_free_free(unix_sockets);
203         unix_sockets = NULL;
204 }
205
206 static bool unix_socket_alive(const char *fn) {
207         assert(fn);
208
209         load_unix_sockets();
210
211         if (unix_sockets)
212                 return !!set_get(unix_sockets, (char*) fn);
213
214         /* We don't know, so assume yes */
215         return true;
216 }
217
218 static int dir_is_mount_point(DIR *d, const char *subdir) {
219         struct file_handle *h;
220         int mount_id_parent, mount_id;
221         int r_p, r;
222
223         h = alloca(MAX_HANDLE_SZ);
224
225         h->handle_bytes = MAX_HANDLE_SZ;
226         r_p = name_to_handle_at(dirfd(d), ".", h, &mount_id_parent, 0);
227         if (r_p < 0)
228                 r_p = -errno;
229
230         h->handle_bytes = MAX_HANDLE_SZ;
231         r = name_to_handle_at(dirfd(d), subdir, h, &mount_id, 0);
232         if (r < 0)
233                 r = -errno;
234
235         /* got no handle; make no assumptions, return error */
236         if (r_p < 0 && r < 0)
237                 return r_p;
238
239         /* got both handles; if they differ, it is a mount point */
240         if (r_p >= 0 && r >= 0)
241                 return mount_id_parent != mount_id;
242
243         /* got only one handle; assume different mount points if one
244          * of both queries was not supported by the filesystem */
245         if (r_p == -ENOSYS || r_p == -ENOTSUP || r == -ENOSYS || r == -ENOTSUP)
246                 return true;
247
248         /* return error */
249         if (r_p < 0)
250                 return r_p;
251         return r;
252 }
253
254 static int dir_cleanup(
255                 Item *i,
256                 const char *p,
257                 DIR *d,
258                 const struct stat *ds,
259                 usec_t cutoff,
260                 dev_t rootdev,
261                 bool mountpoint,
262                 int maxdepth,
263                 bool keep_this_level) {
264
265         struct dirent *dent;
266         struct timespec times[2];
267         bool deleted = false;
268         int r = 0;
269
270         while ((dent = readdir(d))) {
271                 struct stat s;
272                 usec_t age;
273                 _cleanup_free_ char *sub_path = NULL;
274
275                 if (streq(dent->d_name, ".") ||
276                     streq(dent->d_name, ".."))
277                         continue;
278
279                 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
280                         if (errno == ENOENT)
281                                 continue;
282
283                         /* FUSE, NFS mounts, SELinux might return EACCES */
284                         if (errno == EACCES)
285                                 log_debug("stat(%s/%s) failed: %m", p, dent->d_name);
286                         else
287                                 log_error("stat(%s/%s) failed: %m", p, dent->d_name);
288                         r = -errno;
289                         continue;
290                 }
291
292                 /* Stay on the same filesystem */
293                 if (s.st_dev != rootdev)
294                         continue;
295
296                 /* Try to detect bind mounts of the same filesystem instance; they
297                  * do not differ in device major/minors. This type of query is not
298                  * supported on all kernels or filesystem types though. */
299                 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
300                         continue;
301
302                 /* Do not delete read-only files owned by root */
303                 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
304                         continue;
305
306                 if (asprintf(&sub_path, "%s/%s", p, dent->d_name) < 0) {
307                         r = log_oom();
308                         goto finish;
309                 }
310
311                 /* Is there an item configured for this path? */
312                 if (hashmap_get(items, sub_path))
313                         continue;
314
315                 if (find_glob(globs, sub_path))
316                         continue;
317
318                 if (S_ISDIR(s.st_mode)) {
319
320                         if (mountpoint &&
321                             streq(dent->d_name, "lost+found") &&
322                             s.st_uid == 0)
323                                 continue;
324
325                         if (maxdepth <= 0)
326                                 log_warning("Reached max depth on %s.", sub_path);
327                         else {
328                                 _cleanup_closedir_ DIR *sub_dir;
329                                 int q;
330
331                                 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
332                                 if (sub_dir == NULL) {
333                                         if (errno != ENOENT) {
334                                                 log_error("opendir(%s/%s) failed: %m", p, dent->d_name);
335                                                 r = -errno;
336                                         }
337
338                                         continue;
339                                 }
340
341                                 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
342
343                                 if (q < 0)
344                                         r = q;
345                         }
346
347                         /* Note: if you are wondering why we don't
348                          * support the sticky bit for excluding
349                          * directories from cleaning like we do it for
350                          * other file system objects: well, the sticky
351                          * bit already has a meaning for directories,
352                          * so we don't want to overload that. */
353
354                         if (keep_this_level)
355                                 continue;
356
357                         /* Ignore ctime, we change it when deleting */
358                         age = MAX(timespec_load(&s.st_mtim),
359                                   timespec_load(&s.st_atim));
360                         if (age >= cutoff)
361                                 continue;
362
363                         if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
364                                 log_debug("rmdir '%s'", sub_path);
365
366                                 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
367                                         if (errno != ENOENT && errno != ENOTEMPTY) {
368                                                 log_error("rmdir(%s): %m", sub_path);
369                                                 r = -errno;
370                                         }
371                                 }
372                         }
373
374                 } else {
375                         /* Skip files for which the sticky bit is
376                          * set. These are semantics we define, and are
377                          * unknown elsewhere. See XDG_RUNTIME_DIR
378                          * specification for details. */
379                         if (s.st_mode & S_ISVTX)
380                                 continue;
381
382                         if (mountpoint && S_ISREG(s.st_mode)) {
383                                 if (streq(dent->d_name, ".journal") &&
384                                     s.st_uid == 0)
385                                         continue;
386
387                                 if (streq(dent->d_name, "aquota.user") ||
388                                     streq(dent->d_name, "aquota.group"))
389                                         continue;
390                         }
391
392                         /* Ignore sockets that are listed in /proc/net/unix */
393                         if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
394                                 continue;
395
396                         /* Ignore device nodes */
397                         if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
398                                 continue;
399
400                         /* Keep files on this level around if this is
401                          * requested */
402                         if (keep_this_level)
403                                 continue;
404
405                         age = MAX3(timespec_load(&s.st_mtim),
406                                    timespec_load(&s.st_atim),
407                                    timespec_load(&s.st_ctim));
408
409                         if (age >= cutoff)
410                                 continue;
411
412                         log_debug("unlink '%s'", sub_path);
413
414                         if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
415                                 if (errno != ENOENT) {
416                                         log_error("unlink(%s): %m", sub_path);
417                                         r = -errno;
418                                 }
419                         }
420
421                         deleted = true;
422                 }
423         }
424
425 finish:
426         if (deleted) {
427                 /* Restore original directory timestamps */
428                 times[0] = ds->st_atim;
429                 times[1] = ds->st_mtim;
430
431                 if (futimens(dirfd(d), times) < 0)
432                         log_error("utimensat(%s): %m", p);
433         }
434
435         return r;
436 }
437
438 static int item_set_perms_full(Item *i, const char *path, bool ignore_enoent) {
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         return label_fix(path, ignore_enoent, false);
460 }
461
462 static int item_set_perms(Item *i, const char *path) {
463         return item_set_perms_full(i, path, false);
464 }
465
466 static int write_one_file(Item *i, const char *path) {
467         int e, flags;
468         int fd = -1;
469         struct stat st;
470         int r = 0;
471
472         flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
473                 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;
474
475         RUN_WITH_UMASK(0) {
476                 label_context_set(path, S_IFREG);
477                 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
478                 e = errno;
479                 label_context_clear();
480                 errno = e;
481         }
482
483         if (fd < 0) {
484                 if (i->type == WRITE_FILE && errno == ENOENT)
485                         return 0;
486
487                 log_error("Failed to create file %s: %m", path);
488                 return -errno;
489         }
490
491         if (i->argument) {
492                 ssize_t n;
493                 size_t l;
494                 _cleanup_free_ char *unescaped;
495
496                 unescaped = cunescape(i->argument);
497                 if (unescaped == NULL) {
498                         close_nointr_nofail(fd);
499                         return log_oom();
500                 }
501
502                 l = strlen(unescaped);
503                 n = write(fd, unescaped, l);
504
505                 if (n < 0 || (size_t) n < l) {
506                         log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
507                         close_nointr_nofail(fd);
508                         return n < 0 ? n : -EIO;
509                 }
510         }
511
512         close_nointr_nofail(fd);
513
514         if (stat(path, &st) < 0) {
515                 log_error("stat(%s) failed: %m", path);
516                 return -errno;
517         }
518
519         if (!S_ISREG(st.st_mode)) {
520                 log_error("%s is not a file.", path);
521                 return -EEXIST;
522         }
523
524         r = item_set_perms(i, path);
525         if (r < 0)
526                 return r;
527
528         return 0;
529 }
530
531 static int recursive_relabel_children(Item *i, const char *path) {
532         _cleanup_closedir_ DIR *d;
533         int ret = 0;
534
535         /* This returns the first error we run into, but nevertheless
536          * tries to go on */
537
538         d = opendir(path);
539         if (!d)
540                 return errno == ENOENT ? 0 : -errno;
541
542         for (;;) {
543                 struct dirent *de;
544                 bool is_dir;
545                 int r;
546                 _cleanup_free_ char *entry_path = NULL;
547
548                 errno = 0;
549                 de = readdir(d);
550                 if (!de && errno != 0) {
551                         if (ret == 0)
552                                 ret = -errno;
553                         break;
554                 }
555
556                 if (!de)
557                         break;
558
559                 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
560                         continue;
561
562                 if (asprintf(&entry_path, "%s/%s", path, de->d_name) < 0) {
563                         if (ret == 0)
564                                 ret = -ENOMEM;
565                         continue;
566                 }
567
568                 if (de->d_type == DT_UNKNOWN) {
569                         struct stat st;
570
571                         if (lstat(entry_path, &st) < 0) {
572                                 if (ret == 0 && errno != ENOENT)
573                                         ret = -errno;
574                                 continue;
575                         }
576
577                         is_dir = S_ISDIR(st.st_mode);
578
579                 } else
580                         is_dir = de->d_type == DT_DIR;
581
582                 r = item_set_perms(i, entry_path);
583                 if (r < 0) {
584                         if (ret == 0 && r != -ENOENT)
585                                 ret = r;
586                         continue;
587                 }
588
589                 if (is_dir) {
590                         r = recursive_relabel_children(i, entry_path);
591                         if (r < 0 && ret == 0)
592                                 ret = r;
593                 }
594         }
595
596         return ret;
597 }
598
599 static int recursive_relabel(Item *i, const char *path) {
600         int r;
601         struct stat st;
602
603         r = item_set_perms(i, path);
604         if (r < 0)
605                 return r;
606
607         if (lstat(path, &st) < 0)
608                 return -errno;
609
610         if (S_ISDIR(st.st_mode))
611                 r = recursive_relabel_children(i, path);
612
613         return r;
614 }
615
616 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
617         int r = 0, k;
618         _cleanup_globfree_ glob_t g = {};
619         char **fn;
620
621         errno = 0;
622         k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
623         if (k != 0)
624                 if (k != GLOB_NOMATCH) {
625                         if (errno > 0)
626                                 errno = EIO;
627
628                         log_error("glob(%s) failed: %m", i->path);
629                         return -errno;
630                 }
631
632         STRV_FOREACH(fn, g.gl_pathv) {
633                 k = action(i, *fn);
634                 if (k < 0)
635                         r = k;
636         }
637
638         return r;
639 }
640
641 static int create_item(Item *i) {
642         int e;
643         struct stat st;
644         int r = 0;
645
646         assert(i);
647
648         switch (i->type) {
649
650         case IGNORE_PATH:
651         case IGNORE_DIRECTORY_PATH:
652         case REMOVE_PATH:
653         case RECURSIVE_REMOVE_PATH:
654                 return 0;
655
656         case CREATE_FILE:
657         case TRUNCATE_FILE:
658                 r = write_one_file(i, i->path);
659                 if (r < 0)
660                         return r;
661                 break;
662
663         case WRITE_FILE:
664                 r = glob_item(i, write_one_file);
665                 if (r < 0)
666                         return r;
667
668                 break;
669
670         case ADJUST_MODE:
671                 r = item_set_perms_full(i, i->path, true);
672                 if (r < 0)
673                         return r;
674
675                 break;
676
677         case TRUNCATE_DIRECTORY:
678         case CREATE_DIRECTORY:
679
680                 RUN_WITH_UMASK(0000) {
681                         mkdir_parents_label(i->path, 0755);
682                         r = mkdir(i->path, i->mode);
683                 }
684
685                 if (r < 0 && errno != EEXIST) {
686                         log_error("Failed to create directory %s: %m", i->path);
687                         return -errno;
688                 }
689
690                 if (stat(i->path, &st) < 0) {
691                         log_error("stat(%s) failed: %m", i->path);
692                         return -errno;
693                 }
694
695                 if (!S_ISDIR(st.st_mode)) {
696                         log_error("%s is not a directory.", i->path);
697                         return -EEXIST;
698                 }
699
700                 r = item_set_perms(i, i->path);
701                 if (r < 0)
702                         return r;
703
704                 break;
705
706         case CREATE_FIFO:
707
708                 RUN_WITH_UMASK(0000) {
709                         r = mkfifo(i->path, i->mode);
710                 }
711
712                 if (r < 0 && errno != EEXIST) {
713                         log_error("Failed to create fifo %s: %m", i->path);
714                         return -errno;
715                 }
716
717                 if (stat(i->path, &st) < 0) {
718                         log_error("stat(%s) failed: %m", i->path);
719                         return -errno;
720                 }
721
722                 if (!S_ISFIFO(st.st_mode)) {
723                         log_error("%s is not a fifo.", i->path);
724                         return -EEXIST;
725                 }
726
727                 r = item_set_perms(i, i->path);
728                 if (r < 0)
729                         return r;
730
731                 break;
732
733         case CREATE_SYMLINK: {
734                 _cleanup_free_ char *x = NULL;
735
736                 label_context_set(i->path, S_IFLNK);
737                 r = symlink(i->argument, i->path);
738                 e = errno;
739                 label_context_clear();
740                 errno = e;
741
742                 if (r < 0 && errno != EEXIST) {
743                         log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
744                         return -errno;
745                 }
746
747                 r = readlink_malloc(i->path, &x);
748                 if (r < 0) {
749                         log_error("readlink(%s) failed: %s", i->path, strerror(-r));
750                         return -errno;
751                 }
752
753                 if (!streq(i->argument, x)) {
754                         log_error("%s is not the right symlinks.", i->path);
755                         return -EEXIST;
756                 }
757
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                 *action = NULL, *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                    "%ms %ms %ms %ms %ms %ms %n",
1087                    &action,
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         if (strlen(action) > 2 || (strlen(action) > 1 && action[1] != '!')) {
1100                 log_error("[%s:%u] Unknown modifier '%s'", fname, line, action);
1101                 return -EINVAL;
1102         } else if (strlen(action) > 1 && !arg_boot)
1103                 return 0;
1104
1105         type = action[0];
1106
1107         i = new0(Item, 1);
1108         if (!i)
1109                 return log_oom();
1110
1111         r = specifier_printf(path, specifier_table, NULL, &i->path);
1112         if (r < 0) {
1113                 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1114                 return r;
1115         }
1116
1117         if (n >= 0)  {
1118                 n += strspn(buffer+n, WHITESPACE);
1119                 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1120                         i->argument = unquote(buffer+n, "\"");
1121                         if (!i->argument)
1122                                 return log_oom();
1123                 }
1124         }
1125
1126         switch(type) {
1127
1128         case CREATE_FILE:
1129         case TRUNCATE_FILE:
1130         case CREATE_DIRECTORY:
1131         case TRUNCATE_DIRECTORY:
1132         case CREATE_FIFO:
1133         case IGNORE_PATH:
1134         case IGNORE_DIRECTORY_PATH:
1135         case REMOVE_PATH:
1136         case RECURSIVE_REMOVE_PATH:
1137         case RELABEL_PATH:
1138         case RECURSIVE_RELABEL_PATH:
1139         case ADJUST_MODE:
1140                 break;
1141
1142         case CREATE_SYMLINK:
1143                 if (!i->argument) {
1144                         log_error("[%s:%u] Symlink file requires argument.", fname, line);
1145                         return -EBADMSG;
1146                 }
1147                 break;
1148
1149         case WRITE_FILE:
1150                 if (!i->argument) {
1151                         log_error("[%s:%u] Write file requires argument.", fname, line);
1152                         return -EBADMSG;
1153                 }
1154                 break;
1155
1156         case CREATE_CHAR_DEVICE:
1157         case CREATE_BLOCK_DEVICE: {
1158                 unsigned major, minor;
1159
1160                 if (!i->argument) {
1161                         log_error("[%s:%u] Device file requires argument.", fname, line);
1162                         return -EBADMSG;
1163                 }
1164
1165                 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1166                         log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1167                         return -EBADMSG;
1168                 }
1169
1170                 i->major_minor = makedev(major, minor);
1171                 break;
1172         }
1173
1174         default:
1175                 log_error("[%s:%u] Unknown file type '%c'.", fname, line, type);
1176                 return -EBADMSG;
1177         }
1178
1179         i->type = type;
1180
1181         if (!path_is_absolute(i->path)) {
1182                 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1183                 return -EBADMSG;
1184         }
1185
1186         path_kill_slashes(i->path);
1187
1188         if (!should_include_path(i->path))
1189                 return 0;
1190
1191         if (user && !streq(user, "-")) {
1192                 const char *u = user;
1193
1194                 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1195                 if (r < 0) {
1196                         log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1197                         return r;
1198                 }
1199
1200                 i->uid_set = true;
1201         }
1202
1203         if (group && !streq(group, "-")) {
1204                 const char *g = group;
1205
1206                 r = get_group_creds(&g, &i->gid);
1207                 if (r < 0) {
1208                         log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1209                         return r;
1210                 }
1211
1212                 i->gid_set = true;
1213         }
1214
1215         if (mode && !streq(mode, "-")) {
1216                 unsigned m;
1217
1218                 if (sscanf(mode, "%o", &m) != 1) {
1219                         log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1220                         return -ENOENT;
1221                 }
1222
1223                 i->mode = m;
1224                 i->mode_set = true;
1225         } else
1226                 i->mode =
1227                         i->type == CREATE_DIRECTORY ||
1228                         i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1229
1230         if (age && !streq(age, "-")) {
1231                 const char *a = age;
1232
1233                 if (*a == '~') {
1234                         i->keep_first_level = true;
1235                         a++;
1236                 }
1237
1238                 if (parse_sec(a, &i->age) < 0) {
1239                         log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1240                         return -EBADMSG;
1241                 }
1242
1243                 i->age_set = true;
1244         }
1245
1246         h = needs_glob(i->type) ? globs : items;
1247
1248         existing = hashmap_get(h, i->path);
1249         if (existing) {
1250
1251                 /* Two identical items are fine */
1252                 if (!item_equal(existing, i))
1253                         log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1254
1255                 return 0;
1256         }
1257
1258         r = hashmap_put(h, i->path, i);
1259         if (r < 0) {
1260                 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1261                 return r;
1262         }
1263
1264         i = NULL; /* avoid cleanup */
1265
1266         return 0;
1267 }
1268
1269 static int help(void) {
1270
1271         printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1272                "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1273                "  -h --help                 Show this help\n"
1274                "     --version              Show package version\n"
1275                "     --create               Create marked files/directories\n"
1276                "     --clean                Clean up marked directories\n"
1277                "     --remove               Remove marked files/directories\n"
1278                "     --boot                 Execute actions only safe at boot\n"
1279                "     --prefix=PATH          Only apply rules that apply to paths with the specified prefix\n"
1280                "     --exclude-prefix=PATH  Ignore rules that apply to paths with the specified prefix\n",
1281                program_invocation_short_name);
1282
1283         return 0;
1284 }
1285
1286 static int parse_argv(int argc, char *argv[]) {
1287
1288         enum {
1289                 ARG_VERSION = 0x100,
1290                 ARG_CREATE,
1291                 ARG_CLEAN,
1292                 ARG_REMOVE,
1293                 ARG_BOOT,
1294                 ARG_PREFIX,
1295                 ARG_EXCLUDE_PREFIX,
1296         };
1297
1298         static const struct option options[] = {
1299                 { "help",           no_argument,         NULL, 'h'                },
1300                 { "version",        no_argument,         NULL, ARG_VERSION        },
1301                 { "create",         no_argument,         NULL, ARG_CREATE         },
1302                 { "clean",          no_argument,         NULL, ARG_CLEAN          },
1303                 { "remove",         no_argument,         NULL, ARG_REMOVE         },
1304                 { "boot",           no_argument,         NULL, ARG_BOOT           },
1305                 { "prefix",         required_argument,   NULL, ARG_PREFIX         },
1306                 { "exclude-prefix", required_argument,   NULL, ARG_EXCLUDE_PREFIX },
1307                 {}
1308         };
1309
1310         int c;
1311
1312         assert(argc >= 0);
1313         assert(argv);
1314
1315         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
1316
1317                 switch (c) {
1318
1319                 case 'h':
1320                         return help();
1321
1322                 case ARG_VERSION:
1323                         puts(PACKAGE_STRING);
1324                         puts(SYSTEMD_FEATURES);
1325                         return 0;
1326
1327                 case ARG_CREATE:
1328                         arg_create = true;
1329                         break;
1330
1331                 case ARG_CLEAN:
1332                         arg_clean = true;
1333                         break;
1334
1335                 case ARG_REMOVE:
1336                         arg_remove = true;
1337                         break;
1338
1339                 case ARG_BOOT:
1340                         arg_boot = true;
1341                         break;
1342
1343                 case ARG_PREFIX:
1344                         if (strv_push(&include_prefixes, optarg) < 0)
1345                                 return log_oom();
1346                         break;
1347
1348                 case ARG_EXCLUDE_PREFIX:
1349                         if (strv_push(&exclude_prefixes, optarg) < 0)
1350                                 return log_oom();
1351                         break;
1352
1353                 case '?':
1354                         return -EINVAL;
1355
1356                 default:
1357                         assert_not_reached("Unhandled option");
1358                 }
1359         }
1360
1361         if (!arg_clean && !arg_create && !arg_remove) {
1362                 log_error("You need to specify at least one of --clean, --create or --remove.");
1363                 return -EINVAL;
1364         }
1365
1366         return 1;
1367 }
1368
1369 static int read_config_file(const char *fn, bool ignore_enoent) {
1370         _cleanup_fclose_ FILE *f = NULL;
1371         char line[LINE_MAX];
1372         Iterator iterator;
1373         unsigned v = 0;
1374         Item *i;
1375         int r;
1376
1377         assert(fn);
1378
1379         r = search_and_fopen_nulstr(fn, "re", NULL, conf_file_dirs, &f);
1380         if (r < 0) {
1381                 if (ignore_enoent && r == -ENOENT)
1382                         return 0;
1383
1384                 log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
1385                 return r;
1386         }
1387
1388         FOREACH_LINE(line, f, break) {
1389                 char *l;
1390                 int k;
1391
1392                 v++;
1393
1394                 l = strstrip(line);
1395                 if (*l == '#' || *l == 0)
1396                         continue;
1397
1398                 k = parse_line(fn, v, l);
1399                 if (k < 0 && r == 0)
1400                         r = k;
1401         }
1402
1403         /* we have to determine age parameter for each entry of type X */
1404         HASHMAP_FOREACH(i, globs, iterator) {
1405                 Iterator iter;
1406                 Item *j, *candidate_item = NULL;
1407
1408                 if (i->type != IGNORE_DIRECTORY_PATH)
1409                         continue;
1410
1411                 HASHMAP_FOREACH(j, items, iter) {
1412                         if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY)
1413                                 continue;
1414
1415                         if (path_equal(j->path, i->path)) {
1416                                 candidate_item = j;
1417                                 break;
1418                         }
1419
1420                         if ((!candidate_item && path_startswith(i->path, j->path)) ||
1421                             (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1422                                 candidate_item = j;
1423                 }
1424
1425                 if (candidate_item) {
1426                         i->age = candidate_item->age;
1427                         i->age_set = true;
1428                 }
1429         }
1430
1431         if (ferror(f)) {
1432                 log_error("Failed to read from file %s: %m", fn);
1433                 if (r == 0)
1434                         r = -EIO;
1435         }
1436
1437         return r;
1438 }
1439
1440 int main(int argc, char *argv[]) {
1441         int r, k;
1442         Item *i;
1443         Iterator iterator;
1444
1445         r = parse_argv(argc, argv);
1446         if (r <= 0)
1447                 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1448
1449         log_set_target(LOG_TARGET_AUTO);
1450         log_parse_environment();
1451         log_open();
1452
1453         umask(0022);
1454
1455         label_init(NULL);
1456
1457         items = hashmap_new(string_hash_func, string_compare_func);
1458         globs = hashmap_new(string_hash_func, string_compare_func);
1459
1460         if (!items || !globs) {
1461                 r = log_oom();
1462                 goto finish;
1463         }
1464
1465         r = 0;
1466
1467         if (optind < argc) {
1468                 int j;
1469
1470                 for (j = optind; j < argc; j++) {
1471                         k = read_config_file(argv[j], false);
1472                         if (k < 0 && r == 0)
1473                                 r = k;
1474                 }
1475
1476         } else {
1477                 _cleanup_strv_free_ char **files = NULL;
1478                 char **f;
1479
1480                 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
1481                 if (r < 0) {
1482                         log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1483                         goto finish;
1484                 }
1485
1486                 STRV_FOREACH(f, files) {
1487                         k = read_config_file(*f, true);
1488                         if (k < 0 && r == 0)
1489                                 r = k;
1490                 }
1491         }
1492
1493         HASHMAP_FOREACH(i, globs, iterator)
1494                 process_item(i);
1495
1496         HASHMAP_FOREACH(i, items, iterator)
1497                 process_item(i);
1498
1499 finish:
1500         while ((i = hashmap_steal_first(items)))
1501                 item_free(i);
1502
1503         while ((i = hashmap_steal_first(globs)))
1504                 item_free(i);
1505
1506         hashmap_free(items);
1507         hashmap_free(globs);
1508
1509         free(include_prefixes);
1510         free(exclude_prefixes);
1511
1512         set_free_free(unix_sockets);
1513
1514         label_finish();
1515
1516         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1517 }