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