chiark / gitweb /
log.h: new log_oom() -> int -ENOMEM, use it
[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 #ifdef HAVE_SPLIT_USR
111         "/lib/tmpfiles.d",
112 #endif
113         NULL
114 };
115
116 #define MAX_DEPTH 256
117
118 static bool needs_glob(ItemType t) {
119         return t == IGNORE_PATH || t == REMOVE_PATH || t == RECURSIVE_REMOVE_PATH || t == RELABEL_PATH || t == RECURSIVE_RELABEL_PATH;
120 }
121
122 static struct Item* find_glob(Hashmap *h, const char *match) {
123         Item *j;
124         Iterator i;
125
126         HASHMAP_FOREACH(j, h, i)
127                 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
128                         return j;
129
130         return NULL;
131 }
132
133 static void load_unix_sockets(void) {
134         FILE *f = NULL;
135         char line[LINE_MAX];
136
137         if (unix_sockets)
138                 return;
139
140         /* We maintain a cache of the sockets we found in
141          * /proc/net/unix to speed things up a little. */
142
143         unix_sockets = set_new(string_hash_func, string_compare_func);
144         if (!unix_sockets)
145                 return;
146
147         f = fopen("/proc/net/unix", "re");
148         if (!f)
149                 return;
150
151         /* Skip header */
152         if (!fgets(line, sizeof(line), f))
153                 goto fail;
154
155         for (;;) {
156                 char *p, *s;
157                 int k;
158
159                 if (!fgets(line, sizeof(line), f))
160                         break;
161
162                 truncate_nl(line);
163
164                 p = strchr(line, ':');
165                 if (!p)
166                         continue;
167
168                 if (strlen(p) < 37)
169                         continue;
170
171                 p += 37;
172                 p += strspn(p, WHITESPACE);
173                 p += strcspn(p, WHITESPACE); /* skip one more word */
174                 p += strspn(p, WHITESPACE);
175
176                 if (*p != '/')
177                         continue;
178
179                 s = strdup(p);
180                 if (!s)
181                         goto fail;
182
183                 path_kill_slashes(s);
184
185                 k = set_put(unix_sockets, s);
186                 if (k < 0) {
187                         free(s);
188
189                         if (k != -EEXIST)
190                                 goto fail;
191                 }
192         }
193
194         fclose(f);
195         return;
196
197 fail:
198         set_free_free(unix_sockets);
199         unix_sockets = NULL;
200
201         if (f)
202                 fclose(f);
203 }
204
205 static bool unix_socket_alive(const char *fn) {
206         assert(fn);
207
208         load_unix_sockets();
209
210         if (unix_sockets)
211                 return !!set_get(unix_sockets, (char*) fn);
212
213         /* We don't know, so assume yes */
214         return true;
215 }
216
217 static int dir_cleanup(
218                 const char *p,
219                 DIR *d,
220                 const struct stat *ds,
221                 usec_t cutoff,
222                 dev_t rootdev,
223                 bool mountpoint,
224                 int maxdepth,
225                 bool keep_this_level)
226 {
227         struct dirent *dent;
228         struct timespec times[2];
229         bool deleted = false;
230         char *sub_path = NULL;
231         int r = 0;
232
233         while ((dent = readdir(d))) {
234                 struct stat s;
235                 usec_t age;
236
237                 if (streq(dent->d_name, ".") ||
238                     streq(dent->d_name, ".."))
239                         continue;
240
241                 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
242
243                         if (errno != ENOENT) {
244                                 log_error("stat(%s/%s) failed: %m", p, dent->d_name);
245                                 r = -errno;
246                         }
247
248                         continue;
249                 }
250
251                 /* Stay on the same filesystem */
252                 if (s.st_dev != rootdev)
253                         continue;
254
255                 /* Do not delete read-only files owned by root */
256                 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
257                         continue;
258
259                 free(sub_path);
260                 sub_path = NULL;
261
262                 if (asprintf(&sub_path, "%s/%s", p, dent->d_name) < 0) {
263                         r = log_oom();
264                         goto finish;
265                 }
266
267                 /* Is there an item configured for this path? */
268                 if (hashmap_get(items, sub_path))
269                         continue;
270
271                 if (find_glob(globs, sub_path))
272                         continue;
273
274                 if (S_ISDIR(s.st_mode)) {
275
276                         if (mountpoint &&
277                             streq(dent->d_name, "lost+found") &&
278                             s.st_uid == 0)
279                                 continue;
280
281                         if (maxdepth <= 0)
282                                 log_warning("Reached max depth on %s.", sub_path);
283                         else {
284                                 DIR *sub_dir;
285                                 int q;
286
287                                 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
288                                 if (sub_dir == NULL) {
289                                         if (errno != ENOENT) {
290                                                 log_error("opendir(%s/%s) failed: %m", p, dent->d_name);
291                                                 r = -errno;
292                                         }
293
294                                         continue;
295                                 }
296
297                                 q = dir_cleanup(sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
298                                 closedir(sub_dir);
299
300                                 if (q < 0)
301                                         r = q;
302                         }
303
304                         /* Note: if you are wondering why we don't
305                          * support the sticky bit for excluding
306                          * directories from cleaning like we do it for
307                          * other file system objects: well, the sticky
308                          * bit already has a meaning for directories,
309                          * so we don't want to overload that. */
310
311                         if (keep_this_level)
312                                 continue;
313
314                         /* Ignore ctime, we change it when deleting */
315                         age = MAX(timespec_load(&s.st_mtim),
316                                   timespec_load(&s.st_atim));
317                         if (age >= cutoff)
318                                 continue;
319
320                         log_debug("rmdir '%s'\n", sub_path);
321
322                         if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
323                                 if (errno != ENOENT && errno != ENOTEMPTY) {
324                                         log_error("rmdir(%s): %m", sub_path);
325                                         r = -errno;
326                                 }
327                         }
328
329                 } else {
330                         /* Skip files for which the sticky bit is
331                          * set. These are semantics we define, and are
332                          * unknown elsewhere. See XDG_RUNTIME_DIR
333                          * specification for details. */
334                         if (s.st_mode & S_ISVTX)
335                                 continue;
336
337                         if (mountpoint && S_ISREG(s.st_mode)) {
338                                 if (streq(dent->d_name, ".journal") &&
339                                     s.st_uid == 0)
340                                         continue;
341
342                                 if (streq(dent->d_name, "aquota.user") ||
343                                     streq(dent->d_name, "aquota.group"))
344                                         continue;
345                         }
346
347                         /* Ignore sockets that are listed in /proc/net/unix */
348                         if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
349                                 continue;
350
351                         /* Ignore device nodes */
352                         if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
353                                 continue;
354
355                         /* Keep files on this level around if this is
356                          * requested */
357                         if (keep_this_level)
358                                 continue;
359
360                         age = MAX3(timespec_load(&s.st_mtim),
361                                    timespec_load(&s.st_atim),
362                                    timespec_load(&s.st_ctim));
363
364                         if (age >= cutoff)
365                                 continue;
366
367                         log_debug("unlink '%s'\n", sub_path);
368
369                         if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
370                                 if (errno != ENOENT) {
371                                         log_error("unlink(%s): %m", sub_path);
372                                         r = -errno;
373                                 }
374                         }
375
376                         deleted = true;
377                 }
378         }
379
380 finish:
381         if (deleted) {
382                 /* Restore original directory timestamps */
383                 times[0] = ds->st_atim;
384                 times[1] = ds->st_mtim;
385
386                 if (futimens(dirfd(d), times) < 0)
387                         log_error("utimensat(%s): %m", p);
388         }
389
390         free(sub_path);
391
392         return r;
393 }
394
395 static int clean_item(Item *i) {
396         DIR *d;
397         struct stat s, ps;
398         bool mountpoint;
399         int r;
400         usec_t cutoff, n;
401
402         assert(i);
403
404         if (i->type != CREATE_DIRECTORY &&
405             i->type != TRUNCATE_DIRECTORY &&
406             i->type != IGNORE_PATH)
407                 return 0;
408
409         if (!i->age_set || i->age <= 0)
410                 return 0;
411
412         n = now(CLOCK_REALTIME);
413         if (n < i->age)
414                 return 0;
415
416         cutoff = n - i->age;
417
418         d = opendir(i->path);
419         if (!d) {
420                 if (errno == ENOENT)
421                         return 0;
422
423                 log_error("Failed to open directory %s: %m", i->path);
424                 return -errno;
425         }
426
427         if (fstat(dirfd(d), &s) < 0) {
428                 log_error("stat(%s) failed: %m", i->path);
429                 r = -errno;
430                 goto finish;
431         }
432
433         if (!S_ISDIR(s.st_mode)) {
434                 log_error("%s is not a directory.", i->path);
435                 r = -ENOTDIR;
436                 goto finish;
437         }
438
439         if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) {
440                 log_error("stat(%s/..) failed: %m", i->path);
441                 r = -errno;
442                 goto finish;
443         }
444
445         mountpoint = s.st_dev != ps.st_dev ||
446                      (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
447
448         r = dir_cleanup(i->path, d, &s, cutoff, s.st_dev, mountpoint, MAX_DEPTH, i->keep_first_level);
449
450 finish:
451         if (d)
452                 closedir(d);
453
454         return r;
455 }
456
457 static int item_set_perms(Item *i, const char *path) {
458         /* not using i->path directly because it may be a glob */
459         if (i->mode_set)
460                 if (chmod(path, i->mode) < 0) {
461                         log_error("chmod(%s) failed: %m", path);
462                         return -errno;
463                 }
464
465         if (i->uid_set || i->gid_set)
466                 if (chown(path,
467                           i->uid_set ? i->uid : (uid_t) -1,
468                           i->gid_set ? i->gid : (gid_t) -1) < 0) {
469
470                         log_error("chown(%s) failed: %m", path);
471                         return -errno;
472                 }
473
474         return label_fix(path, false, false);
475 }
476
477 static int recursive_relabel_children(Item *i, const char *path) {
478         DIR *d;
479         int ret = 0;
480
481         /* This returns the first error we run into, but nevertheless
482          * tries to go on */
483
484         d = opendir(path);
485         if (!d)
486                 return errno == ENOENT ? 0 : -errno;
487
488         for (;;) {
489                 struct dirent buf, *de;
490                 bool is_dir;
491                 int r;
492                 char *entry_path;
493
494                 r = readdir_r(d, &buf, &de);
495                 if (r != 0) {
496                         if (ret == 0)
497                                 ret = -r;
498                         break;
499                 }
500
501                 if (!de)
502                         break;
503
504                 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
505                         continue;
506
507                 if (asprintf(&entry_path, "%s/%s", path, de->d_name) < 0) {
508                         if (ret == 0)
509                                 ret = -ENOMEM;
510                         continue;
511                 }
512
513                 if (de->d_type == DT_UNKNOWN) {
514                         struct stat st;
515
516                         if (lstat(entry_path, &st) < 0) {
517                                 if (ret == 0 && errno != ENOENT)
518                                         ret = -errno;
519                                 free(entry_path);
520                                 continue;
521                         }
522
523                         is_dir = S_ISDIR(st.st_mode);
524
525                 } else
526                         is_dir = de->d_type == DT_DIR;
527
528                 r = item_set_perms(i, entry_path);
529                 if (r < 0) {
530                         if (ret == 0 && r != -ENOENT)
531                                 ret = r;
532                         free(entry_path);
533                         continue;
534                 }
535
536                 if (is_dir) {
537                         r = recursive_relabel_children(i, entry_path);
538                         if (r < 0 && ret == 0)
539                                 ret = r;
540                 }
541
542                 free(entry_path);
543         }
544
545         closedir(d);
546
547         return ret;
548 }
549
550 static int recursive_relabel(Item *i, const char *path) {
551         int r;
552         struct stat st;
553
554         r = item_set_perms(i, path);
555         if (r < 0)
556                 return r;
557
558         if (lstat(path, &st) < 0)
559                 return -errno;
560
561         if (S_ISDIR(st.st_mode))
562                 r = recursive_relabel_children(i, path);
563
564         return r;
565 }
566
567 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
568         int r = 0, k;
569         glob_t g;
570         char **fn;
571
572         zero(g);
573
574         errno = 0;
575         if ((k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g)) != 0) {
576
577                 if (k != GLOB_NOMATCH) {
578                         if (errno != 0)
579                                 errno = EIO;
580
581                         log_error("glob(%s) failed: %m", i->path);
582                         return -errno;
583                 }
584         }
585
586         STRV_FOREACH(fn, g.gl_pathv)
587                 if ((k = action(i, *fn)) < 0)
588                         r = k;
589
590         globfree(&g);
591         return r;
592 }
593
594 static int create_item(Item *i) {
595         int r, e;
596         mode_t u;
597         struct stat st;
598
599         assert(i);
600
601         switch (i->type) {
602
603         case IGNORE_PATH:
604         case REMOVE_PATH:
605         case RECURSIVE_REMOVE_PATH:
606                 return 0;
607
608         case CREATE_FILE:
609         case TRUNCATE_FILE:
610         case WRITE_FILE: {
611                 int fd, flags;
612
613                 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
614                         i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;
615
616                 u = umask(0);
617                 label_context_set(i->path, S_IFREG);
618                 fd = open(i->path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
619                 e = errno;
620                 label_context_clear();
621                 umask(u);
622                 errno = e;
623
624                 if (fd < 0) {
625                         if (i->type == WRITE_FILE && errno == ENOENT)
626                                 break;
627
628                         log_error("Failed to create file %s: %m", i->path);
629                         return -errno;
630                 }
631
632                 if (i->argument) {
633                         ssize_t n;
634                         size_t l;
635                         struct iovec iovec[2];
636                         static const char new_line = '\n';
637
638                         l = strlen(i->argument);
639
640                         zero(iovec);
641                         iovec[0].iov_base = i->argument;
642                         iovec[0].iov_len = l;
643
644                         iovec[1].iov_base = (void*) &new_line;
645                         iovec[1].iov_len = 1;
646
647                         n = writev(fd, iovec, 2);
648
649                         /* It's OK if we don't write the trailing
650                          * newline, hence we check for l, instead of
651                          * l+1 here. Files in /sys often refuse
652                          * writing of the trailing newline. */
653                         if (n < 0 || (size_t) n < l) {
654                                 log_error("Failed to write file %s: %s", i->path, n < 0 ? strerror(-n) : "Short write");
655                                 close_nointr_nofail(fd);
656                                 return n < 0 ? n : -EIO;
657                         }
658                 }
659
660                 close_nointr_nofail(fd);
661
662                 if (stat(i->path, &st) < 0) {
663                         log_error("stat(%s) failed: %m", i->path);
664                         return -errno;
665                 }
666
667                 if (!S_ISREG(st.st_mode)) {
668                         log_error("%s is not a file.", i->path);
669                         return -EEXIST;
670                 }
671
672                 r = item_set_perms(i, i->path);
673                 if (r < 0)
674                         return r;
675
676                 break;
677         }
678
679         case TRUNCATE_DIRECTORY:
680         case CREATE_DIRECTORY:
681
682                 u = umask(0);
683                 mkdir_parents_label(i->path, 0755);
684                 r = mkdir(i->path, i->mode);
685                 umask(u);
686
687                 if (r < 0 && errno != EEXIST) {
688                         log_error("Failed to create directory %s: %m", i->path);
689                         return -errno;
690                 }
691
692                 if (stat(i->path, &st) < 0) {
693                         log_error("stat(%s) failed: %m", i->path);
694                         return -errno;
695                 }
696
697                 if (!S_ISDIR(st.st_mode)) {
698                         log_error("%s is not a directory.", i->path);
699                         return -EEXIST;
700                 }
701
702                 r = item_set_perms(i, i->path);
703                 if (r < 0)
704                         return r;
705
706                 break;
707
708         case CREATE_FIFO:
709
710                 u = umask(0);
711                 r = mkfifo(i->path, i->mode);
712                 umask(u);
713
714                 if (r < 0 && errno != EEXIST) {
715                         log_error("Failed to create fifo %s: %m", i->path);
716                         return -errno;
717                 }
718
719                 if (stat(i->path, &st) < 0) {
720                         log_error("stat(%s) failed: %m", i->path);
721                         return -errno;
722                 }
723
724                 if (!S_ISFIFO(st.st_mode)) {
725                         log_error("%s is not a fifo.", i->path);
726                         return -EEXIST;
727                 }
728
729                 r = item_set_perms(i, i->path);
730                 if (r < 0)
731                         return r;
732
733                 break;
734
735         case CREATE_SYMLINK: {
736                 char *x;
737
738                 label_context_set(i->path, S_IFLNK);
739                 r = symlink(i->argument, i->path);
740                 e = errno;
741                 label_context_clear();
742                 errno = e;
743
744                 if (r < 0 && errno != EEXIST) {
745                         log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
746                         return -errno;
747                 }
748
749                 r = readlink_malloc(i->path, &x);
750                 if (r < 0) {
751                         log_error("readlink(%s) failed: %s", i->path, strerror(-r));
752                         return -errno;
753                 }
754
755                 if (!streq(i->argument, x)) {
756                         free(x);
757                         log_error("%s is not the right symlinks.", i->path);
758                         return -EEXIST;
759                 }
760
761                 free(x);
762                 break;
763         }
764
765         case CREATE_BLOCK_DEVICE:
766         case CREATE_CHAR_DEVICE: {
767                 mode_t file_type = (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);
768
769                 u = umask(0);
770                 label_context_set(i->path, file_type);
771                 r = mknod(i->path, i->mode | file_type, i->major_minor);
772                 e = errno;
773                 label_context_clear();
774                 umask(u);
775                 errno = e;
776
777                 if (r < 0 && errno != EEXIST) {
778                         log_error("Failed to create device node %s: %m", i->path);
779                         return -errno;
780                 }
781
782                 if (stat(i->path, &st) < 0) {
783                         log_error("stat(%s) failed: %m", i->path);
784                         return -errno;
785                 }
786
787                 if ((st.st_mode & S_IFMT) != file_type) {
788                         log_error("%s is not a device node.", i->path);
789                         return -EEXIST;
790                 }
791
792                 r = item_set_perms(i, i->path);
793                 if (r < 0)
794                         return r;
795
796                 break;
797         }
798
799         case RELABEL_PATH:
800
801                 r = glob_item(i, item_set_perms);
802                 if (r < 0)
803                         return 0;
804                 break;
805
806         case RECURSIVE_RELABEL_PATH:
807
808                 r = glob_item(i, recursive_relabel);
809                 if (r < 0)
810                         return r;
811         }
812
813         log_debug("%s created successfully.", i->path);
814
815         return 0;
816 }
817
818 static int remove_item_instance(Item *i, const char *instance) {
819         int r;
820
821         assert(i);
822
823         switch (i->type) {
824
825         case CREATE_FILE:
826         case TRUNCATE_FILE:
827         case CREATE_DIRECTORY:
828         case CREATE_FIFO:
829         case CREATE_SYMLINK:
830         case CREATE_BLOCK_DEVICE:
831         case CREATE_CHAR_DEVICE:
832         case IGNORE_PATH:
833         case RELABEL_PATH:
834         case RECURSIVE_RELABEL_PATH:
835         case WRITE_FILE:
836                 break;
837
838         case REMOVE_PATH:
839                 if (remove(instance) < 0 && errno != ENOENT) {
840                         log_error("remove(%s): %m", instance);
841                         return -errno;
842                 }
843
844                 break;
845
846         case TRUNCATE_DIRECTORY:
847         case RECURSIVE_REMOVE_PATH:
848                 /* FIXME: we probably should use dir_cleanup() here
849                  * instead of rm_rf() so that 'x' is honoured. */
850                 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
851                 if (r < 0 && r != -ENOENT) {
852                         log_error("rm_rf(%s): %s", instance, strerror(-r));
853                         return r;
854                 }
855
856                 break;
857         }
858
859         return 0;
860 }
861
862 static int remove_item(Item *i) {
863         int r = 0;
864
865         assert(i);
866
867         switch (i->type) {
868
869         case CREATE_FILE:
870         case TRUNCATE_FILE:
871         case CREATE_DIRECTORY:
872         case CREATE_FIFO:
873         case CREATE_SYMLINK:
874         case CREATE_CHAR_DEVICE:
875         case CREATE_BLOCK_DEVICE:
876         case IGNORE_PATH:
877         case RELABEL_PATH:
878         case RECURSIVE_RELABEL_PATH:
879         case WRITE_FILE:
880                 break;
881
882         case REMOVE_PATH:
883         case TRUNCATE_DIRECTORY:
884         case RECURSIVE_REMOVE_PATH:
885                 r = glob_item(i, remove_item_instance);
886                 break;
887         }
888
889         return r;
890 }
891
892 static int process_item(Item *i) {
893         int r, q, p;
894
895         assert(i);
896
897         r = arg_create ? create_item(i) : 0;
898         q = arg_remove ? remove_item(i) : 0;
899         p = arg_clean ? clean_item(i) : 0;
900
901         if (r < 0)
902                 return r;
903
904         if (q < 0)
905                 return q;
906
907         return p;
908 }
909
910 static void item_free(Item *i) {
911         assert(i);
912
913         free(i->path);
914         free(i->argument);
915         free(i);
916 }
917
918 static bool item_equal(Item *a, Item *b) {
919         assert(a);
920         assert(b);
921
922         if (!streq_ptr(a->path, b->path))
923                 return false;
924
925         if (a->type != b->type)
926                 return false;
927
928         if (a->uid_set != b->uid_set ||
929             (a->uid_set && a->uid != b->uid))
930             return false;
931
932         if (a->gid_set != b->gid_set ||
933             (a->gid_set && a->gid != b->gid))
934             return false;
935
936         if (a->mode_set != b->mode_set ||
937             (a->mode_set && a->mode != b->mode))
938             return false;
939
940         if (a->age_set != b->age_set ||
941             (a->age_set && a->age != b->age))
942             return false;
943
944         if ((a->type == CREATE_FILE ||
945              a->type == TRUNCATE_FILE ||
946              a->type == WRITE_FILE ||
947              a->type == CREATE_SYMLINK) &&
948             !streq_ptr(a->argument, b->argument))
949                 return false;
950
951         if ((a->type == CREATE_CHAR_DEVICE ||
952              a->type == CREATE_BLOCK_DEVICE) &&
953             a->major_minor != b->major_minor)
954                 return false;
955
956         return true;
957 }
958
959 static int parse_line(const char *fname, unsigned line, const char *buffer) {
960         Item *i, *existing;
961         char *mode = NULL, *user = NULL, *group = NULL, *age = NULL;
962         char type;
963         Hashmap *h;
964         int r, n = -1;
965
966         assert(fname);
967         assert(line >= 1);
968         assert(buffer);
969
970         i = new0(Item, 1);
971         if (!i)
972                 return log_oom();
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                                 return log_oom();
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, 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 = strjoin(*p, "/", fragment, NULL);
1299                 if (resolved_path == NULL) {
1300                         log_oom();
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_oom();
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 }