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