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