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