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