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