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