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