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