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