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