chiark / gitweb /
841d1635239e25a81fc596c99dadb594be013f4d
[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);
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                 r = rm_rf(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
847                 if (r < 0 && r != -ENOENT) {
848                         log_error("rm_rf(%s): %s", instance, strerror(-r));
849                         return r;
850                 }
851
852                 break;
853         }
854
855         return 0;
856 }
857
858 static int remove_item(Item *i) {
859         int r = 0;
860
861         assert(i);
862
863         switch (i->type) {
864
865         case CREATE_FILE:
866         case TRUNCATE_FILE:
867         case CREATE_DIRECTORY:
868         case CREATE_FIFO:
869         case CREATE_SYMLINK:
870         case CREATE_CHAR_DEVICE:
871         case CREATE_BLOCK_DEVICE:
872         case IGNORE_PATH:
873         case RELABEL_PATH:
874         case RECURSIVE_RELABEL_PATH:
875         case WRITE_FILE:
876                 break;
877
878         case REMOVE_PATH:
879         case TRUNCATE_DIRECTORY:
880         case RECURSIVE_REMOVE_PATH:
881                 r = glob_item(i, remove_item_instance);
882                 break;
883         }
884
885         return r;
886 }
887
888 static int process_item(Item *i) {
889         int r, q, p;
890
891         assert(i);
892
893         r = arg_create ? create_item(i) : 0;
894         q = arg_remove ? remove_item(i) : 0;
895         p = arg_clean ? clean_item(i) : 0;
896
897         if (r < 0)
898                 return r;
899
900         if (q < 0)
901                 return q;
902
903         return p;
904 }
905
906 static void item_free(Item *i) {
907         assert(i);
908
909         free(i->path);
910         free(i->argument);
911         free(i);
912 }
913
914 static bool item_equal(Item *a, Item *b) {
915         assert(a);
916         assert(b);
917
918         if (!streq_ptr(a->path, b->path))
919                 return false;
920
921         if (a->type != b->type)
922                 return false;
923
924         if (a->uid_set != b->uid_set ||
925             (a->uid_set && a->uid != b->uid))
926             return false;
927
928         if (a->gid_set != b->gid_set ||
929             (a->gid_set && a->gid != b->gid))
930             return false;
931
932         if (a->mode_set != b->mode_set ||
933             (a->mode_set && a->mode != b->mode))
934             return false;
935
936         if (a->age_set != b->age_set ||
937             (a->age_set && a->age != b->age))
938             return false;
939
940         if ((a->type == CREATE_FILE ||
941              a->type == TRUNCATE_FILE ||
942              a->type == WRITE_FILE ||
943              a->type == CREATE_SYMLINK) &&
944             !streq_ptr(a->argument, b->argument))
945                 return false;
946
947         if ((a->type == CREATE_CHAR_DEVICE ||
948              a->type == CREATE_BLOCK_DEVICE) &&
949             a->major_minor != b->major_minor)
950                 return false;
951
952         return true;
953 }
954
955 static int parse_line(const char *fname, unsigned line, const char *buffer) {
956         Item *i, *existing;
957         char *mode = NULL, *user = NULL, *group = NULL, *age = NULL;
958         char type;
959         Hashmap *h;
960         int r, n = -1;
961
962         assert(fname);
963         assert(line >= 1);
964         assert(buffer);
965
966         i = new0(Item, 1);
967         if (!i) {
968                 log_error("Out of memory");
969                 return -ENOMEM;
970         }
971
972         if (sscanf(buffer,
973                    "%c "
974                    "%ms "
975                    "%ms "
976                    "%ms "
977                    "%ms "
978                    "%ms "
979                    "%n",
980                    &type,
981                    &i->path,
982                    &mode,
983                    &user,
984                    &group,
985                    &age,
986                    &n) < 2) {
987                 log_error("[%s:%u] Syntax error.", fname, line);
988                 r = -EIO;
989                 goto finish;
990         }
991
992         if (n >= 0)  {
993                 n += strspn(buffer+n, WHITESPACE);
994                 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
995                         i->argument = unquote(buffer+n, "\"");
996                         if (!i->argument) {
997                                 log_error("Out of memory");
998                                 return -ENOMEM;
999                         }
1000                 }
1001         }
1002
1003         switch(type) {
1004
1005         case CREATE_FILE:
1006         case TRUNCATE_FILE:
1007         case CREATE_DIRECTORY:
1008         case TRUNCATE_DIRECTORY:
1009         case CREATE_FIFO:
1010         case IGNORE_PATH:
1011         case REMOVE_PATH:
1012         case RECURSIVE_REMOVE_PATH:
1013         case RELABEL_PATH:
1014         case RECURSIVE_RELABEL_PATH:
1015                 break;
1016
1017         case CREATE_SYMLINK:
1018                 if (!i->argument) {
1019                         log_error("[%s:%u] Symlink file requires argument.", fname, line);
1020                         r = -EBADMSG;
1021                         goto finish;
1022                 }
1023                 break;
1024
1025         case WRITE_FILE:
1026                 if (!i->argument) {
1027                         log_error("[%s:%u] Write file requires argument.", fname, line);
1028                         r = -EBADMSG;
1029                         goto finish;
1030                 }
1031                 break;
1032
1033         case CREATE_CHAR_DEVICE:
1034         case CREATE_BLOCK_DEVICE: {
1035                 unsigned major, minor;
1036
1037                 if (!i->argument) {
1038                         log_error("[%s:%u] Device file requires argument.", fname, line);
1039                         r = -EBADMSG;
1040                         goto finish;
1041                 }
1042
1043                 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1044                         log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1045                         r = -EBADMSG;
1046                         goto finish;
1047                 }
1048
1049                 i->major_minor = makedev(major, minor);
1050                 break;
1051         }
1052
1053         default:
1054                 log_error("[%s:%u] Unknown file type '%c'.", fname, line, type);
1055                 r = -EBADMSG;
1056                 goto finish;
1057         }
1058
1059         i->type = type;
1060
1061         if (!path_is_absolute(i->path)) {
1062                 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1063                 r = -EBADMSG;
1064                 goto finish;
1065         }
1066
1067         path_kill_slashes(i->path);
1068
1069         if (arg_prefix && !path_startswith(i->path, arg_prefix)) {
1070                 r = 0;
1071                 goto finish;
1072         }
1073
1074         if (user && !streq(user, "-")) {
1075                 const char *u = user;
1076
1077                 r = get_user_creds(&u, &i->uid, NULL, NULL);
1078                 if (r < 0) {
1079                         log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1080                         goto finish;
1081                 }
1082
1083                 i->uid_set = true;
1084         }
1085
1086         if (group && !streq(group, "-")) {
1087                 const char *g = group;
1088
1089                 r = get_group_creds(&g, &i->gid);
1090                 if (r < 0) {
1091                         log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1092                         goto finish;
1093                 }
1094
1095                 i->gid_set = true;
1096         }
1097
1098         if (mode && !streq(mode, "-")) {
1099                 unsigned m;
1100
1101                 if (sscanf(mode, "%o", &m) != 1) {
1102                         log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1103                         r = -ENOENT;
1104                         goto finish;
1105                 }
1106
1107                 i->mode = m;
1108                 i->mode_set = true;
1109         } else
1110                 i->mode =
1111                         i->type == CREATE_DIRECTORY ||
1112                         i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1113
1114         if (age && !streq(age, "-")) {
1115                 const char *a = age;
1116
1117                 if (*a == '~') {
1118                         i->keep_first_level = true;
1119                         a++;
1120                 }
1121
1122                 if (parse_usec(a, &i->age) < 0) {
1123                         log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1124                         r = -EBADMSG;
1125                         goto finish;
1126                 }
1127
1128                 i->age_set = true;
1129         }
1130
1131         h = needs_glob(i->type) ? globs : items;
1132
1133         existing = hashmap_get(h, i->path);
1134         if (existing) {
1135
1136                 /* Two identical items are fine */
1137                 if (!item_equal(existing, i))
1138                         log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1139
1140                 r = 0;
1141                 goto finish;
1142         }
1143
1144         r = hashmap_put(h, i->path, i);
1145         if (r < 0) {
1146                 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1147                 goto finish;
1148         }
1149
1150         i = NULL;
1151         r = 0;
1152
1153 finish:
1154         free(user);
1155         free(group);
1156         free(mode);
1157         free(age);
1158
1159         if (i)
1160                 item_free(i);
1161
1162         return r;
1163 }
1164
1165 static int help(void) {
1166
1167         printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1168                "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1169                "  -h --help             Show this help\n"
1170                "     --create           Create marked files/directories\n"
1171                "     --clean            Clean up marked directories\n"
1172                "     --remove           Remove marked files/directories\n"
1173                "     --prefix=PATH      Only apply rules that apply to paths with the specified prefix\n",
1174                program_invocation_short_name);
1175
1176         return 0;
1177 }
1178
1179 static int parse_argv(int argc, char *argv[]) {
1180
1181         enum {
1182                 ARG_CREATE,
1183                 ARG_CLEAN,
1184                 ARG_REMOVE,
1185                 ARG_PREFIX
1186         };
1187
1188         static const struct option options[] = {
1189                 { "help",      no_argument,       NULL, 'h'           },
1190                 { "create",    no_argument,       NULL, ARG_CREATE    },
1191                 { "clean",     no_argument,       NULL, ARG_CLEAN     },
1192                 { "remove",    no_argument,       NULL, ARG_REMOVE    },
1193                 { "prefix",    required_argument, NULL, ARG_PREFIX    },
1194                 { NULL,        0,                 NULL, 0             }
1195         };
1196
1197         int c;
1198
1199         assert(argc >= 0);
1200         assert(argv);
1201
1202         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
1203
1204                 switch (c) {
1205
1206                 case 'h':
1207                         help();
1208                         return 0;
1209
1210                 case ARG_CREATE:
1211                         arg_create = true;
1212                         break;
1213
1214                 case ARG_CLEAN:
1215                         arg_clean = true;
1216                         break;
1217
1218                 case ARG_REMOVE:
1219                         arg_remove = true;
1220                         break;
1221
1222                 case ARG_PREFIX:
1223                         arg_prefix = optarg;
1224                         break;
1225
1226                 case '?':
1227                         return -EINVAL;
1228
1229                 default:
1230                         log_error("Unknown option code %c", c);
1231                         return -EINVAL;
1232                 }
1233         }
1234
1235         if (!arg_clean && !arg_create && !arg_remove) {
1236                 log_error("You need to specify at least one of --clean, --create or --remove.");
1237                 return -EINVAL;
1238         }
1239
1240         return 1;
1241 }
1242
1243 static int read_config_file(const char *fn, bool ignore_enoent) {
1244         FILE *f;
1245         unsigned v = 0;
1246         int r = 0;
1247
1248         assert(fn);
1249
1250         f = fopen(fn, "re");
1251         if (!f) {
1252
1253                 if (ignore_enoent && errno == ENOENT)
1254                         return 0;
1255
1256                 log_error("Failed to open %s: %m", fn);
1257                 return -errno;
1258         }
1259
1260         log_debug("apply: %s\n", fn);
1261         for (;;) {
1262                 char line[LINE_MAX], *l;
1263                 int k;
1264
1265                 if (!(fgets(line, sizeof(line), f)))
1266                         break;
1267
1268                 v++;
1269
1270                 l = strstrip(line);
1271                 if (*l == '#' || *l == 0)
1272                         continue;
1273
1274                 if ((k = parse_line(fn, v, l)) < 0)
1275                         if (r == 0)
1276                                 r = k;
1277         }
1278
1279         if (ferror(f)) {
1280                 log_error("Failed to read from file %s: %m", fn);
1281                 if (r == 0)
1282                         r = -EIO;
1283         }
1284
1285         fclose(f);
1286
1287         return r;
1288 }
1289
1290 static char *resolve_fragment(const char *fragment, const char **search_paths) {
1291         const char **p;
1292         char *resolved_path;
1293
1294         if (is_path(fragment))
1295                 return strdup(fragment);
1296
1297         STRV_FOREACH(p, search_paths) {
1298                 resolved_path = join(*p, "/", fragment, NULL);
1299                 if (resolved_path == NULL) {
1300                         log_error("Out of memory");
1301                         return NULL;
1302                 }
1303
1304                 if (access(resolved_path, F_OK) == 0)
1305                         return resolved_path;
1306
1307                 free(resolved_path);
1308         }
1309
1310         errno = ENOENT;
1311         return NULL;
1312 }
1313
1314 int main(int argc, char *argv[]) {
1315         int r;
1316         Item *i;
1317         Iterator iterator;
1318
1319         r = parse_argv(argc, argv);
1320         if (r <= 0)
1321                 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1322
1323         log_set_target(LOG_TARGET_AUTO);
1324         log_parse_environment();
1325         log_open();
1326
1327         umask(0022);
1328
1329         label_init(NULL);
1330
1331         items = hashmap_new(string_hash_func, string_compare_func);
1332         globs = hashmap_new(string_hash_func, string_compare_func);
1333
1334         if (!items || !globs) {
1335                 log_error("Out of memory");
1336                 r = EXIT_FAILURE;
1337                 goto finish;
1338         }
1339
1340         r = EXIT_SUCCESS;
1341
1342         if (optind < argc) {
1343                 int j;
1344
1345                 for (j = optind; j < argc; j++) {
1346                         char *fragment;
1347
1348                         fragment = resolve_fragment(argv[j], (const char**) conf_file_dirs);
1349                         if (!fragment) {
1350                                 log_error("Failed to find a %s file: %m", argv[j]);
1351                                 r = EXIT_FAILURE;
1352                                 goto finish;
1353                         }
1354                         if (read_config_file(fragment, false) < 0)
1355                                 r = EXIT_FAILURE;
1356                         free(fragment);
1357                 }
1358
1359         } else {
1360                 char **files, **f;
1361
1362                 r = conf_files_list_strv(&files, ".conf",
1363                                     (const char **) conf_file_dirs);
1364                 if (r < 0) {
1365                         log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1366                         r = EXIT_FAILURE;
1367                         goto finish;
1368                 }
1369
1370                 STRV_FOREACH(f, files) {
1371                         if (read_config_file(*f, true) < 0)
1372                                 r = EXIT_FAILURE;
1373                 }
1374
1375                 strv_free(files);
1376         }
1377
1378         HASHMAP_FOREACH(i, globs, iterator)
1379                 process_item(i);
1380
1381         HASHMAP_FOREACH(i, items, iterator)
1382                 process_item(i);
1383
1384 finish:
1385         while ((i = hashmap_steal_first(items)))
1386                 item_free(i);
1387
1388         while ((i = hashmap_steal_first(globs)))
1389                 item_free(i);
1390
1391         hashmap_free(items);
1392         hashmap_free(globs);
1393
1394         set_free_free(unix_sockets);
1395
1396         label_finish();
1397
1398         return r;
1399 }