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