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