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