chiark / gitweb /
tmpfiles: fix 'D' lines
[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/xattr.h>
42
43 #include "log.h"
44 #include "util.h"
45 #include "macro.h"
46 #include "missing.h"
47 #include "mkdir.h"
48 #include "path-util.h"
49 #include "strv.h"
50 #include "label.h"
51 #include "set.h"
52 #include "conf-files.h"
53 #include "capability.h"
54 #include "specifier.h"
55 #include "build.h"
56 #include "copy.h"
57 #include "selinux-util.h"
58 #include "btrfs-util.h"
59
60 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
61  * them in the file system. This is intended to be used to create
62  * properly owned directories beneath /tmp, /var/tmp, /run, which are
63  * volatile and hence need to be recreated on bootup. */
64
65 typedef enum ItemType {
66         /* These ones take file names */
67         CREATE_FILE = 'f',
68         TRUNCATE_FILE = 'F',
69         CREATE_DIRECTORY = 'd',
70         TRUNCATE_DIRECTORY = 'D',
71         CREATE_SUBVOLUME = 'v',
72         CREATE_FIFO = 'p',
73         CREATE_SYMLINK = 'L',
74         CREATE_CHAR_DEVICE = 'c',
75         CREATE_BLOCK_DEVICE = 'b',
76         COPY_FILES = 'C',
77         SET_XATTR = 't',
78
79         /* These ones take globs */
80         WRITE_FILE = 'w',
81         IGNORE_PATH = 'x',
82         IGNORE_DIRECTORY_PATH = 'X',
83         REMOVE_PATH = 'r',
84         RECURSIVE_REMOVE_PATH = 'R',
85         ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
86         RELABEL_PATH = 'z',
87         RECURSIVE_RELABEL_PATH = 'Z',
88 } ItemType;
89
90 typedef struct Item {
91         ItemType type;
92
93         char *path;
94         char *argument;
95         char **xattrs;
96         uid_t uid;
97         gid_t gid;
98         mode_t mode;
99         usec_t age;
100
101         dev_t major_minor;
102
103         bool uid_set:1;
104         bool gid_set:1;
105         bool mode_set:1;
106         bool age_set:1;
107         bool mask_perms:1;
108
109         bool keep_first_level:1;
110
111         bool force:1;
112
113         bool done:1;
114 } Item;
115
116 static bool arg_create = false;
117 static bool arg_clean = false;
118 static bool arg_remove = false;
119 static bool arg_boot = false;
120
121 static char **arg_include_prefixes = NULL;
122 static char **arg_exclude_prefixes = NULL;
123 static char *arg_root = NULL;
124
125 static const char conf_file_dirs[] = CONF_DIRS_NULSTR("tmpfiles");
126
127 #define MAX_DEPTH 256
128
129 static Hashmap *items = NULL, *globs = NULL;
130 static Set *unix_sockets = NULL;
131
132 static bool needs_glob(ItemType t) {
133         return IN_SET(t,
134                       WRITE_FILE,
135                       IGNORE_PATH,
136                       IGNORE_DIRECTORY_PATH,
137                       REMOVE_PATH,
138                       RECURSIVE_REMOVE_PATH,
139                       ADJUST_MODE,
140                       RELABEL_PATH,
141                       RECURSIVE_RELABEL_PATH);
142 }
143
144 static struct Item* find_glob(Hashmap *h, const char *match) {
145         Item *j;
146         Iterator i;
147
148         HASHMAP_FOREACH(j, h, i)
149                 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
150                         return j;
151
152         return NULL;
153 }
154
155 static void load_unix_sockets(void) {
156         _cleanup_fclose_ FILE *f = NULL;
157         char line[LINE_MAX];
158
159         if (unix_sockets)
160                 return;
161
162         /* We maintain a cache of the sockets we found in
163          * /proc/net/unix to speed things up a little. */
164
165         unix_sockets = set_new(&string_hash_ops);
166         if (!unix_sockets)
167                 return;
168
169         f = fopen("/proc/net/unix", "re");
170         if (!f)
171                 return;
172
173         /* Skip header */
174         if (!fgets(line, sizeof(line), f))
175                 goto fail;
176
177         for (;;) {
178                 char *p, *s;
179                 int k;
180
181                 if (!fgets(line, sizeof(line), f))
182                         break;
183
184                 truncate_nl(line);
185
186                 p = strchr(line, ':');
187                 if (!p)
188                         continue;
189
190                 if (strlen(p) < 37)
191                         continue;
192
193                 p += 37;
194                 p += strspn(p, WHITESPACE);
195                 p += strcspn(p, WHITESPACE); /* skip one more word */
196                 p += strspn(p, WHITESPACE);
197
198                 if (*p != '/')
199                         continue;
200
201                 s = strdup(p);
202                 if (!s)
203                         goto fail;
204
205                 path_kill_slashes(s);
206
207                 k = set_consume(unix_sockets, s);
208                 if (k < 0 && k != -EEXIST)
209                         goto fail;
210         }
211
212         return;
213
214 fail:
215         set_free_free(unix_sockets);
216         unix_sockets = NULL;
217 }
218
219 static bool unix_socket_alive(const char *fn) {
220         assert(fn);
221
222         load_unix_sockets();
223
224         if (unix_sockets)
225                 return !!set_get(unix_sockets, (char*) fn);
226
227         /* We don't know, so assume yes */
228         return true;
229 }
230
231 static int dir_is_mount_point(DIR *d, const char *subdir) {
232
233         union file_handle_union h = {
234                 .handle.handle_bytes = MAX_HANDLE_SZ
235         };
236
237         int mount_id_parent, mount_id;
238         int r_p, r;
239
240         r_p = name_to_handle_at(dirfd(d), ".", &h.handle, &mount_id_parent, 0);
241         if (r_p < 0)
242                 r_p = -errno;
243
244         h.handle.handle_bytes = MAX_HANDLE_SZ;
245         r = name_to_handle_at(dirfd(d), subdir, &h.handle, &mount_id, 0);
246         if (r < 0)
247                 r = -errno;
248
249         /* got no handle; make no assumptions, return error */
250         if (r_p < 0 && r < 0)
251                 return r_p;
252
253         /* got both handles; if they differ, it is a mount point */
254         if (r_p >= 0 && r >= 0)
255                 return mount_id_parent != mount_id;
256
257         /* got only one handle; assume different mount points if one
258          * of both queries was not supported by the filesystem */
259         if (r_p == -ENOSYS || r_p == -EOPNOTSUPP || r == -ENOSYS || r == -EOPNOTSUPP)
260                 return true;
261
262         /* return error */
263         if (r_p < 0)
264                 return r_p;
265         return r;
266 }
267
268 static int dir_cleanup(
269                 Item *i,
270                 const char *p,
271                 DIR *d,
272                 const struct stat *ds,
273                 usec_t cutoff,
274                 dev_t rootdev,
275                 bool mountpoint,
276                 int maxdepth,
277                 bool keep_this_level) {
278
279         struct dirent *dent;
280         struct timespec times[2];
281         bool deleted = false;
282         int r = 0;
283
284         while ((dent = readdir(d))) {
285                 struct stat s;
286                 usec_t age;
287                 _cleanup_free_ char *sub_path = NULL;
288
289                 if (streq(dent->d_name, ".") ||
290                     streq(dent->d_name, ".."))
291                         continue;
292
293                 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
294                         if (errno == ENOENT)
295                                 continue;
296
297                         /* FUSE, NFS mounts, SELinux might return EACCES */
298                         if (errno == EACCES)
299                                 log_debug_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
300                         else
301                                 log_error_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
302                         r = -errno;
303                         continue;
304                 }
305
306                 /* Stay on the same filesystem */
307                 if (s.st_dev != rootdev)
308                         continue;
309
310                 /* Try to detect bind mounts of the same filesystem instance; they
311                  * do not differ in device major/minors. This type of query is not
312                  * supported on all kernels or filesystem types though. */
313                 if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
314                         continue;
315
316                 /* Do not delete read-only files owned by root */
317                 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
318                         continue;
319
320                 sub_path = strjoin(p, "/", dent->d_name, NULL);
321                 if (!sub_path) {
322                         r = log_oom();
323                         goto finish;
324                 }
325
326                 /* Is there an item configured for this path? */
327                 if (hashmap_get(items, sub_path))
328                         continue;
329
330                 if (find_glob(globs, sub_path))
331                         continue;
332
333                 if (S_ISDIR(s.st_mode)) {
334
335                         if (mountpoint &&
336                             streq(dent->d_name, "lost+found") &&
337                             s.st_uid == 0)
338                                 continue;
339
340                         if (maxdepth <= 0)
341                                 log_warning("Reached max depth on %s.", sub_path);
342                         else {
343                                 _cleanup_closedir_ DIR *sub_dir;
344                                 int q;
345
346                                 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
347                                 if (!sub_dir) {
348                                         if (errno != ENOENT) {
349                                                 log_error_errno(errno, "opendir(%s/%s) failed: %m", p, dent->d_name);
350                                                 r = -errno;
351                                         }
352
353                                         continue;
354                                 }
355
356                                 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
357                                 if (q < 0)
358                                         r = q;
359                         }
360
361                         /* Note: if you are wondering why we don't
362                          * support the sticky bit for excluding
363                          * directories from cleaning like we do it for
364                          * other file system objects: well, the sticky
365                          * bit already has a meaning for directories,
366                          * so we don't want to overload that. */
367
368                         if (keep_this_level)
369                                 continue;
370
371                         /* Ignore ctime, we change it when deleting */
372                         age = MAX(timespec_load(&s.st_mtim),
373                                   timespec_load(&s.st_atim));
374                         if (age >= cutoff)
375                                 continue;
376
377                         if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
378                                 log_debug("rmdir '%s'", sub_path);
379
380                                 if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
381                                         if (errno != ENOENT && errno != ENOTEMPTY) {
382                                                 log_error_errno(errno, "rmdir(%s): %m", sub_path);
383                                                 r = -errno;
384                                         }
385                                 }
386                         }
387
388                 } else {
389                         /* Skip files for which the sticky bit is
390                          * set. These are semantics we define, and are
391                          * unknown elsewhere. See XDG_RUNTIME_DIR
392                          * specification for details. */
393                         if (s.st_mode & S_ISVTX)
394                                 continue;
395
396                         if (mountpoint && S_ISREG(s.st_mode)) {
397                                 if (streq(dent->d_name, ".journal") &&
398                                     s.st_uid == 0)
399                                         continue;
400
401                                 if (streq(dent->d_name, "aquota.user") ||
402                                     streq(dent->d_name, "aquota.group"))
403                                         continue;
404                         }
405
406                         /* Ignore sockets that are listed in /proc/net/unix */
407                         if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
408                                 continue;
409
410                         /* Ignore device nodes */
411                         if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
412                                 continue;
413
414                         /* Keep files on this level around if this is
415                          * requested */
416                         if (keep_this_level)
417                                 continue;
418
419                         age = MAX3(timespec_load(&s.st_mtim),
420                                    timespec_load(&s.st_atim),
421                                    timespec_load(&s.st_ctim));
422
423                         if (age >= cutoff)
424                                 continue;
425
426                         log_debug("unlink '%s'", sub_path);
427
428                         if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
429                                 if (errno != ENOENT) {
430                                         log_error_errno(errno, "unlink(%s): %m", sub_path);
431                                         r = -errno;
432                                 }
433                         }
434
435                         deleted = true;
436                 }
437         }
438
439 finish:
440         if (deleted) {
441                 /* Restore original directory timestamps */
442                 times[0] = ds->st_atim;
443                 times[1] = ds->st_mtim;
444
445                 if (futimens(dirfd(d), times) < 0)
446                         log_error_errno(errno, "utimensat(%s): %m", p);
447         }
448
449         return r;
450 }
451
452 static int item_set_perms(Item *i, const char *path) {
453         struct stat st;
454         bool st_valid;
455
456         assert(i);
457         assert(path);
458
459         st_valid = stat(path, &st) == 0;
460
461         /* not using i->path directly because it may be a glob */
462         if (i->mode_set) {
463                 mode_t m = i->mode;
464
465                 if (i->mask_perms && st_valid) {
466                         if (!(st.st_mode & 0111))
467                                 m &= ~0111;
468                         if (!(st.st_mode & 0222))
469                                 m &= ~0222;
470                         if (!(st.st_mode & 0444))
471                                 m &= ~0444;
472                         if (!S_ISDIR(st.st_mode))
473                                 m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
474                 }
475
476                 if (!st_valid || m != (st.st_mode & 07777)) {
477                         if (chmod(path, m) < 0)
478                                 return log_error_errno(errno, "chmod(%s) failed: %m", path);
479                 }
480         }
481
482         if ((!st_valid || (i->uid != st.st_uid || i->gid != st.st_gid)) &&
483             (i->uid_set || i->gid_set))
484                 if (chown(path,
485                           i->uid_set ? i->uid : UID_INVALID,
486                           i->gid_set ? i->gid : GID_INVALID) < 0) {
487
488                         log_error_errno(errno, "chown(%s) failed: %m", path);
489                         return -errno;
490                 }
491
492         return label_fix(path, false, false);
493 }
494
495 static int get_xattrs_from_arg(Item *i) {
496         char *xattr;
497         const char *p;
498         int r;
499
500         assert(i);
501
502         if (!i->argument) {
503                 log_error("%s: Argument can't be empty!", i->path);
504                 return -EBADMSG;
505         }
506         p = i->argument;
507
508         while ((r = unquote_first_word(&p, &xattr, false)) > 0) {
509                 _cleanup_free_ char *tmp = NULL, *name = NULL, *value = NULL;
510                 r = split_pair(xattr, "=", &name, &value);
511                 if (r < 0) {
512                         log_warning("Illegal xattr found: \"%s\" - ignoring.", xattr);
513                         free(xattr);
514                         continue;
515                 }
516                 free(xattr);
517                 if (streq(name, "") || streq(value, "")) {
518                         log_warning("Malformed xattr found: \"%s=%s\" - ignoring.", name, value);
519                         continue;
520                 }
521                 tmp = unquote(value, "\"");
522                 if (!tmp)
523                         return log_oom();
524                 free(value);
525                 value = cunescape(tmp);
526                 if (!value)
527                         return log_oom();
528                 if (strv_consume_pair(&i->xattrs, name, value) < 0)
529                         return log_oom();
530                 name = value = NULL;
531         }
532
533         return r;
534 }
535
536 static int item_set_xattrs(Item *i, const char *path) {
537         char **name, **value;
538
539         assert(i);
540         assert(path);
541
542         if (strv_isempty(i->xattrs))
543                 return 0;
544
545         STRV_FOREACH_PAIR(name, value, i->xattrs) {
546                 int n;
547                 n = strlen(*value);
548                 if (lsetxattr(path, *name, *value, n, 0) < 0) {
549                         log_error("Setting extended attribute %s=%s on %s failed: %m", *name, *value, path);
550                         return -errno;
551                 }
552         }
553         return 0;
554 }
555
556 static int write_one_file(Item *i, const char *path) {
557         _cleanup_close_ int fd = -1;
558         int flags, r = 0;
559         struct stat st;
560
561         assert(i);
562         assert(path);
563
564         flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND|O_NOFOLLOW :
565                 i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
566
567         RUN_WITH_UMASK(0000) {
568                 mac_selinux_create_file_prepare(path, S_IFREG);
569                 fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
570                 mac_selinux_create_file_clear();
571         }
572
573         if (fd < 0) {
574                 if (i->type == WRITE_FILE && errno == ENOENT)
575                         return 0;
576
577                 log_error_errno(errno, "Failed to create file %s: %m", path);
578                 return -errno;
579         }
580
581         if (i->argument) {
582                 _cleanup_free_ char *unescaped;
583                 ssize_t n;
584                 size_t l;
585
586                 unescaped = cunescape(i->argument);
587                 if (!unescaped)
588                         return log_oom();
589
590                 l = strlen(unescaped);
591                 n = write(fd, unescaped, l);
592
593                 if (n < 0 || (size_t) n < l) {
594                         log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write");
595                         return n < 0 ? n : -EIO;
596                 }
597         }
598
599         fd = safe_close(fd);
600
601         if (stat(path, &st) < 0)
602                 return log_error_errno(errno, "stat(%s) failed: %m", path);
603
604         if (!S_ISREG(st.st_mode)) {
605                 log_error("%s is not a file.", path);
606                 return -EEXIST;
607         }
608
609         r = item_set_perms(i, path);
610         if (r < 0)
611                 return r;
612
613         r = item_set_xattrs(i, i->path);
614         if (r < 0)
615                 return r;
616
617         return 0;
618 }
619
620 static int item_set_perms_children(Item *i, const char *path) {
621         _cleanup_closedir_ DIR *d;
622         int r = 0;
623
624         assert(i);
625         assert(path);
626
627         /* This returns the first error we run into, but nevertheless
628          * tries to go on */
629
630         d = opendir(path);
631         if (!d)
632                 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
633
634         for (;;) {
635                 _cleanup_free_ char *p = NULL;
636                 struct dirent *de;
637                 int q;
638
639                 errno = 0;
640                 de = readdir(d);
641                 if (!de) {
642                         if (errno != 0 && r == 0)
643                                 r = -errno;
644
645                         break;
646                 }
647
648                 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
649                         continue;
650
651                 p = strjoin(path, "/", de->d_name, NULL);
652                 if (!p)
653                         return -ENOMEM;
654
655                 q = item_set_perms(i, p);
656                 if (q < 0 && q != -ENOENT && r == 0)
657                         r = q;
658
659                 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
660                         q = item_set_perms_children(i, p);
661                         if (q < 0 && r == 0)
662                                 r = q;
663                 }
664         }
665
666         return r;
667 }
668
669 static int item_set_perms_recursive(Item *i, const char *path) {
670         int r, q;
671
672         assert(i);
673         assert(path);
674
675         r = item_set_perms(i, path);
676         if (r < 0)
677                 return r;
678
679         q = item_set_perms_children(i, path);
680         if (q < 0 && r == 0)
681                 r = q;
682
683         return r;
684 }
685
686 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
687         _cleanup_globfree_ glob_t g = {};
688         int r = 0, k;
689         char **fn;
690
691         errno = 0;
692         k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
693         if (k != 0 && k != GLOB_NOMATCH) {
694                 if (errno == 0)
695                         errno = EIO;
696
697                 log_error_errno(errno, "glob(%s) failed: %m", i->path);
698                 return -errno;
699         }
700
701         STRV_FOREACH(fn, g.gl_pathv) {
702                 k = action(i, *fn);
703                 if (k < 0 && r == 0)
704                         r = k;
705         }
706
707         return r;
708 }
709
710 static int create_item(Item *i) {
711         struct stat st;
712         int r = 0;
713
714         assert(i);
715
716         switch (i->type) {
717
718         case IGNORE_PATH:
719         case IGNORE_DIRECTORY_PATH:
720         case REMOVE_PATH:
721         case RECURSIVE_REMOVE_PATH:
722                 return 0;
723
724         case CREATE_FILE:
725         case TRUNCATE_FILE:
726                 r = write_one_file(i, i->path);
727                 if (r < 0)
728                         return r;
729                 break;
730
731         case COPY_FILES:
732                 r = copy_tree(i->argument, i->path, false);
733                 if (r < 0) {
734                         struct stat a, b;
735
736                         if (r != -EEXIST)
737                                 return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
738
739                         if (stat(i->argument, &a) < 0)
740                                 return log_error_errno(errno, "stat(%s) failed: %m", i->argument);
741
742                         if (stat(i->path, &b) < 0)
743                                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
744
745                         if ((a.st_mode ^ b.st_mode) & S_IFMT) {
746                                 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
747                                 return 0;
748                         }
749                 }
750
751                 r = item_set_perms(i, i->path);
752                 if (r < 0)
753                         return r;
754
755                 break;
756
757         case WRITE_FILE:
758                 r = glob_item(i, write_one_file);
759                 if (r < 0)
760                         return r;
761
762                 break;
763
764         case CREATE_DIRECTORY:
765         case TRUNCATE_DIRECTORY:
766         case CREATE_SUBVOLUME:
767
768                 RUN_WITH_UMASK(0000)
769                         mkdir_parents_label(i->path, 0755);
770
771                 if (i->type == CREATE_SUBVOLUME) {
772                         RUN_WITH_UMASK((~i->mode) & 0777)
773                                 r = btrfs_subvol_make(i->path);
774                 } else
775                         r = 0;
776
777                 if (i->type == CREATE_DIRECTORY || i->type == TRUNCATE_DIRECTORY || r == -ENOTTY) {
778                         RUN_WITH_UMASK(0000)
779                                 r = mkdir_label(i->path, i->mode);
780                 }
781
782                 if (r < 0) {
783                         if (r != -EEXIST)
784                                 return log_error_errno(r, "Failed to create directory or subvolume %s: %m", i->path);
785
786                         if (stat(i->path, &st) < 0)
787                                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
788
789                         if (!S_ISDIR(st.st_mode)) {
790                                 log_debug("%s already exists and is not a directory.", i->path);
791                                 return 0;
792                         }
793                 }
794
795                 r = item_set_perms(i, i->path);
796                 if (r < 0)
797                         return r;
798
799                 r = item_set_xattrs(i, i->path);
800                 if (r < 0)
801                         return r;
802
803                 break;
804
805         case CREATE_FIFO:
806
807                 RUN_WITH_UMASK(0000) {
808                         mac_selinux_create_file_prepare(i->path, S_IFIFO);
809                         r = mkfifo(i->path, i->mode);
810                         mac_selinux_create_file_clear();
811                 }
812
813                 if (r < 0) {
814                         if (errno != EEXIST)
815                                 return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
816
817                         if (stat(i->path, &st) < 0)
818                                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
819
820                         if (!S_ISFIFO(st.st_mode)) {
821
822                                 if (i->force) {
823
824                                         RUN_WITH_UMASK(0000) {
825                                                 mac_selinux_create_file_prepare(i->path, S_IFIFO);
826                                                 r = mkfifo_atomic(i->path, i->mode);
827                                                 mac_selinux_create_file_clear();
828                                         }
829
830                                         if (r < 0)
831                                                 return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
832                                 } else {
833                                         log_debug("%s is not a fifo.", i->path);
834                                         return 0;
835                                 }
836                         }
837                 }
838
839                 r = item_set_perms(i, i->path);
840                 if (r < 0)
841                         return r;
842
843                 r = item_set_xattrs(i, i->path);
844                 if (r < 0)
845                         return r;
846
847                 break;
848
849         case CREATE_SYMLINK:
850
851                 mac_selinux_create_file_prepare(i->path, S_IFLNK);
852                 r = symlink(i->argument, i->path);
853                 mac_selinux_create_file_clear();
854
855                 if (r < 0) {
856                         _cleanup_free_ char *x = NULL;
857
858                         if (errno != EEXIST)
859                                 return log_error_errno(errno, "symlink(%s, %s) failed: %m", i->argument, i->path);
860
861                         r = readlink_malloc(i->path, &x);
862                         if (r < 0 || !streq(i->argument, x)) {
863
864                                 if (i->force) {
865                                         mac_selinux_create_file_prepare(i->path, S_IFLNK);
866                                         r = symlink_atomic(i->argument, i->path);
867                                         mac_selinux_create_file_clear();
868
869                                         if (r < 0)
870                                                 return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
871                                 } else {
872                                         log_debug("%s is not a symlink or does not point to the correct path.", i->path);
873                                         return 0;
874                                 }
875                         }
876                 }
877
878                 r = item_set_xattrs(i, i->path);
879                 if (r < 0)
880                        return r;
881
882                 break;
883
884         case CREATE_BLOCK_DEVICE:
885         case CREATE_CHAR_DEVICE: {
886                 mode_t file_type;
887
888                 if (have_effective_cap(CAP_MKNOD) == 0) {
889                         /* In a container we lack CAP_MKNOD. We
890                         shouldn't attempt to create the device node in
891                         that case to avoid noise, and we don't support
892                         virtualized devices in containers anyway. */
893
894                         log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
895                         return 0;
896                 }
897
898                 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
899
900                 RUN_WITH_UMASK(0000) {
901                         mac_selinux_create_file_prepare(i->path, file_type);
902                         r = mknod(i->path, i->mode | file_type, i->major_minor);
903                         mac_selinux_create_file_clear();
904                 }
905
906                 if (r < 0) {
907                         if (errno == EPERM) {
908                                 log_debug("We lack permissions, possibly because of cgroup configuration; "
909                                           "skipping creation of device node %s.", i->path);
910                                 return 0;
911                         }
912
913                         if (errno != EEXIST)
914                                 return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
915
916                         if (stat(i->path, &st) < 0)
917                                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
918
919                         if ((st.st_mode & S_IFMT) != file_type) {
920
921                                 if (i->force) {
922
923                                         RUN_WITH_UMASK(0000) {
924                                                 mac_selinux_create_file_prepare(i->path, file_type);
925                                                 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
926                                                 mac_selinux_create_file_clear();
927                                         }
928
929                                         if (r < 0)
930                                                 return log_error_errno(r, "Failed to create device node %s: %m", i->path);
931                                 } else {
932                                         log_debug("%s is not a device node.", i->path);
933                                         return 0;
934                                 }
935                         }
936                 }
937
938                 r = item_set_perms(i, i->path);
939                 if (r < 0)
940                         return r;
941
942                 r = item_set_xattrs(i, i->path);
943                 if (r < 0)
944                         return r;
945
946                 break;
947         }
948
949         case ADJUST_MODE:
950         case RELABEL_PATH:
951
952                 r = glob_item(i, item_set_perms);
953                 if (r < 0)
954                         return r;
955                 break;
956
957         case RECURSIVE_RELABEL_PATH:
958
959                 r = glob_item(i, item_set_perms_recursive);
960                 if (r < 0)
961                         return r;
962                 break;
963
964         case SET_XATTR:
965                 r = item_set_xattrs(i, i->path);
966                 if (r < 0)
967                         return r;
968                 break;
969         }
970
971         log_debug("%s created successfully.", i->path);
972
973         return 0;
974 }
975
976 static int remove_item_instance(Item *i, const char *instance) {
977         int r;
978
979         assert(i);
980
981         switch (i->type) {
982
983         case CREATE_FILE:
984         case TRUNCATE_FILE:
985         case CREATE_DIRECTORY:
986         case CREATE_SUBVOLUME:
987         case CREATE_FIFO:
988         case CREATE_SYMLINK:
989         case CREATE_BLOCK_DEVICE:
990         case CREATE_CHAR_DEVICE:
991         case IGNORE_PATH:
992         case IGNORE_DIRECTORY_PATH:
993         case ADJUST_MODE:
994         case RELABEL_PATH:
995         case RECURSIVE_RELABEL_PATH:
996         case WRITE_FILE:
997         case COPY_FILES:
998         case SET_XATTR:
999                 break;
1000
1001         case REMOVE_PATH:
1002                 if (remove(instance) < 0 && errno != ENOENT)
1003                         return log_error_errno(errno, "remove(%s): %m", instance);
1004
1005                 break;
1006
1007         case TRUNCATE_DIRECTORY:
1008         case RECURSIVE_REMOVE_PATH:
1009                 /* FIXME: we probably should use dir_cleanup() here
1010                  * instead of rm_rf() so that 'x' is honoured. */
1011                 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
1012                 if (r < 0 && r != -ENOENT)
1013                         return log_error_errno(r, "rm_rf(%s): %m", instance);
1014
1015                 break;
1016         }
1017
1018         return 0;
1019 }
1020
1021 static int remove_item(Item *i) {
1022         int r = 0;
1023
1024         assert(i);
1025
1026         switch (i->type) {
1027
1028         case CREATE_FILE:
1029         case TRUNCATE_FILE:
1030         case CREATE_DIRECTORY:
1031         case CREATE_SUBVOLUME:
1032         case CREATE_FIFO:
1033         case CREATE_SYMLINK:
1034         case CREATE_CHAR_DEVICE:
1035         case CREATE_BLOCK_DEVICE:
1036         case IGNORE_PATH:
1037         case IGNORE_DIRECTORY_PATH:
1038         case ADJUST_MODE:
1039         case RELABEL_PATH:
1040         case RECURSIVE_RELABEL_PATH:
1041         case WRITE_FILE:
1042         case COPY_FILES:
1043         case SET_XATTR:
1044                 break;
1045
1046         case REMOVE_PATH:
1047         case TRUNCATE_DIRECTORY:
1048         case RECURSIVE_REMOVE_PATH:
1049                 r = glob_item(i, remove_item_instance);
1050                 break;
1051         }
1052
1053         return r;
1054 }
1055
1056 static int clean_item_instance(Item *i, const char* instance) {
1057         _cleanup_closedir_ DIR *d = NULL;
1058         struct stat s, ps;
1059         bool mountpoint;
1060         int r;
1061         usec_t cutoff, n;
1062
1063         assert(i);
1064
1065         if (!i->age_set)
1066                 return 0;
1067
1068         n = now(CLOCK_REALTIME);
1069         if (n < i->age)
1070                 return 0;
1071
1072         cutoff = n - i->age;
1073
1074         d = opendir(instance);
1075         if (!d) {
1076                 if (errno == ENOENT || errno == ENOTDIR)
1077                         return 0;
1078
1079                 log_error_errno(errno, "Failed to open directory %s: %m", i->path);
1080                 return -errno;
1081         }
1082
1083         if (fstat(dirfd(d), &s) < 0)
1084                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1085
1086         if (!S_ISDIR(s.st_mode)) {
1087                 log_error("%s is not a directory.", i->path);
1088                 return -ENOTDIR;
1089         }
1090
1091         if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
1092                 return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
1093
1094         mountpoint = s.st_dev != ps.st_dev ||
1095                      (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1096
1097         r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1098                         MAX_DEPTH, i->keep_first_level);
1099         return r;
1100 }
1101
1102 static int clean_item(Item *i) {
1103         int r = 0;
1104
1105         assert(i);
1106
1107         switch (i->type) {
1108         case CREATE_DIRECTORY:
1109         case CREATE_SUBVOLUME:
1110         case TRUNCATE_DIRECTORY:
1111         case IGNORE_PATH:
1112         case COPY_FILES:
1113                 clean_item_instance(i, i->path);
1114                 break;
1115         case IGNORE_DIRECTORY_PATH:
1116                 r = glob_item(i, clean_item_instance);
1117                 break;
1118         default:
1119                 break;
1120         }
1121
1122         return r;
1123 }
1124
1125 static int process_item(Item *i) {
1126         int r, q, p;
1127         _cleanup_free_ char *prefix = NULL;
1128
1129         assert(i);
1130
1131         if (i->done)
1132                 return 0;
1133
1134         i->done = true;
1135
1136         prefix = malloc(strlen(i->path) + 1);
1137         if (!prefix)
1138                 return log_oom();
1139
1140         PATH_FOREACH_PREFIX(prefix, i->path) {
1141                 Item *j;
1142
1143                 j = hashmap_get(items, prefix);
1144                 if (j)
1145                         process_item(j);
1146         }
1147
1148         r = arg_create ? create_item(i) : 0;
1149         q = arg_remove ? remove_item(i) : 0;
1150         p = arg_clean ? clean_item(i) : 0;
1151
1152         if (r < 0)
1153                 return r;
1154
1155         if (q < 0)
1156                 return q;
1157
1158         return p;
1159 }
1160
1161 static void item_free(Item *i) {
1162
1163         if (!i)
1164                 return;
1165
1166         free(i->path);
1167         free(i->argument);
1168         strv_free(i->xattrs);
1169         free(i);
1170 }
1171
1172 DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free);
1173
1174 static bool item_equal(Item *a, Item *b) {
1175         assert(a);
1176         assert(b);
1177
1178         if (!streq_ptr(a->path, b->path))
1179                 return false;
1180
1181         if (a->type != b->type)
1182                 return false;
1183
1184         if (a->uid_set != b->uid_set ||
1185             (a->uid_set && a->uid != b->uid))
1186             return false;
1187
1188         if (a->gid_set != b->gid_set ||
1189             (a->gid_set && a->gid != b->gid))
1190             return false;
1191
1192         if (a->mode_set != b->mode_set ||
1193             (a->mode_set && a->mode != b->mode))
1194             return false;
1195
1196         if (a->age_set != b->age_set ||
1197             (a->age_set && a->age != b->age))
1198             return false;
1199
1200         if ((a->type == CREATE_FILE ||
1201              a->type == TRUNCATE_FILE ||
1202              a->type == WRITE_FILE ||
1203              a->type == CREATE_SYMLINK ||
1204              a->type == COPY_FILES) &&
1205             !streq_ptr(a->argument, b->argument))
1206                 return false;
1207
1208         if ((a->type == CREATE_CHAR_DEVICE ||
1209              a->type == CREATE_BLOCK_DEVICE) &&
1210             a->major_minor != b->major_minor)
1211                 return false;
1212
1213         return true;
1214 }
1215
1216 static bool should_include_path(const char *path) {
1217         char **prefix;
1218
1219         STRV_FOREACH(prefix, arg_exclude_prefixes)
1220                 if (path_startswith(path, *prefix))
1221                         return false;
1222
1223         STRV_FOREACH(prefix, arg_include_prefixes)
1224                 if (path_startswith(path, *prefix))
1225                         return true;
1226
1227         /* no matches, so we should include this path only if we
1228          * have no whitelist at all */
1229         return strv_length(arg_include_prefixes) == 0;
1230 }
1231
1232 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1233
1234         static const Specifier specifier_table[] = {
1235                 { 'm', specifier_machine_id, NULL },
1236                 { 'b', specifier_boot_id, NULL },
1237                 { 'H', specifier_host_name, NULL },
1238                 { 'v', specifier_kernel_release, NULL },
1239                 {}
1240         };
1241
1242         _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1243         _cleanup_(item_freep) Item *i = NULL;
1244         Item *existing;
1245         char type;
1246         Hashmap *h;
1247         int r, n = -1;
1248
1249         assert(fname);
1250         assert(line >= 1);
1251         assert(buffer);
1252
1253         r = sscanf(buffer,
1254                    "%ms %ms %ms %ms %ms %ms %n",
1255                    &action,
1256                    &path,
1257                    &mode,
1258                    &user,
1259                    &group,
1260                    &age,
1261                    &n);
1262         if (r < 2) {
1263                 log_error("[%s:%u] Syntax error.", fname, line);
1264                 return -EIO;
1265         }
1266
1267         if (isempty(action)) {
1268                 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1269                 return -EINVAL;
1270         }
1271
1272         if (strlen(action) > 1 && !in_charset(action+1, "!+")) {
1273                 log_error("[%s:%u] Unknown modifiers in command '%s'", fname, line, action);
1274                 return -EINVAL;
1275         }
1276
1277         if (strchr(action+1, '!') && !arg_boot)
1278                 return 0;
1279
1280         type = action[0];
1281
1282         i = new0(Item, 1);
1283         if (!i)
1284                 return log_oom();
1285
1286         i->force = !!strchr(action+1, '+');
1287
1288         r = specifier_printf(path, specifier_table, NULL, &i->path);
1289         if (r < 0) {
1290                 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1291                 return r;
1292         }
1293
1294         if (n >= 0)  {
1295                 n += strspn(buffer+n, WHITESPACE);
1296                 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
1297                         i->argument = unquote(buffer+n, "\"");
1298                         if (!i->argument)
1299                                 return log_oom();
1300                 }
1301         }
1302
1303         switch (type) {
1304
1305         case CREATE_FILE:
1306         case TRUNCATE_FILE:
1307         case CREATE_DIRECTORY:
1308         case CREATE_SUBVOLUME:
1309         case TRUNCATE_DIRECTORY:
1310         case CREATE_FIFO:
1311         case IGNORE_PATH:
1312         case IGNORE_DIRECTORY_PATH:
1313         case REMOVE_PATH:
1314         case RECURSIVE_REMOVE_PATH:
1315         case ADJUST_MODE:
1316         case RELABEL_PATH:
1317         case RECURSIVE_RELABEL_PATH:
1318                 break;
1319
1320         case CREATE_SYMLINK:
1321                 if (!i->argument) {
1322                         i->argument = strappend("/usr/share/factory", i->path);
1323                         if (!i->argument)
1324                                 return log_oom();
1325                 }
1326                 break;
1327
1328         case WRITE_FILE:
1329                 if (!i->argument) {
1330                         log_error("[%s:%u] Write file requires argument.", fname, line);
1331                         return -EBADMSG;
1332                 }
1333                 break;
1334
1335         case COPY_FILES:
1336                 if (!i->argument) {
1337                         i->argument = strappend("/usr/share/factory", i->path);
1338                         if (!i->argument)
1339                                 return log_oom();
1340                 }
1341
1342                 if (!path_is_absolute(i->argument)) {
1343                         log_error("[%s:%u] Source path is not absolute.", fname, line);
1344                         return -EBADMSG;
1345                 }
1346
1347                 path_kill_slashes(i->argument);
1348                 break;
1349
1350         case CREATE_CHAR_DEVICE:
1351         case CREATE_BLOCK_DEVICE: {
1352                 unsigned major, minor;
1353
1354                 if (!i->argument) {
1355                         log_error("[%s:%u] Device file requires argument.", fname, line);
1356                         return -EBADMSG;
1357                 }
1358
1359                 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1360                         log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1361                         return -EBADMSG;
1362                 }
1363
1364                 i->major_minor = makedev(major, minor);
1365                 break;
1366         }
1367
1368         case SET_XATTR:
1369                 if (!i->argument) {
1370                         log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1371                         return -EBADMSG;
1372                 }
1373                 r = get_xattrs_from_arg(i);
1374                 if (r < 0)
1375                         return r;
1376                 break;
1377
1378         default:
1379                 log_error("[%s:%u] Unknown command type '%c'.", fname, line, type);
1380                 return -EBADMSG;
1381         }
1382
1383         i->type = type;
1384
1385         if (!path_is_absolute(i->path)) {
1386                 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1387                 return -EBADMSG;
1388         }
1389
1390         path_kill_slashes(i->path);
1391
1392         if (!should_include_path(i->path))
1393                 return 0;
1394
1395         if (arg_root) {
1396                 char *p;
1397
1398                 p = strappend(arg_root, i->path);
1399                 if (!p)
1400                         return log_oom();
1401
1402                 free(i->path);
1403                 i->path = p;
1404         }
1405
1406         if (user && !streq(user, "-")) {
1407                 const char *u = user;
1408
1409                 r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
1410                 if (r < 0) {
1411                         log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1412                         return r;
1413                 }
1414
1415                 i->uid_set = true;
1416         }
1417
1418         if (group && !streq(group, "-")) {
1419                 const char *g = group;
1420
1421                 r = get_group_creds(&g, &i->gid);
1422                 if (r < 0) {
1423                         log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1424                         return r;
1425                 }
1426
1427                 i->gid_set = true;
1428         }
1429
1430         if (mode && !streq(mode, "-")) {
1431                 const char *mm = mode;
1432                 unsigned m;
1433
1434                 if (*mm == '~') {
1435                         i->mask_perms = true;
1436                         mm++;
1437                 }
1438
1439                 if (sscanf(mm, "%o", &m) != 1) {
1440                         log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1441                         return -ENOENT;
1442                 }
1443
1444                 i->mode = m;
1445                 i->mode_set = true;
1446         } else
1447                 i->mode =
1448                         i->type == CREATE_DIRECTORY ||
1449                         i->type == CREATE_SUBVOLUME ||
1450                         i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1451
1452         if (age && !streq(age, "-")) {
1453                 const char *a = age;
1454
1455                 if (*a == '~') {
1456                         i->keep_first_level = true;
1457                         a++;
1458                 }
1459
1460                 if (parse_sec(a, &i->age) < 0) {
1461                         log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1462                         return -EBADMSG;
1463                 }
1464
1465                 i->age_set = true;
1466         }
1467
1468         h = needs_glob(i->type) ? globs : items;
1469
1470         existing = hashmap_get(h, i->path);
1471         if (existing) {
1472                 if (i->type == SET_XATTR) {
1473                         r = strv_extend_strv(&existing->xattrs, i->xattrs);
1474                         if (r < 0)
1475                                 return log_oom();
1476                         return 0;
1477                 } else if (existing->type == SET_XATTR) {
1478                         r = strv_extend_strv(&i->xattrs, existing->xattrs);
1479                         if (r < 0)
1480                                 return log_oom();
1481                         r = hashmap_replace(h, i->path, i);
1482                         if (r < 0) {
1483                                 log_error("Failed to replace item for %s.", i->path);
1484                                 return r;
1485                         }
1486                         item_free(existing);
1487                 } else {
1488                         /* Two identical items are fine */
1489                         if (!item_equal(existing, i))
1490                                 log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1491                         return 0;
1492                 }
1493         } else {
1494                 r = hashmap_put(h, i->path, i);
1495                 if (r < 0) {
1496                         log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1497                         return r;
1498                 }
1499         }
1500
1501         i = NULL; /* avoid cleanup */
1502
1503         return 0;
1504 }
1505
1506 static void help(void) {
1507         printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1508                "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1509                "  -h --help                 Show this help\n"
1510                "     --version              Show package version\n"
1511                "     --create               Create marked files/directories\n"
1512                "     --clean                Clean up marked directories\n"
1513                "     --remove               Remove marked files/directories\n"
1514                "     --boot                 Execute actions only safe at boot\n"
1515                "     --prefix=PATH          Only apply rules that apply to paths with the specified prefix\n"
1516                "     --exclude-prefix=PATH  Ignore rules that apply to paths with the specified prefix\n"
1517                "     --root=PATH            Operate on an alternate filesystem root\n",
1518                program_invocation_short_name);
1519 }
1520
1521 static int parse_argv(int argc, char *argv[]) {
1522
1523         enum {
1524                 ARG_VERSION = 0x100,
1525                 ARG_CREATE,
1526                 ARG_CLEAN,
1527                 ARG_REMOVE,
1528                 ARG_BOOT,
1529                 ARG_PREFIX,
1530                 ARG_EXCLUDE_PREFIX,
1531                 ARG_ROOT,
1532         };
1533
1534         static const struct option options[] = {
1535                 { "help",           no_argument,         NULL, 'h'                },
1536                 { "version",        no_argument,         NULL, ARG_VERSION        },
1537                 { "create",         no_argument,         NULL, ARG_CREATE         },
1538                 { "clean",          no_argument,         NULL, ARG_CLEAN          },
1539                 { "remove",         no_argument,         NULL, ARG_REMOVE         },
1540                 { "boot",           no_argument,         NULL, ARG_BOOT           },
1541                 { "prefix",         required_argument,   NULL, ARG_PREFIX         },
1542                 { "exclude-prefix", required_argument,   NULL, ARG_EXCLUDE_PREFIX },
1543                 { "root",           required_argument,   NULL, ARG_ROOT           },
1544                 {}
1545         };
1546
1547         int c;
1548
1549         assert(argc >= 0);
1550         assert(argv);
1551
1552         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1553
1554                 switch (c) {
1555
1556                 case 'h':
1557                         help();
1558                         return 0;
1559
1560                 case ARG_VERSION:
1561                         puts(PACKAGE_STRING);
1562                         puts(SYSTEMD_FEATURES);
1563                         return 0;
1564
1565                 case ARG_CREATE:
1566                         arg_create = true;
1567                         break;
1568
1569                 case ARG_CLEAN:
1570                         arg_clean = true;
1571                         break;
1572
1573                 case ARG_REMOVE:
1574                         arg_remove = true;
1575                         break;
1576
1577                 case ARG_BOOT:
1578                         arg_boot = true;
1579                         break;
1580
1581                 case ARG_PREFIX:
1582                         if (strv_push(&arg_include_prefixes, optarg) < 0)
1583                                 return log_oom();
1584                         break;
1585
1586                 case ARG_EXCLUDE_PREFIX:
1587                         if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1588                                 return log_oom();
1589                         break;
1590
1591                 case ARG_ROOT:
1592                         free(arg_root);
1593                         arg_root = path_make_absolute_cwd(optarg);
1594                         if (!arg_root)
1595                                 return log_oom();
1596
1597                         path_kill_slashes(arg_root);
1598                         break;
1599
1600                 case '?':
1601                         return -EINVAL;
1602
1603                 default:
1604                         assert_not_reached("Unhandled option");
1605                 }
1606
1607         if (!arg_clean && !arg_create && !arg_remove) {
1608                 log_error("You need to specify at least one of --clean, --create or --remove.");
1609                 return -EINVAL;
1610         }
1611
1612         return 1;
1613 }
1614
1615 static int read_config_file(const char *fn, bool ignore_enoent) {
1616         _cleanup_fclose_ FILE *f = NULL;
1617         char line[LINE_MAX];
1618         Iterator iterator;
1619         unsigned v = 0;
1620         Item *i;
1621         int r;
1622
1623         assert(fn);
1624
1625         r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1626         if (r < 0) {
1627                 if (ignore_enoent && r == -ENOENT)
1628                         return 0;
1629
1630                 return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
1631         }
1632
1633         FOREACH_LINE(line, f, break) {
1634                 char *l;
1635                 int k;
1636
1637                 v++;
1638
1639                 l = strstrip(line);
1640                 if (*l == '#' || *l == 0)
1641                         continue;
1642
1643                 k = parse_line(fn, v, l);
1644                 if (k < 0 && r == 0)
1645                         r = k;
1646         }
1647
1648         /* we have to determine age parameter for each entry of type X */
1649         HASHMAP_FOREACH(i, globs, iterator) {
1650                 Iterator iter;
1651                 Item *j, *candidate_item = NULL;
1652
1653                 if (i->type != IGNORE_DIRECTORY_PATH)
1654                         continue;
1655
1656                 HASHMAP_FOREACH(j, items, iter) {
1657                         if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME)
1658                                 continue;
1659
1660                         if (path_equal(j->path, i->path)) {
1661                                 candidate_item = j;
1662                                 break;
1663                         }
1664
1665                         if ((!candidate_item && path_startswith(i->path, j->path)) ||
1666                             (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1667                                 candidate_item = j;
1668                 }
1669
1670                 if (candidate_item && candidate_item->age_set) {
1671                         i->age = candidate_item->age;
1672                         i->age_set = true;
1673                 }
1674         }
1675
1676         if (ferror(f)) {
1677                 log_error_errno(errno, "Failed to read from file %s: %m", fn);
1678                 if (r == 0)
1679                         r = -EIO;
1680         }
1681
1682         return r;
1683 }
1684
1685 int main(int argc, char *argv[]) {
1686         int r, k;
1687         Item *i;
1688         Iterator iterator;
1689
1690         r = parse_argv(argc, argv);
1691         if (r <= 0)
1692                 goto finish;
1693
1694         log_set_target(LOG_TARGET_AUTO);
1695         log_parse_environment();
1696         log_open();
1697
1698         umask(0022);
1699
1700         mac_selinux_init(NULL);
1701
1702         items = hashmap_new(&string_hash_ops);
1703         globs = hashmap_new(&string_hash_ops);
1704
1705         if (!items || !globs) {
1706                 r = log_oom();
1707                 goto finish;
1708         }
1709
1710         r = 0;
1711
1712         if (optind < argc) {
1713                 int j;
1714
1715                 for (j = optind; j < argc; j++) {
1716                         k = read_config_file(argv[j], false);
1717                         if (k < 0 && r == 0)
1718                                 r = k;
1719                 }
1720
1721         } else {
1722                 _cleanup_strv_free_ char **files = NULL;
1723                 char **f;
1724
1725                 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1726                 if (r < 0) {
1727                         log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
1728                         goto finish;
1729                 }
1730
1731                 STRV_FOREACH(f, files) {
1732                         k = read_config_file(*f, true);
1733                         if (k < 0 && r == 0)
1734                                 r = k;
1735                 }
1736         }
1737
1738         HASHMAP_FOREACH(i, globs, iterator)
1739                 process_item(i);
1740
1741         HASHMAP_FOREACH(i, items, iterator)
1742                 process_item(i);
1743
1744 finish:
1745         while ((i = hashmap_steal_first(items)))
1746                 item_free(i);
1747
1748         while ((i = hashmap_steal_first(globs)))
1749                 item_free(i);
1750
1751         hashmap_free(items);
1752         hashmap_free(globs);
1753
1754         free(arg_include_prefixes);
1755         free(arg_exclude_prefixes);
1756         free(arg_root);
1757
1758         set_free_free(unix_sockets);
1759
1760         mac_selinux_finish();
1761
1762         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1763 }