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