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