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