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