chiark / gitweb /
sd-dhcp-client: log positive error number
[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 e, flags;
466         int fd = -1;
467         struct stat st;
468         int r = 0;
469
470         flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
471                 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;
472
473         RUN_WITH_UMASK(0) {
474                 label_context_set(path, S_IFREG);
475                 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
476                 e = errno;
477                 label_context_clear();
478                 errno = e;
479         }
480
481         if (fd < 0) {
482                 if (i->type == WRITE_FILE && errno == ENOENT)
483                         return 0;
484
485                 log_error("Failed to create file %s: %m", path);
486                 return -errno;
487         }
488
489         if (i->argument) {
490                 ssize_t n;
491                 size_t l;
492                 _cleanup_free_ char *unescaped;
493
494                 unescaped = cunescape(i->argument);
495                 if (unescaped == NULL) {
496                         safe_close(fd);
497                         return log_oom();
498                 }
499
500                 l = strlen(unescaped);
501                 n = write(fd, unescaped, l);
502
503                 if (n < 0 || (size_t) n < l) {
504                         log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
505                         safe_close(fd);
506                         return n < 0 ? n : -EIO;
507                 }
508         }
509
510         safe_close(fd);
511
512         if (stat(path, &st) < 0) {
513                 log_error("stat(%s) failed: %m", path);
514                 return -errno;
515         }
516
517         if (!S_ISREG(st.st_mode)) {
518                 log_error("%s is not a file.", path);
519                 return -EEXIST;
520         }
521
522         r = item_set_perms(i, path);
523         if (r < 0)
524                 return r;
525
526         return 0;
527 }
528
529 static int recursive_relabel_children(Item *i, const char *path) {
530         _cleanup_closedir_ DIR *d;
531         int ret = 0;
532
533         /* This returns the first error we run into, but nevertheless
534          * tries to go on */
535
536         d = opendir(path);
537         if (!d)
538                 return errno == ENOENT ? 0 : -errno;
539
540         for (;;) {
541                 struct dirent *de;
542                 bool dir;
543                 int r;
544                 _cleanup_free_ char *entry_path = NULL;
545
546                 errno = 0;
547                 de = readdir(d);
548                 if (!de && errno != 0) {
549                         if (ret == 0)
550                                 ret = -errno;
551                         break;
552                 }
553
554                 if (!de)
555                         break;
556
557                 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
558                         continue;
559
560                 if (asprintf(&entry_path, "%s/%s", path, de->d_name) < 0) {
561                         if (ret == 0)
562                                 ret = -ENOMEM;
563                         continue;
564                 }
565
566                 if (de->d_type == DT_UNKNOWN) {
567                         r = is_dir(entry_path);
568                         if (r < 0) {
569                                 if (ret == 0 && errno != ENOENT)
570                                         ret = -errno;
571                                 continue;
572                         }
573
574                         dir = r;
575
576                 } else
577                         dir = de->d_type == DT_DIR;
578
579                 r = item_set_perms(i, entry_path);
580                 if (r < 0) {
581                         if (ret == 0 && r != -ENOENT)
582                                 ret = r;
583                         continue;
584                 }
585
586                 if (dir) {
587                         r = recursive_relabel_children(i, entry_path);
588                         if (r < 0 && ret == 0)
589                                 ret = r;
590                 }
591         }
592
593         return ret;
594 }
595
596 static int recursive_relabel(Item *i, const char *path) {
597         int r;
598         struct stat st;
599
600         r = item_set_perms(i, path);
601         if (r < 0)
602                 return r;
603
604         if (lstat(path, &st) < 0)
605                 return -errno;
606
607         if (S_ISDIR(st.st_mode))
608                 r = recursive_relabel_children(i, path);
609
610         return r;
611 }
612
613 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
614         int r = 0, k;
615         _cleanup_globfree_ glob_t g = {};
616         char **fn;
617
618         errno = 0;
619         k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
620         if (k != 0)
621                 if (k != GLOB_NOMATCH) {
622                         if (errno > 0)
623                                 errno = EIO;
624
625                         log_error("glob(%s) failed: %m", i->path);
626                         return -errno;
627                 }
628
629         STRV_FOREACH(fn, g.gl_pathv) {
630                 k = action(i, *fn);
631                 if (k < 0)
632                         r = k;
633         }
634
635         return r;
636 }
637
638 static int create_item(Item *i) {
639         int e;
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                 e = errno;
736                 label_context_clear();
737                 errno = e;
738
739                 if (r < 0 && errno != EEXIST) {
740                         log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
741                         return -errno;
742                 }
743
744                 r = readlink_malloc(i->path, &x);
745                 if (r < 0) {
746                         log_error("readlink(%s) failed: %s", i->path, strerror(-r));
747                         return -errno;
748                 }
749
750                 if (!streq(i->argument, x)) {
751                         log_error("%s is not the right symlinks.", i->path);
752                         return -EEXIST;
753                 }
754
755                 break;
756         }
757
758         case CREATE_BLOCK_DEVICE:
759         case CREATE_CHAR_DEVICE: {
760                 mode_t file_type;
761
762                 if (have_effective_cap(CAP_MKNOD) == 0) {
763                         /* In a container we lack CAP_MKNOD. We
764                         shouldn't attempt to create the device node in
765                         that case to avoid noise, and we don't support
766                         virtualized devices in containers anyway. */
767
768                         log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
769                         return 0;
770                 }
771
772                 file_type = (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);
773
774                 RUN_WITH_UMASK(0000) {
775                         label_context_set(i->path, file_type);
776                         r = mknod(i->path, i->mode | file_type, i->major_minor);
777                         e = errno;
778                         label_context_clear();
779                         errno = e;
780                 }
781
782                 if (r < 0 && errno != EEXIST) {
783                         log_error("Failed to create device node %s: %m", i->path);
784                         return -errno;
785                 }
786
787                 if (stat(i->path, &st) < 0) {
788                         log_error("stat(%s) failed: %m", i->path);
789                         return -errno;
790                 }
791
792                 if ((st.st_mode & S_IFMT) != file_type) {
793                         log_error("%s is not a device node.", i->path);
794                         return -EEXIST;
795                 }
796
797                 r = item_set_perms(i, i->path);
798                 if (r < 0)
799                         return r;
800
801                 break;
802         }
803
804         case RELABEL_PATH:
805
806                 r = glob_item(i, item_set_perms);
807                 if (r < 0)
808                         return r;
809                 break;
810
811         case RECURSIVE_RELABEL_PATH:
812
813                 r = glob_item(i, recursive_relabel);
814                 if (r < 0)
815                         return r;
816         }
817
818         log_debug("%s created successfully.", i->path);
819
820         return 0;
821 }
822
823 static int remove_item_instance(Item *i, const char *instance) {
824         int r;
825
826         assert(i);
827
828         switch (i->type) {
829
830         case CREATE_FILE:
831         case TRUNCATE_FILE:
832         case CREATE_DIRECTORY:
833         case CREATE_FIFO:
834         case CREATE_SYMLINK:
835         case CREATE_BLOCK_DEVICE:
836         case CREATE_CHAR_DEVICE:
837         case IGNORE_PATH:
838         case IGNORE_DIRECTORY_PATH:
839         case RELABEL_PATH:
840         case RECURSIVE_RELABEL_PATH:
841         case WRITE_FILE:
842         case ADJUST_MODE:
843                 break;
844
845         case REMOVE_PATH:
846                 if (remove(instance) < 0 && errno != ENOENT) {
847                         log_error("remove(%s): %m", instance);
848                         return -errno;
849                 }
850
851                 break;
852
853         case TRUNCATE_DIRECTORY:
854         case RECURSIVE_REMOVE_PATH:
855                 /* FIXME: we probably should use dir_cleanup() here
856                  * instead of rm_rf() so that 'x' is honoured. */
857                 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
858                 if (r < 0 && r != -ENOENT) {
859                         log_error("rm_rf(%s): %s", instance, strerror(-r));
860                         return r;
861                 }
862
863                 break;
864         }
865
866         return 0;
867 }
868
869 static int remove_item(Item *i) {
870         int r = 0;
871
872         assert(i);
873
874         switch (i->type) {
875
876         case CREATE_FILE:
877         case TRUNCATE_FILE:
878         case CREATE_DIRECTORY:
879         case CREATE_FIFO:
880         case CREATE_SYMLINK:
881         case CREATE_CHAR_DEVICE:
882         case CREATE_BLOCK_DEVICE:
883         case IGNORE_PATH:
884         case IGNORE_DIRECTORY_PATH:
885         case RELABEL_PATH:
886         case RECURSIVE_RELABEL_PATH:
887         case WRITE_FILE:
888         case ADJUST_MODE:
889                 break;
890
891         case REMOVE_PATH:
892         case TRUNCATE_DIRECTORY:
893         case RECURSIVE_REMOVE_PATH:
894                 r = glob_item(i, remove_item_instance);
895                 break;
896         }
897
898         return r;
899 }
900
901 static int clean_item_instance(Item *i, const char* instance) {
902         _cleanup_closedir_ DIR *d = NULL;
903         struct stat s, ps;
904         bool mountpoint;
905         int r;
906         usec_t cutoff, n;
907
908         assert(i);
909
910         if (!i->age_set)
911                 return 0;
912
913         n = now(CLOCK_REALTIME);
914         if (n < i->age)
915                 return 0;
916
917         cutoff = n - i->age;
918
919         d = opendir(instance);
920         if (!d) {
921                 if (errno == ENOENT || errno == ENOTDIR)
922                         return 0;
923
924                 log_error("Failed to open directory %s: %m", i->path);
925                 return -errno;
926         }
927
928         if (fstat(dirfd(d), &s) < 0) {
929                 log_error("stat(%s) failed: %m", i->path);
930                 return -errno;
931         }
932
933         if (!S_ISDIR(s.st_mode)) {
934                 log_error("%s is not a directory.", i->path);
935                 return -ENOTDIR;
936         }
937
938         if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) {
939                 log_error("stat(%s/..) failed: %m", i->path);
940                 return -errno;
941         }
942
943         mountpoint = s.st_dev != ps.st_dev ||
944                      (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
945
946         r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
947                         MAX_DEPTH, i->keep_first_level);
948         return r;
949 }
950
951 static int clean_item(Item *i) {
952         int r = 0;
953
954         assert(i);
955
956         switch (i->type) {
957         case CREATE_DIRECTORY:
958         case TRUNCATE_DIRECTORY:
959         case IGNORE_PATH:
960                 clean_item_instance(i, i->path);
961                 break;
962         case IGNORE_DIRECTORY_PATH:
963                 r = glob_item(i, clean_item_instance);
964                 break;
965         default:
966                 break;
967         }
968
969         return r;
970 }
971
972 static int process_item(Item *i) {
973         int r, q, p;
974
975         assert(i);
976
977         r = arg_create ? create_item(i) : 0;
978         q = arg_remove ? remove_item(i) : 0;
979         p = arg_clean ? clean_item(i) : 0;
980
981         if (r < 0)
982                 return r;
983
984         if (q < 0)
985                 return q;
986
987         return p;
988 }
989
990 static void item_free(Item *i) {
991         assert(i);
992
993         free(i->path);
994         free(i->argument);
995         free(i);
996 }
997
998 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
999 #define _cleanup_item_free_ _cleanup_(item_freep)
1000
1001 static bool item_equal(Item *a, Item *b) {
1002         assert(a);
1003         assert(b);
1004
1005         if (!streq_ptr(a->path, b->path))
1006                 return false;
1007
1008         if (a->type != b->type)
1009                 return false;
1010
1011         if (a->uid_set != b->uid_set ||
1012             (a->uid_set && a->uid != b->uid))
1013             return false;
1014
1015         if (a->gid_set != b->gid_set ||
1016             (a->gid_set && a->gid != b->gid))
1017             return false;
1018
1019         if (a->mode_set != b->mode_set ||
1020             (a->mode_set && a->mode != b->mode))
1021             return false;
1022
1023         if (a->age_set != b->age_set ||
1024             (a->age_set && a->age != b->age))
1025             return false;
1026
1027         if ((a->type == CREATE_FILE ||
1028              a->type == TRUNCATE_FILE ||
1029              a->type == WRITE_FILE ||
1030              a->type == CREATE_SYMLINK) &&
1031             !streq_ptr(a->argument, b->argument))
1032                 return false;
1033
1034         if ((a->type == CREATE_CHAR_DEVICE ||
1035              a->type == CREATE_BLOCK_DEVICE) &&
1036             a->major_minor != b->major_minor)
1037                 return false;
1038
1039         return true;
1040 }
1041
1042 static bool should_include_path(const char *path) {
1043         char **prefix;
1044
1045         STRV_FOREACH(prefix, exclude_prefixes) {
1046                 if (path_startswith(path, *prefix))
1047                         return false;
1048         }
1049
1050         STRV_FOREACH(prefix, include_prefixes) {
1051                 if (path_startswith(path, *prefix))
1052                         return true;
1053         }
1054
1055         /* no matches, so we should include this path only if we
1056          * have no whitelist at all */
1057         return strv_length(include_prefixes) == 0;
1058 }
1059
1060 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1061
1062         static const Specifier specifier_table[] = {
1063                 { 'm', specifier_machine_id, NULL },
1064                 { 'b', specifier_boot_id, NULL },
1065                 { 'H', specifier_host_name, NULL },
1066                 { 'v', specifier_kernel_release, NULL },
1067                 {}
1068         };
1069
1070         _cleanup_item_free_ Item *i = NULL;
1071         Item *existing;
1072         _cleanup_free_ char
1073                 *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1074         char type;
1075         Hashmap *h;
1076         int r, n = -1;
1077
1078         assert(fname);
1079         assert(line >= 1);
1080         assert(buffer);
1081
1082         r = sscanf(buffer,
1083                    "%ms %ms %ms %ms %ms %ms %n",
1084                    &action,
1085                    &path,
1086                    &mode,
1087                    &user,
1088                    &group,
1089                    &age,
1090                    &n);
1091         if (r < 2) {
1092                 log_error("[%s:%u] Syntax error.", fname, line);
1093                 return -EIO;
1094         }
1095
1096         if (strlen(action) > 2 || (strlen(action) > 1 && action[1] != '!')) {
1097                 log_error("[%s:%u] Unknown modifier '%s'", fname, line, action);
1098                 return -EINVAL;
1099         } else if (strlen(action) > 1 && !arg_boot)
1100                 return 0;
1101
1102         type = action[0];
1103
1104         i = new0(Item, 1);
1105         if (!i)
1106                 return log_oom();
1107
1108         r = specifier_printf(path, specifier_table, NULL, &i->path);
1109         if (r < 0) {
1110                 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1111                 return r;
1112         }
1113
1114         if (n >= 0)  {
1115                 n += strspn(buffer+n, WHITESPACE);
1116                 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1117                         i->argument = unquote(buffer+n, "\"");
1118                         if (!i->argument)
1119                                 return log_oom();
1120                 }
1121         }
1122
1123         switch(type) {
1124
1125         case CREATE_FILE:
1126         case TRUNCATE_FILE:
1127         case CREATE_DIRECTORY:
1128         case TRUNCATE_DIRECTORY:
1129         case CREATE_FIFO:
1130         case IGNORE_PATH:
1131         case IGNORE_DIRECTORY_PATH:
1132         case REMOVE_PATH:
1133         case RECURSIVE_REMOVE_PATH:
1134         case RELABEL_PATH:
1135         case RECURSIVE_RELABEL_PATH:
1136         case ADJUST_MODE:
1137                 break;
1138
1139         case CREATE_SYMLINK:
1140                 if (!i->argument) {
1141                         log_error("[%s:%u] Symlink file requires argument.", fname, line);
1142                         return -EBADMSG;
1143                 }
1144                 break;
1145
1146         case WRITE_FILE:
1147                 if (!i->argument) {
1148                         log_error("[%s:%u] Write file requires argument.", fname, line);
1149                         return -EBADMSG;
1150                 }
1151                 break;
1152
1153         case CREATE_CHAR_DEVICE:
1154         case CREATE_BLOCK_DEVICE: {
1155                 unsigned major, minor;
1156
1157                 if (!i->argument) {
1158                         log_error("[%s:%u] Device file requires argument.", fname, line);
1159                         return -EBADMSG;
1160                 }
1161
1162                 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1163                         log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1164                         return -EBADMSG;
1165                 }
1166
1167                 i->major_minor = makedev(major, minor);
1168                 break;
1169         }
1170
1171         default:
1172                 log_error("[%s:%u] Unknown file type '%c'.", fname, line, type);
1173                 return -EBADMSG;
1174         }
1175
1176         i->type = type;
1177
1178         if (!path_is_absolute(i->path)) {
1179                 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1180                 return -EBADMSG;
1181         }
1182
1183         path_kill_slashes(i->path);
1184
1185         if (!should_include_path(i->path))
1186                 return 0;
1187
1188         if (arg_root) {
1189                 char *p = strappend(arg_root, i->path);
1190                 if (!p)
1191                         return log_oom();
1192
1193                 free(i->path);
1194                 i->path = p;
1195         }
1196
1197         if (user && !streq(user, "-")) {
1198                 const char *u = user;
1199
1200                 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1201                 if (r < 0) {
1202                         log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1203                         return r;
1204                 }
1205
1206                 i->uid_set = true;
1207         }
1208
1209         if (group && !streq(group, "-")) {
1210                 const char *g = group;
1211
1212                 r = get_group_creds(&g, &i->gid);
1213                 if (r < 0) {
1214                         log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1215                         return r;
1216                 }
1217
1218                 i->gid_set = true;
1219         }
1220
1221         if (mode && !streq(mode, "-")) {
1222                 unsigned m;
1223
1224                 if (sscanf(mode, "%o", &m) != 1) {
1225                         log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1226                         return -ENOENT;
1227                 }
1228
1229                 i->mode = m;
1230                 i->mode_set = true;
1231         } else
1232                 i->mode =
1233                         i->type == CREATE_DIRECTORY ||
1234                         i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1235
1236         if (age && !streq(age, "-")) {
1237                 const char *a = age;
1238
1239                 if (*a == '~') {
1240                         i->keep_first_level = true;
1241                         a++;
1242                 }
1243
1244                 if (parse_sec(a, &i->age) < 0) {
1245                         log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1246                         return -EBADMSG;
1247                 }
1248
1249                 i->age_set = true;
1250         }
1251
1252         h = needs_glob(i->type) ? globs : items;
1253
1254         existing = hashmap_get(h, i->path);
1255         if (existing) {
1256
1257                 /* Two identical items are fine */
1258                 if (!item_equal(existing, i))
1259                         log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1260
1261                 return 0;
1262         }
1263
1264         r = hashmap_put(h, i->path, i);
1265         if (r < 0) {
1266                 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1267                 return r;
1268         }
1269
1270         i = NULL; /* avoid cleanup */
1271
1272         return 0;
1273 }
1274
1275 static int help(void) {
1276
1277         printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1278                "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1279                "  -h --help                 Show this help\n"
1280                "     --version              Show package version\n"
1281                "     --create               Create marked files/directories\n"
1282                "     --clean                Clean up marked directories\n"
1283                "     --remove               Remove marked files/directories\n"
1284                "     --boot                 Execute actions only safe at boot\n"
1285                "     --prefix=PATH          Only apply rules that apply to paths with the specified prefix\n"
1286                "     --exclude-prefix=PATH  Ignore rules that apply to paths with the specified prefix\n"
1287                "     --root=PATH            Operate on an alternate filesystem root\n",
1288                program_invocation_short_name);
1289
1290         return 0;
1291 }
1292
1293 static int parse_argv(int argc, char *argv[]) {
1294
1295         enum {
1296                 ARG_VERSION = 0x100,
1297                 ARG_CREATE,
1298                 ARG_CLEAN,
1299                 ARG_REMOVE,
1300                 ARG_BOOT,
1301                 ARG_PREFIX,
1302                 ARG_EXCLUDE_PREFIX,
1303                 ARG_ROOT,
1304         };
1305
1306         static const struct option options[] = {
1307                 { "help",           no_argument,         NULL, 'h'                },
1308                 { "version",        no_argument,         NULL, ARG_VERSION        },
1309                 { "create",         no_argument,         NULL, ARG_CREATE         },
1310                 { "clean",          no_argument,         NULL, ARG_CLEAN          },
1311                 { "remove",         no_argument,         NULL, ARG_REMOVE         },
1312                 { "boot",           no_argument,         NULL, ARG_BOOT           },
1313                 { "prefix",         required_argument,   NULL, ARG_PREFIX         },
1314                 { "exclude-prefix", required_argument,   NULL, ARG_EXCLUDE_PREFIX },
1315                 { "root",           required_argument,   NULL, ARG_ROOT           },
1316                 {}
1317         };
1318
1319         int c;
1320
1321         assert(argc >= 0);
1322         assert(argv);
1323
1324         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
1325
1326                 switch (c) {
1327
1328                 case 'h':
1329                         return help();
1330
1331                 case ARG_VERSION:
1332                         puts(PACKAGE_STRING);
1333                         puts(SYSTEMD_FEATURES);
1334                         return 0;
1335
1336                 case ARG_CREATE:
1337                         arg_create = true;
1338                         break;
1339
1340                 case ARG_CLEAN:
1341                         arg_clean = true;
1342                         break;
1343
1344                 case ARG_REMOVE:
1345                         arg_remove = true;
1346                         break;
1347
1348                 case ARG_BOOT:
1349                         arg_boot = true;
1350                         break;
1351
1352                 case ARG_PREFIX:
1353                         if (strv_push(&include_prefixes, optarg) < 0)
1354                                 return log_oom();
1355                         break;
1356
1357                 case ARG_EXCLUDE_PREFIX:
1358                         if (strv_push(&exclude_prefixes, optarg) < 0)
1359                                 return log_oom();
1360                         break;
1361
1362                 case ARG_ROOT:
1363                         arg_root = path_make_absolute_cwd(optarg);
1364                         if (!arg_root)
1365                                 return log_oom();
1366                         path_kill_slashes(arg_root);
1367                         break;
1368
1369                 case '?':
1370                         return -EINVAL;
1371
1372                 default:
1373                         assert_not_reached("Unhandled option");
1374                 }
1375         }
1376
1377         if (!arg_clean && !arg_create && !arg_remove) {
1378                 log_error("You need to specify at least one of --clean, --create or --remove.");
1379                 return -EINVAL;
1380         }
1381
1382         return 1;
1383 }
1384
1385 static int read_config_file(const char *fn, bool ignore_enoent) {
1386         _cleanup_fclose_ FILE *f = NULL;
1387         char line[LINE_MAX];
1388         Iterator iterator;
1389         unsigned v = 0;
1390         Item *i;
1391         int r;
1392
1393         assert(fn);
1394
1395         r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1396         if (r < 0) {
1397                 if (ignore_enoent && r == -ENOENT)
1398                         return 0;
1399
1400                 log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
1401                 return r;
1402         }
1403
1404         FOREACH_LINE(line, f, break) {
1405                 char *l;
1406                 int k;
1407
1408                 v++;
1409
1410                 l = strstrip(line);
1411                 if (*l == '#' || *l == 0)
1412                         continue;
1413
1414                 k = parse_line(fn, v, l);
1415                 if (k < 0 && r == 0)
1416                         r = k;
1417         }
1418
1419         /* we have to determine age parameter for each entry of type X */
1420         HASHMAP_FOREACH(i, globs, iterator) {
1421                 Iterator iter;
1422                 Item *j, *candidate_item = NULL;
1423
1424                 if (i->type != IGNORE_DIRECTORY_PATH)
1425                         continue;
1426
1427                 HASHMAP_FOREACH(j, items, iter) {
1428                         if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY)
1429                                 continue;
1430
1431                         if (path_equal(j->path, i->path)) {
1432                                 candidate_item = j;
1433                                 break;
1434                         }
1435
1436                         if ((!candidate_item && path_startswith(i->path, j->path)) ||
1437                             (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1438                                 candidate_item = j;
1439                 }
1440
1441                 if (candidate_item) {
1442                         i->age = candidate_item->age;
1443                         i->age_set = true;
1444                 }
1445         }
1446
1447         if (ferror(f)) {
1448                 log_error("Failed to read from file %s: %m", fn);
1449                 if (r == 0)
1450                         r = -EIO;
1451         }
1452
1453         return r;
1454 }
1455
1456 int main(int argc, char *argv[]) {
1457         int r, k;
1458         Item *i;
1459         Iterator iterator;
1460
1461         r = parse_argv(argc, argv);
1462         if (r <= 0)
1463                 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1464
1465         log_set_target(LOG_TARGET_AUTO);
1466         log_parse_environment();
1467         log_open();
1468
1469         umask(0022);
1470
1471         label_init(NULL);
1472
1473         items = hashmap_new(string_hash_func, string_compare_func);
1474         globs = hashmap_new(string_hash_func, string_compare_func);
1475
1476         if (!items || !globs) {
1477                 r = log_oom();
1478                 goto finish;
1479         }
1480
1481         r = 0;
1482
1483         if (optind < argc) {
1484                 int j;
1485
1486                 for (j = optind; j < argc; j++) {
1487                         k = read_config_file(argv[j], false);
1488                         if (k < 0 && r == 0)
1489                                 r = k;
1490                 }
1491
1492         } else {
1493                 _cleanup_strv_free_ char **files = NULL;
1494                 char **f;
1495
1496                 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1497                 if (r < 0) {
1498                         log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1499                         goto finish;
1500                 }
1501
1502                 STRV_FOREACH(f, files) {
1503                         k = read_config_file(*f, true);
1504                         if (k < 0 && r == 0)
1505                                 r = k;
1506                 }
1507         }
1508
1509         HASHMAP_FOREACH(i, globs, iterator)
1510                 process_item(i);
1511
1512         HASHMAP_FOREACH(i, items, iterator)
1513                 process_item(i);
1514
1515 finish:
1516         while ((i = hashmap_steal_first(items)))
1517                 item_free(i);
1518
1519         while ((i = hashmap_steal_first(globs)))
1520                 item_free(i);
1521
1522         hashmap_free(items);
1523         hashmap_free(globs);
1524
1525         free(include_prefixes);
1526         free(exclude_prefixes);
1527         free(arg_root);
1528
1529         set_free_free(unix_sockets);
1530
1531         label_finish();
1532
1533         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1534 }