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