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