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