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