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