chiark / gitweb /
42cc34d6c41576ece05a1a9242cd7a22daaa67c2
[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
56 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
57  * them in the file system. This is intended to be used to create
58  * properly owned directories beneath /tmp, /var/tmp, /run, which are
59  * volatile and hence need to be recreated on bootup. */
60
61 typedef enum ItemType {
62         /* These ones take file names */
63         CREATE_FILE = 'f',
64         TRUNCATE_FILE = 'F',
65         WRITE_FILE = 'w',
66         CREATE_DIRECTORY = 'd',
67         TRUNCATE_DIRECTORY = 'D',
68         CREATE_FIFO = 'p',
69         CREATE_SYMLINK = 'L',
70         CREATE_CHAR_DEVICE = 'c',
71         CREATE_BLOCK_DEVICE = 'b',
72         ADJUST_MODE = 'm',
73
74         /* These ones take globs */
75         IGNORE_PATH = 'x',
76         IGNORE_DIRECTORY_PATH = 'X',
77         REMOVE_PATH = 'r',
78         RECURSIVE_REMOVE_PATH = 'R',
79         RELABEL_PATH = 'z',
80         RECURSIVE_RELABEL_PATH = 'Z'
81 } ItemType;
82
83 typedef struct Item {
84         ItemType type;
85
86         char *path;
87         char *argument;
88         uid_t uid;
89         gid_t gid;
90         mode_t mode;
91         usec_t age;
92
93         dev_t major_minor;
94
95         bool uid_set:1;
96         bool gid_set:1;
97         bool mode_set:1;
98         bool age_set:1;
99
100         bool keep_first_level:1;
101 } Item;
102
103 static Hashmap *items = NULL, *globs = NULL;
104 static Set *unix_sockets = NULL;
105
106 static bool arg_create = false;
107 static bool arg_clean = false;
108 static bool arg_remove = false;
109
110 static char **include_prefixes = NULL;
111 static char **exclude_prefixes = NULL;
112
113 static const char conf_file_dirs[] =
114         "/etc/tmpfiles.d\0"
115         "/run/tmpfiles.d\0"
116         "/usr/local/lib/tmpfiles.d\0"
117         "/usr/lib/tmpfiles.d\0"
118 #ifdef HAVE_SPLIT_USR
119         "/lib/tmpfiles.d\0"
120 #endif
121         ;
122
123 #define MAX_DEPTH 256
124
125 static bool needs_glob(ItemType t) {
126         return t == IGNORE_PATH || t == IGNORE_DIRECTORY_PATH || t == REMOVE_PATH || t == RECURSIVE_REMOVE_PATH || t == RELABEL_PATH || t == RECURSIVE_RELABEL_PATH;
127 }
128
129 static struct Item* find_glob(Hashmap *h, const char *match) {
130         Item *j;
131         Iterator i;
132
133         HASHMAP_FOREACH(j, h, i)
134                 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
135                         return j;
136
137         return NULL;
138 }
139
140 static void load_unix_sockets(void) {
141         _cleanup_fclose_ FILE *f = NULL;
142         char line[LINE_MAX];
143
144         if (unix_sockets)
145                 return;
146
147         /* We maintain a cache of the sockets we found in
148          * /proc/net/unix to speed things up a little. */
149
150         unix_sockets = set_new(string_hash_func, string_compare_func);
151         if (!unix_sockets)
152                 return;
153
154         f = fopen("/proc/net/unix", "re");
155         if (!f)
156                 return;
157
158         /* Skip header */
159         if (!fgets(line, sizeof(line), f))
160                 goto fail;
161
162         for (;;) {
163                 char *p, *s;
164                 int k;
165
166                 if (!fgets(line, sizeof(line), f))
167                         break;
168
169                 truncate_nl(line);
170
171                 p = strchr(line, ':');
172                 if (!p)
173                         continue;
174
175                 if (strlen(p) < 37)
176                         continue;
177
178                 p += 37;
179                 p += strspn(p, WHITESPACE);
180                 p += strcspn(p, WHITESPACE); /* skip one more word */
181                 p += strspn(p, WHITESPACE);
182
183                 if (*p != '/')
184                         continue;
185
186                 s = strdup(p);
187                 if (!s)
188                         goto fail;
189
190                 path_kill_slashes(s);
191
192                 k = set_consume(unix_sockets, s);
193                 if (k < 0 && k != -EEXIST)
194                         goto fail;
195         }
196
197         return;
198
199 fail:
200         set_free_free(unix_sockets);
201         unix_sockets = NULL;
202 }
203
204 static bool unix_socket_alive(const char *fn) {
205         assert(fn);
206
207         load_unix_sockets();
208
209         if (unix_sockets)
210                 return !!set_get(unix_sockets, (char*) fn);
211
212         /* We don't know, so assume yes */
213         return true;
214 }
215
216 static int dir_is_mount_point(DIR *d, const char *subdir) {
217         struct file_handle *h;
218         int mount_id_parent, mount_id;
219         int r_p, r;
220
221         h = alloca(MAX_HANDLE_SZ);
222
223         h->handle_bytes = MAX_HANDLE_SZ;
224         r_p = name_to_handle_at(dirfd(d), ".", h, &mount_id_parent, 0);
225         if (r_p < 0)
226                 r_p = -errno;
227
228         h->handle_bytes = MAX_HANDLE_SZ;
229         r = name_to_handle_at(dirfd(d), subdir, h, &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
279                         if (errno != ENOENT) {
280                                 log_error("stat(%s/%s) failed: %m", p, dent->d_name);
281                                 r = -errno;
282                         }
283
284                         continue;
285                 }
286
287                 /* Stay on the same filesystem */
288                 if (s.st_dev != rootdev)
289                         continue;
290
291                 /* Try to detect bind mounts of the same filesystem instance; they
292                  * do not differ in device major/minors. This type of query is not
293                  * supported on all kernels or filesystem types though. */
294                 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
295                         continue;
296
297                 /* Do not delete read-only files owned by root */
298                 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
299                         continue;
300
301                 if (asprintf(&sub_path, "%s/%s", p, dent->d_name) < 0) {
302                         r = log_oom();
303                         goto finish;
304                 }
305
306                 /* Is there an item configured for this path? */
307                 if (hashmap_get(items, sub_path))
308                         continue;
309
310                 if (find_glob(globs, sub_path))
311                         continue;
312
313                 if (S_ISDIR(s.st_mode)) {
314
315                         if (mountpoint &&
316                             streq(dent->d_name, "lost+found") &&
317                             s.st_uid == 0)
318                                 continue;
319
320                         if (maxdepth <= 0)
321                                 log_warning("Reached max depth on %s.", sub_path);
322                         else {
323                                 _cleanup_closedir_ DIR *sub_dir;
324                                 int q;
325
326                                 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
327                                 if (sub_dir == NULL) {
328                                         if (errno != ENOENT) {
329                                                 log_error("opendir(%s/%s) failed: %m", p, dent->d_name);
330                                                 r = -errno;
331                                         }
332
333                                         continue;
334                                 }
335
336                                 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
337
338                                 if (q < 0)
339                                         r = q;
340                         }
341
342                         /* Note: if you are wondering why we don't
343                          * support the sticky bit for excluding
344                          * directories from cleaning like we do it for
345                          * other file system objects: well, the sticky
346                          * bit already has a meaning for directories,
347                          * so we don't want to overload that. */
348
349                         if (keep_this_level)
350                                 continue;
351
352                         /* Ignore ctime, we change it when deleting */
353                         age = MAX(timespec_load(&s.st_mtim),
354                                   timespec_load(&s.st_atim));
355                         if (age >= cutoff)
356                                 continue;
357
358                         if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
359                                 log_debug("rmdir '%s'\n", sub_path);
360
361                                 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
362                                         if (errno != ENOENT && errno != ENOTEMPTY) {
363                                                 log_error("rmdir(%s): %m", sub_path);
364                                                 r = -errno;
365                                         }
366                                 }
367                         }
368
369                 } else {
370                         /* Skip files for which the sticky bit is
371                          * set. These are semantics we define, and are
372                          * unknown elsewhere. See XDG_RUNTIME_DIR
373                          * specification for details. */
374                         if (s.st_mode & S_ISVTX)
375                                 continue;
376
377                         if (mountpoint && S_ISREG(s.st_mode)) {
378                                 if (streq(dent->d_name, ".journal") &&
379                                     s.st_uid == 0)
380                                         continue;
381
382                                 if (streq(dent->d_name, "aquota.user") ||
383                                     streq(dent->d_name, "aquota.group"))
384                                         continue;
385                         }
386
387                         /* Ignore sockets that are listed in /proc/net/unix */
388                         if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
389                                 continue;
390
391                         /* Ignore device nodes */
392                         if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
393                                 continue;
394
395                         /* Keep files on this level around if this is
396                          * requested */
397                         if (keep_this_level)
398                                 continue;
399
400                         age = MAX3(timespec_load(&s.st_mtim),
401                                    timespec_load(&s.st_atim),
402                                    timespec_load(&s.st_ctim));
403
404                         if (age >= cutoff)
405                                 continue;
406
407                         log_debug("unlink '%s'\n", sub_path);
408
409                         if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
410                                 if (errno != ENOENT) {
411                                         log_error("unlink(%s): %m", sub_path);
412                                         r = -errno;
413                                 }
414                         }
415
416                         deleted = true;
417                 }
418         }
419
420 finish:
421         if (deleted) {
422                 /* Restore original directory timestamps */
423                 times[0] = ds->st_atim;
424                 times[1] = ds->st_mtim;
425
426                 if (futimens(dirfd(d), times) < 0)
427                         log_error("utimensat(%s): %m", p);
428         }
429
430         return r;
431 }
432
433 static int item_set_perms_full(Item *i, const char *path, bool ignore_enoent) {
434         int r;
435
436         /* not using i->path directly because it may be a glob */
437         if (i->mode_set)
438                 if (chmod(path, i->mode) < 0) {
439                         if (errno != ENOENT || !ignore_enoent) {
440                                 log_error("chmod(%s) failed: %m", path);
441                                 return -errno;
442                         }
443                 }
444
445         if (i->uid_set || i->gid_set)
446                 if (chown(path,
447                           i->uid_set ? i->uid : (uid_t) -1,
448                           i->gid_set ? i->gid : (gid_t) -1) < 0) {
449
450                         if (errno != ENOENT || !ignore_enoent) {
451                                 log_error("chown(%s) failed: %m", path);
452                                 return -errno;
453                         }
454                 }
455
456         r = label_fix(path, false, false);
457         return r == -ENOENT && ignore_enoent ? 0 : r;
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 r, e, fd, flags;
466         struct stat st;
467
468         flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
469                 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;
470
471         RUN_WITH_UMASK(0) {
472                 label_context_set(path, S_IFREG);
473                 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
474                 e = errno;
475                 label_context_clear();
476                 errno = e;
477         }
478
479         if (fd < 0) {
480                 if (i->type == WRITE_FILE && errno == ENOENT)
481                         return 0;
482
483                 log_error("Failed to create file %s: %m", path);
484                 return -errno;
485         }
486
487         if (i->argument) {
488                 ssize_t n;
489                 size_t l;
490                 _cleanup_free_ char *unescaped;
491
492                 unescaped = cunescape(i->argument);
493                 if (unescaped == NULL) {
494                         close_nointr_nofail(fd);
495                         return log_oom();
496                 }
497
498                 l = strlen(unescaped);
499                 n = write(fd, unescaped, l);
500
501                 if (n < 0 || (size_t) n < l) {
502                         log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
503                         close_nointr_nofail(fd);
504                         return n < 0 ? n : -EIO;
505                 }
506         }
507
508         close_nointr_nofail(fd);
509
510         if (stat(path, &st) < 0) {
511                 log_error("stat(%s) failed: %m", path);
512                 return -errno;
513         }
514
515         if (!S_ISREG(st.st_mode)) {
516                 log_error("%s is not a file.", path);
517                 return -EEXIST;
518         }
519
520         r = item_set_perms(i, path);
521         if (r < 0)
522                 return r;
523
524         return 0;
525 }
526
527 static int recursive_relabel_children(Item *i, const char *path) {
528         _cleanup_closedir_ DIR *d;
529         int ret = 0;
530
531         /* This returns the first error we run into, but nevertheless
532          * tries to go on */
533
534         d = opendir(path);
535         if (!d)
536                 return errno == ENOENT ? 0 : -errno;
537
538         for (;;) {
539                 struct dirent *de;
540                 union dirent_storage buf;
541                 bool is_dir;
542                 int r;
543                 _cleanup_free_ char *entry_path = NULL;
544
545                 r = readdir_r(d, &buf.de, &de);
546                 if (r != 0) {
547                         if (ret == 0)
548                                 ret = -r;
549                         break;
550                 }
551
552                 if (!de)
553                         break;
554
555                 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
556                         continue;
557
558                 if (asprintf(&entry_path, "%s/%s", path, de->d_name) < 0) {
559                         if (ret == 0)
560                                 ret = -ENOMEM;
561                         continue;
562                 }
563
564                 if (de->d_type == DT_UNKNOWN) {
565                         struct stat st;
566
567                         if (lstat(entry_path, &st) < 0) {
568                                 if (ret == 0 && errno != ENOENT)
569                                         ret = -errno;
570                                 continue;
571                         }
572
573                         is_dir = S_ISDIR(st.st_mode);
574
575                 } else
576                         is_dir = de->d_type == DT_DIR;
577
578                 r = item_set_perms(i, entry_path);
579                 if (r < 0) {
580                         if (ret == 0 && r != -ENOENT)
581                                 ret = r;
582                         continue;
583                 }
584
585                 if (is_dir) {
586                         r = recursive_relabel_children(i, entry_path);
587                         if (r < 0 && ret == 0)
588                                 ret = r;
589                 }
590         }
591
592         return ret;
593 }
594
595 static int recursive_relabel(Item *i, const char *path) {
596         int r;
597         struct stat st;
598
599         r = item_set_perms(i, path);
600         if (r < 0)
601                 return r;
602
603         if (lstat(path, &st) < 0)
604                 return -errno;
605
606         if (S_ISDIR(st.st_mode))
607                 r = recursive_relabel_children(i, path);
608
609         return r;
610 }
611
612 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
613         int r = 0, k;
614         _cleanup_globfree_ glob_t g = {};
615         char **fn;
616
617         errno = 0;
618         k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
619         if (k != 0)
620                 if (k != GLOB_NOMATCH) {
621                         if (errno > 0)
622                                 errno = EIO;
623
624                         log_error("glob(%s) failed: %m", i->path);
625                         return -errno;
626                 }
627
628         STRV_FOREACH(fn, g.gl_pathv) {
629                 k = action(i, *fn);
630                 if (k < 0)
631                         r = k;
632         }
633
634         return r;
635 }
636
637 static int create_item(Item *i) {
638         int r, e;
639         struct stat st;
640
641         assert(i);
642
643         switch (i->type) {
644
645         case IGNORE_PATH:
646         case IGNORE_DIRECTORY_PATH:
647         case REMOVE_PATH:
648         case RECURSIVE_REMOVE_PATH:
649                 return 0;
650
651         case CREATE_FILE:
652         case TRUNCATE_FILE:
653                 r = write_one_file(i, i->path);
654                 if (r < 0)
655                         return r;
656                 break;
657
658         case WRITE_FILE:
659                 r = glob_item(i, write_one_file);
660                 if (r < 0)
661                         return r;
662
663                 break;
664
665         case ADJUST_MODE:
666                 r = item_set_perms_full(i, i->path, true);
667                 if (r < 0)
668                         return r;
669
670                 break;
671
672         case TRUNCATE_DIRECTORY:
673         case CREATE_DIRECTORY:
674
675                 RUN_WITH_UMASK(0000) {
676                         mkdir_parents_label(i->path, 0755);
677                         r = mkdir(i->path, i->mode);
678                 }
679
680                 if (r < 0 && errno != EEXIST) {
681                         log_error("Failed to create directory %s: %m", i->path);
682                         return -errno;
683                 }
684
685                 if (stat(i->path, &st) < 0) {
686                         log_error("stat(%s) failed: %m", i->path);
687                         return -errno;
688                 }
689
690                 if (!S_ISDIR(st.st_mode)) {
691                         log_error("%s is not a directory.", i->path);
692                         return -EEXIST;
693                 }
694
695                 r = item_set_perms(i, i->path);
696                 if (r < 0)
697                         return r;
698
699                 break;
700
701         case CREATE_FIFO:
702
703                 RUN_WITH_UMASK(0000) {
704                         r = mkfifo(i->path, i->mode);
705                 }
706
707                 if (r < 0 && errno != EEXIST) {
708                         log_error("Failed to create fifo %s: %m", i->path);
709                         return -errno;
710                 }
711
712                 if (stat(i->path, &st) < 0) {
713                         log_error("stat(%s) failed: %m", i->path);
714                         return -errno;
715                 }
716
717                 if (!S_ISFIFO(st.st_mode)) {
718                         log_error("%s is not a fifo.", i->path);
719                         return -EEXIST;
720                 }
721
722                 r = item_set_perms(i, i->path);
723                 if (r < 0)
724                         return r;
725
726                 break;
727
728         case CREATE_SYMLINK: {
729                 char *x;
730
731                 label_context_set(i->path, S_IFLNK);
732                 r = symlink(i->argument, i->path);
733                 e = errno;
734                 label_context_clear();
735                 errno = e;
736
737                 if (r < 0 && errno != EEXIST) {
738                         log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
739                         return -errno;
740                 }
741
742                 r = readlink_malloc(i->path, &x);
743                 if (r < 0) {
744                         log_error("readlink(%s) failed: %s", i->path, strerror(-r));
745                         return -errno;
746                 }
747
748                 if (!streq(i->argument, x)) {
749                         free(x);
750                         log_error("%s is not the right symlinks.", i->path);
751                         return -EEXIST;
752                 }
753
754                 free(x);
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                 *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                    "%c %ms %ms %ms %ms %ms %n",
1084                    &type,
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         i = new0(Item, 1);
1097         if (!i)
1098                 return log_oom();
1099
1100         r = specifier_printf(path, specifier_table, NULL, &i->path);
1101         if (r < 0) {
1102                 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1103                 return r;
1104         }
1105
1106         if (n >= 0)  {
1107                 n += strspn(buffer+n, WHITESPACE);
1108                 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1109                         i->argument = unquote(buffer+n, "\"");
1110                         if (!i->argument)
1111                                 return log_oom();
1112                 }
1113         }
1114
1115         switch(type) {
1116
1117         case CREATE_FILE:
1118         case TRUNCATE_FILE:
1119         case CREATE_DIRECTORY:
1120         case TRUNCATE_DIRECTORY:
1121         case CREATE_FIFO:
1122         case IGNORE_PATH:
1123         case IGNORE_DIRECTORY_PATH:
1124         case REMOVE_PATH:
1125         case RECURSIVE_REMOVE_PATH:
1126         case RELABEL_PATH:
1127         case RECURSIVE_RELABEL_PATH:
1128         case ADJUST_MODE:
1129                 break;
1130
1131         case CREATE_SYMLINK:
1132                 if (!i->argument) {
1133                         log_error("[%s:%u] Symlink file requires argument.", fname, line);
1134                         return -EBADMSG;
1135                 }
1136                 break;
1137
1138         case WRITE_FILE:
1139                 if (!i->argument) {
1140                         log_error("[%s:%u] Write file requires argument.", fname, line);
1141                         return -EBADMSG;
1142                 }
1143                 break;
1144
1145         case CREATE_CHAR_DEVICE:
1146         case CREATE_BLOCK_DEVICE: {
1147                 unsigned major, minor;
1148
1149                 if (!i->argument) {
1150                         log_error("[%s:%u] Device file requires argument.", fname, line);
1151                         return -EBADMSG;
1152                 }
1153
1154                 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1155                         log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1156                         return -EBADMSG;
1157                 }
1158
1159                 i->major_minor = makedev(major, minor);
1160                 break;
1161         }
1162
1163         default:
1164                 log_error("[%s:%u] Unknown file type '%c'.", fname, line, type);
1165                 return -EBADMSG;
1166         }
1167
1168         i->type = type;
1169
1170         if (!path_is_absolute(i->path)) {
1171                 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1172                 return -EBADMSG;
1173         }
1174
1175         path_kill_slashes(i->path);
1176
1177         if (!should_include_path(i->path))
1178                 return 0;
1179
1180         if (user && !streq(user, "-")) {
1181                 const char *u = user;
1182
1183                 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1184                 if (r < 0) {
1185                         log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1186                         return r;
1187                 }
1188
1189                 i->uid_set = true;
1190         }
1191
1192         if (group && !streq(group, "-")) {
1193                 const char *g = group;
1194
1195                 r = get_group_creds(&g, &i->gid);
1196                 if (r < 0) {
1197                         log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1198                         return r;
1199                 }
1200
1201                 i->gid_set = true;
1202         }
1203
1204         if (mode && !streq(mode, "-")) {
1205                 unsigned m;
1206
1207                 if (sscanf(mode, "%o", &m) != 1) {
1208                         log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1209                         return -ENOENT;
1210                 }
1211
1212                 i->mode = m;
1213                 i->mode_set = true;
1214         } else
1215                 i->mode =
1216                         i->type == CREATE_DIRECTORY ||
1217                         i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1218
1219         if (age && !streq(age, "-")) {
1220                 const char *a = age;
1221
1222                 if (*a == '~') {
1223                         i->keep_first_level = true;
1224                         a++;
1225                 }
1226
1227                 if (parse_sec(a, &i->age) < 0) {
1228                         log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1229                         return -EBADMSG;
1230                 }
1231
1232                 i->age_set = true;
1233         }
1234
1235         h = needs_glob(i->type) ? globs : items;
1236
1237         existing = hashmap_get(h, i->path);
1238         if (existing) {
1239
1240                 /* Two identical items are fine */
1241                 if (!item_equal(existing, i))
1242                         log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1243
1244                 return 0;
1245         }
1246
1247         r = hashmap_put(h, i->path, i);
1248         if (r < 0) {
1249                 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1250                 return r;
1251         }
1252
1253         i = NULL; /* avoid cleanup */
1254
1255         return 0;
1256 }
1257
1258 static int help(void) {
1259
1260         printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1261                "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1262                "  -h --help                 Show this help\n"
1263                "     --create               Create marked files/directories\n"
1264                "     --clean                Clean up marked directories\n"
1265                "     --remove               Remove marked files/directories\n"
1266                "     --prefix=PATH          Only apply rules that apply to paths with the specified prefix\n"
1267                "     --exclude-prefix=PATH  Ignore rules that apply to paths with the specified prefix\n",
1268                program_invocation_short_name);
1269
1270         return 0;
1271 }
1272
1273 static int parse_argv(int argc, char *argv[]) {
1274
1275         enum {
1276                 ARG_CREATE,
1277                 ARG_CLEAN,
1278                 ARG_REMOVE,
1279                 ARG_PREFIX,
1280                 ARG_EXCLUDE_PREFIX,
1281         };
1282
1283         static const struct option options[] = {
1284                 { "help",           no_argument,         NULL, 'h'                },
1285                 { "create",         no_argument,         NULL, ARG_CREATE         },
1286                 { "clean",          no_argument,         NULL, ARG_CLEAN          },
1287                 { "remove",         no_argument,         NULL, ARG_REMOVE         },
1288                 { "prefix",         required_argument,   NULL, ARG_PREFIX         },
1289                 { "exclude-prefix", required_argument,   NULL, ARG_EXCLUDE_PREFIX },
1290                 { NULL,             0,                   NULL, 0                  }
1291         };
1292
1293         int c;
1294
1295         assert(argc >= 0);
1296         assert(argv);
1297
1298         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
1299
1300                 switch (c) {
1301
1302                 case 'h':
1303                         help();
1304                         return 0;
1305
1306                 case ARG_CREATE:
1307                         arg_create = true;
1308                         break;
1309
1310                 case ARG_CLEAN:
1311                         arg_clean = true;
1312                         break;
1313
1314                 case ARG_REMOVE:
1315                         arg_remove = true;
1316                         break;
1317
1318                 case ARG_PREFIX:
1319                         if (strv_extend(&include_prefixes, optarg) < 0)
1320                                 return log_oom();
1321                         break;
1322
1323                 case ARG_EXCLUDE_PREFIX:
1324                         if (strv_extend(&exclude_prefixes, optarg) < 0)
1325                                 return log_oom();
1326                         break;
1327
1328                 case '?':
1329                         return -EINVAL;
1330
1331                 default:
1332                         log_error("Unknown option code %c", c);
1333                         return -EINVAL;
1334                 }
1335         }
1336
1337         if (!arg_clean && !arg_create && !arg_remove) {
1338                 log_error("You need to specify at least one of --clean, --create or --remove.");
1339                 return -EINVAL;
1340         }
1341
1342         return 1;
1343 }
1344
1345 static int read_config_file(const char *fn, bool ignore_enoent) {
1346         _cleanup_fclose_ FILE *f = NULL;
1347         char line[LINE_MAX];
1348         Iterator iterator;
1349         unsigned v = 0;
1350         Item *i;
1351         int r;
1352
1353         assert(fn);
1354
1355         r = search_and_fopen_nulstr(fn, "re", conf_file_dirs, &f);
1356         if (r < 0) {
1357                 if (ignore_enoent && r == -ENOENT)
1358                         return 0;
1359
1360                 log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
1361                 return r;
1362         }
1363
1364         FOREACH_LINE(line, f, break) {
1365                 char *l;
1366                 int k;
1367
1368                 v++;
1369
1370                 l = strstrip(line);
1371                 if (*l == '#' || *l == 0)
1372                         continue;
1373
1374                 k = parse_line(fn, v, l);
1375                 if (k < 0 && r == 0)
1376                         r = k;
1377         }
1378
1379         /* we have to determine age parameter for each entry of type X */
1380         HASHMAP_FOREACH(i, globs, iterator) {
1381                 Iterator iter;
1382                 Item *j, *candidate_item = NULL;
1383
1384                 if (i->type != IGNORE_DIRECTORY_PATH)
1385                         continue;
1386
1387                 HASHMAP_FOREACH(j, items, iter) {
1388                         if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY)
1389                                 continue;
1390
1391                         if (path_equal(j->path, i->path)) {
1392                                 candidate_item = j;
1393                                 break;
1394                         }
1395
1396                         if ((!candidate_item && path_startswith(i->path, j->path)) ||
1397                             (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1398                                 candidate_item = j;
1399                 }
1400
1401                 if (candidate_item) {
1402                         i->age = candidate_item->age;
1403                         i->age_set = true;
1404                 }
1405         }
1406
1407         if (ferror(f)) {
1408                 log_error("Failed to read from file %s: %m", fn);
1409                 if (r == 0)
1410                         r = -EIO;
1411         }
1412
1413         return r;
1414 }
1415
1416 int main(int argc, char *argv[]) {
1417         int r, k;
1418         Item *i;
1419         Iterator iterator;
1420
1421         r = parse_argv(argc, argv);
1422         if (r <= 0)
1423                 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1424
1425         log_set_target(LOG_TARGET_AUTO);
1426         log_parse_environment();
1427         log_open();
1428
1429         umask(0022);
1430
1431         label_init(NULL);
1432
1433         items = hashmap_new(string_hash_func, string_compare_func);
1434         globs = hashmap_new(string_hash_func, string_compare_func);
1435
1436         if (!items || !globs) {
1437                 r = log_oom();
1438                 goto finish;
1439         }
1440
1441         r = 0;
1442
1443         if (optind < argc) {
1444                 int j;
1445
1446                 for (j = optind; j < argc; j++) {
1447                         k = read_config_file(argv[j], false);
1448                         if (k < 0 && r == 0)
1449                                 r = k;
1450                 }
1451
1452         } else {
1453                 _cleanup_strv_free_ char **files = NULL;
1454                 char **f;
1455
1456                 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
1457                 if (r < 0) {
1458                         log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1459                         goto finish;
1460                 }
1461
1462                 STRV_FOREACH(f, files) {
1463                         k = read_config_file(*f, true);
1464                         if (k < 0 && r == 0)
1465                                 r = k;
1466                 }
1467         }
1468
1469         HASHMAP_FOREACH(i, globs, iterator)
1470                 process_item(i);
1471
1472         HASHMAP_FOREACH(i, items, iterator)
1473                 process_item(i);
1474
1475 finish:
1476         while ((i = hashmap_steal_first(items)))
1477                 item_free(i);
1478
1479         while ((i = hashmap_steal_first(globs)))
1480                 item_free(i);
1481
1482         hashmap_free(items);
1483         hashmap_free(globs);
1484
1485         strv_free(include_prefixes);
1486
1487         set_free_free(unix_sockets);
1488
1489         label_finish();
1490
1491         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1492 }