chiark / gitweb /
tmpfiles: add 'a' type to set ACLs
[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 static int item_set_perms_children(Item *i, const char *path) {
704         _cleanup_closedir_ DIR *d;
705         int r = 0;
706
707         assert(i);
708         assert(path);
709
710         /* This returns the first error we run into, but nevertheless
711          * tries to go on */
712
713         d = opendir(path);
714         if (!d)
715                 return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
716
717         for (;;) {
718                 _cleanup_free_ char *p = NULL;
719                 struct dirent *de;
720                 int q;
721
722                 errno = 0;
723                 de = readdir(d);
724                 if (!de) {
725                         if (errno != 0 && r == 0)
726                                 r = -errno;
727
728                         break;
729                 }
730
731                 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
732                         continue;
733
734                 p = strjoin(path, "/", de->d_name, NULL);
735                 if (!p)
736                         return -ENOMEM;
737
738                 q = item_set_perms(i, p);
739                 if (q < 0 && q != -ENOENT && r == 0)
740                         r = q;
741
742                 if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
743                         q = item_set_perms_children(i, p);
744                         if (q < 0 && r == 0)
745                                 r = q;
746                 }
747         }
748
749         return r;
750 }
751
752 static int item_set_perms_recursive(Item *i, const char *path) {
753         int r, q;
754
755         assert(i);
756         assert(path);
757
758         r = item_set_perms(i, path);
759         if (r < 0)
760                 return r;
761
762         q = item_set_perms_children(i, path);
763         if (q < 0 && r == 0)
764                 r = q;
765
766         return r;
767 }
768
769 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
770         _cleanup_globfree_ glob_t g = {};
771         int r = 0, k;
772         char **fn;
773
774         errno = 0;
775         k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
776         if (k != 0 && k != GLOB_NOMATCH) {
777                 if (errno == 0)
778                         errno = EIO;
779
780                 log_error_errno(errno, "glob(%s) failed: %m", i->path);
781                 return -errno;
782         }
783
784         STRV_FOREACH(fn, g.gl_pathv) {
785                 k = action(i, *fn);
786                 if (k < 0 && r == 0)
787                         r = k;
788         }
789
790         return r;
791 }
792
793 static int create_item(Item *i) {
794         struct stat st;
795         int r = 0;
796
797         assert(i);
798
799         switch (i->type) {
800
801         case IGNORE_PATH:
802         case IGNORE_DIRECTORY_PATH:
803         case REMOVE_PATH:
804         case RECURSIVE_REMOVE_PATH:
805                 return 0;
806
807         case CREATE_FILE:
808         case TRUNCATE_FILE:
809                 r = write_one_file(i, i->path);
810                 if (r < 0)
811                         return r;
812                 break;
813
814         case COPY_FILES:
815                 r = copy_tree(i->argument, i->path, false);
816                 if (r < 0) {
817                         struct stat a, b;
818
819                         if (r != -EEXIST)
820                                 return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
821
822                         if (stat(i->argument, &a) < 0)
823                                 return log_error_errno(errno, "stat(%s) failed: %m", i->argument);
824
825                         if (stat(i->path, &b) < 0)
826                                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
827
828                         if ((a.st_mode ^ b.st_mode) & S_IFMT) {
829                                 log_debug("Can't copy to %s, file exists already and is of different type", i->path);
830                                 return 0;
831                         }
832                 }
833
834                 r = item_set_perms(i, i->path);
835                 if (r < 0)
836                         return r;
837
838                 break;
839
840         case WRITE_FILE:
841                 r = glob_item(i, write_one_file);
842                 if (r < 0)
843                         return r;
844
845                 break;
846
847         case CREATE_DIRECTORY:
848         case TRUNCATE_DIRECTORY:
849         case CREATE_SUBVOLUME:
850
851                 RUN_WITH_UMASK(0000)
852                         mkdir_parents_label(i->path, 0755);
853
854                 if (i->type == CREATE_SUBVOLUME) {
855                         RUN_WITH_UMASK((~i->mode) & 0777)
856                                 r = btrfs_subvol_make(i->path);
857                 } else
858                         r = 0;
859
860                 if (IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY) || r == -ENOTTY) {
861                         RUN_WITH_UMASK(0000)
862                                 r = mkdir_label(i->path, i->mode);
863                 }
864
865                 if (r < 0) {
866                         if (r != -EEXIST)
867                                 return log_error_errno(r, "Failed to create directory or subvolume %s: %m", i->path);
868
869                         if (stat(i->path, &st) < 0)
870                                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
871
872                         if (!S_ISDIR(st.st_mode)) {
873                                 log_debug("%s already exists and is not a directory.", i->path);
874                                 return 0;
875                         }
876                 }
877
878                 r = item_set_perms(i, i->path);
879                 if (r < 0)
880                         return r;
881
882                 break;
883
884         case CREATE_FIFO:
885
886                 RUN_WITH_UMASK(0000) {
887                         mac_selinux_create_file_prepare(i->path, S_IFIFO);
888                         r = mkfifo(i->path, i->mode);
889                         mac_selinux_create_file_clear();
890                 }
891
892                 if (r < 0) {
893                         if (errno != EEXIST)
894                                 return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
895
896                         if (stat(i->path, &st) < 0)
897                                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
898
899                         if (!S_ISFIFO(st.st_mode)) {
900
901                                 if (i->force) {
902
903                                         RUN_WITH_UMASK(0000) {
904                                                 mac_selinux_create_file_prepare(i->path, S_IFIFO);
905                                                 r = mkfifo_atomic(i->path, i->mode);
906                                                 mac_selinux_create_file_clear();
907                                         }
908
909                                         if (r < 0)
910                                                 return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
911                                 } else {
912                                         log_debug("%s is not a fifo.", i->path);
913                                         return 0;
914                                 }
915                         }
916                 }
917
918                 r = item_set_perms(i, i->path);
919                 if (r < 0)
920                         return r;
921
922                 break;
923
924         case CREATE_SYMLINK:
925
926                 mac_selinux_create_file_prepare(i->path, S_IFLNK);
927                 r = symlink(i->argument, i->path);
928                 mac_selinux_create_file_clear();
929
930                 if (r < 0) {
931                         _cleanup_free_ char *x = NULL;
932
933                         if (errno != EEXIST)
934                                 return log_error_errno(errno, "symlink(%s, %s) failed: %m", i->argument, i->path);
935
936                         r = readlink_malloc(i->path, &x);
937                         if (r < 0 || !streq(i->argument, x)) {
938
939                                 if (i->force) {
940                                         mac_selinux_create_file_prepare(i->path, S_IFLNK);
941                                         r = symlink_atomic(i->argument, i->path);
942                                         mac_selinux_create_file_clear();
943
944                                         if (r < 0)
945                                                 return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
946                                 } else {
947                                         log_debug("%s is not a symlink or does not point to the correct path.", i->path);
948                                         return 0;
949                                 }
950                         }
951                 }
952
953                 break;
954
955         case CREATE_BLOCK_DEVICE:
956         case CREATE_CHAR_DEVICE: {
957                 mode_t file_type;
958
959                 if (have_effective_cap(CAP_MKNOD) == 0) {
960                         /* In a container we lack CAP_MKNOD. We
961                         shouldn't attempt to create the device node in
962                         that case to avoid noise, and we don't support
963                         virtualized devices in containers anyway. */
964
965                         log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
966                         return 0;
967                 }
968
969                 file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
970
971                 RUN_WITH_UMASK(0000) {
972                         mac_selinux_create_file_prepare(i->path, file_type);
973                         r = mknod(i->path, i->mode | file_type, i->major_minor);
974                         mac_selinux_create_file_clear();
975                 }
976
977                 if (r < 0) {
978                         if (errno == EPERM) {
979                                 log_debug("We lack permissions, possibly because of cgroup configuration; "
980                                           "skipping creation of device node %s.", i->path);
981                                 return 0;
982                         }
983
984                         if (errno != EEXIST)
985                                 return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
986
987                         if (stat(i->path, &st) < 0)
988                                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
989
990                         if ((st.st_mode & S_IFMT) != file_type) {
991
992                                 if (i->force) {
993
994                                         RUN_WITH_UMASK(0000) {
995                                                 mac_selinux_create_file_prepare(i->path, file_type);
996                                                 r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
997                                                 mac_selinux_create_file_clear();
998                                         }
999
1000                                         if (r < 0)
1001                                                 return log_error_errno(r, "Failed to create device node %s: %m", i->path);
1002                                 } else {
1003                                         log_debug("%s is not a device node.", i->path);
1004                                         return 0;
1005                                 }
1006                         }
1007                 }
1008
1009                 r = item_set_perms(i, i->path);
1010                 if (r < 0)
1011                         return r;
1012
1013                 break;
1014         }
1015
1016         case ADJUST_MODE:
1017         case RELABEL_PATH:
1018
1019                 r = glob_item(i, item_set_perms);
1020                 if (r < 0)
1021                         return r;
1022                 break;
1023
1024         case RECURSIVE_RELABEL_PATH:
1025
1026                 r = glob_item(i, item_set_perms_recursive);
1027                 if (r < 0)
1028                         return r;
1029                 break;
1030
1031         case SET_XATTR:
1032                 r = item_set_xattrs(i, i->path);
1033                 if (r < 0)
1034                         return r;
1035                 break;
1036
1037         case SET_ACL:
1038                 r = item_set_acl(i, i->path);
1039                 if (r < 0)
1040                         return r;
1041         }
1042
1043         log_debug("%s created successfully.", i->path);
1044
1045         return 0;
1046 }
1047
1048 static int remove_item_instance(Item *i, const char *instance) {
1049         int r;
1050
1051         assert(i);
1052
1053         switch (i->type) {
1054
1055         case CREATE_FILE:
1056         case TRUNCATE_FILE:
1057         case CREATE_DIRECTORY:
1058         case CREATE_SUBVOLUME:
1059         case CREATE_FIFO:
1060         case CREATE_SYMLINK:
1061         case CREATE_BLOCK_DEVICE:
1062         case CREATE_CHAR_DEVICE:
1063         case IGNORE_PATH:
1064         case IGNORE_DIRECTORY_PATH:
1065         case ADJUST_MODE:
1066         case RELABEL_PATH:
1067         case RECURSIVE_RELABEL_PATH:
1068         case WRITE_FILE:
1069         case COPY_FILES:
1070         case SET_XATTR:
1071         case SET_ACL:
1072                 break;
1073
1074         case REMOVE_PATH:
1075                 if (remove(instance) < 0 && errno != ENOENT)
1076                         return log_error_errno(errno, "rm(%s): %m", instance);
1077
1078                 break;
1079
1080         case TRUNCATE_DIRECTORY:
1081         case RECURSIVE_REMOVE_PATH:
1082                 /* FIXME: we probably should use dir_cleanup() here
1083                  * instead of rm_rf() so that 'x' is honoured. */
1084                 r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
1085                 if (r < 0 && r != -ENOENT)
1086                         return log_error_errno(r, "rm_rf(%s): %m", instance);
1087
1088                 break;
1089         }
1090
1091         return 0;
1092 }
1093
1094 static int remove_item(Item *i) {
1095         int r = 0;
1096
1097         assert(i);
1098
1099         switch (i->type) {
1100
1101         case CREATE_FILE:
1102         case TRUNCATE_FILE:
1103         case CREATE_DIRECTORY:
1104         case CREATE_SUBVOLUME:
1105         case CREATE_FIFO:
1106         case CREATE_SYMLINK:
1107         case CREATE_CHAR_DEVICE:
1108         case CREATE_BLOCK_DEVICE:
1109         case IGNORE_PATH:
1110         case IGNORE_DIRECTORY_PATH:
1111         case ADJUST_MODE:
1112         case RELABEL_PATH:
1113         case RECURSIVE_RELABEL_PATH:
1114         case WRITE_FILE:
1115         case COPY_FILES:
1116         case SET_XATTR:
1117         case SET_ACL:
1118                 break;
1119
1120         case REMOVE_PATH:
1121         case TRUNCATE_DIRECTORY:
1122         case RECURSIVE_REMOVE_PATH:
1123                 r = glob_item(i, remove_item_instance);
1124                 break;
1125         }
1126
1127         return r;
1128 }
1129
1130 static int clean_item_instance(Item *i, const char* instance) {
1131         _cleanup_closedir_ DIR *d = NULL;
1132         struct stat s, ps;
1133         bool mountpoint;
1134         int r;
1135         usec_t cutoff, n;
1136
1137         assert(i);
1138
1139         if (!i->age_set)
1140                 return 0;
1141
1142         n = now(CLOCK_REALTIME);
1143         if (n < i->age)
1144                 return 0;
1145
1146         cutoff = n - i->age;
1147
1148         d = opendir(instance);
1149         if (!d) {
1150                 if (errno == ENOENT || errno == ENOTDIR)
1151                         return 0;
1152
1153                 log_error_errno(errno, "Failed to open directory %s: %m", i->path);
1154                 return -errno;
1155         }
1156
1157         if (fstat(dirfd(d), &s) < 0)
1158                 return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1159
1160         if (!S_ISDIR(s.st_mode)) {
1161                 log_error("%s is not a directory.", i->path);
1162                 return -ENOTDIR;
1163         }
1164
1165         if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
1166                 return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
1167
1168         mountpoint = s.st_dev != ps.st_dev ||
1169                      (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
1170
1171         r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
1172                         MAX_DEPTH, i->keep_first_level);
1173         return r;
1174 }
1175
1176 static int clean_item(Item *i) {
1177         int r = 0;
1178
1179         assert(i);
1180
1181         switch (i->type) {
1182         case CREATE_DIRECTORY:
1183         case CREATE_SUBVOLUME:
1184         case TRUNCATE_DIRECTORY:
1185         case IGNORE_PATH:
1186         case COPY_FILES:
1187                 clean_item_instance(i, i->path);
1188                 break;
1189         case IGNORE_DIRECTORY_PATH:
1190                 r = glob_item(i, clean_item_instance);
1191                 break;
1192         default:
1193                 break;
1194         }
1195
1196         return r;
1197 }
1198
1199 static int process_item_array(ItemArray *array);
1200
1201 static int process_item(Item *i) {
1202         int r, q, p, t = 0;
1203         _cleanup_free_ char *prefix = NULL;
1204
1205         assert(i);
1206
1207         if (i->done)
1208                 return 0;
1209
1210         i->done = true;
1211
1212         prefix = malloc(strlen(i->path) + 1);
1213         if (!prefix)
1214                 return log_oom();
1215
1216         PATH_FOREACH_PREFIX(prefix, i->path) {
1217                 ItemArray *j;
1218
1219                 j = hashmap_get(items, prefix);
1220                 if (j) {
1221                         int s;
1222
1223                         s = process_item_array(j);
1224                         if (s < 0 && t == 0)
1225                                 t = s;
1226                 }
1227         }
1228
1229         r = arg_create ? create_item(i) : 0;
1230         q = arg_remove ? remove_item(i) : 0;
1231         p = arg_clean ? clean_item(i) : 0;
1232
1233         return t < 0 ? t :
1234                 r < 0 ? r :
1235                 q < 0 ? q :
1236                 p;
1237 }
1238
1239 static int process_item_array(ItemArray *array) {
1240         unsigned n;
1241         int r = 0, k;
1242
1243         assert(array);
1244
1245         for (n = 0; n < array->count; n++) {
1246                 k = process_item(array->items + n);
1247                 if (k < 0 && r == 0)
1248                         r = k;
1249         }
1250
1251         return r;
1252 }
1253
1254 static void item_free_contents(Item *i) {
1255         assert(i);
1256         free(i->path);
1257         free(i->argument);
1258         strv_free(i->xattrs);
1259
1260 #ifdef HAVE_ACL
1261         acl_free(i->acl_access);
1262         acl_free(i->acl_default);
1263 #endif
1264 }
1265
1266 static void item_array_free(ItemArray *a) {
1267         unsigned n;
1268
1269         if (!a)
1270                 return;
1271
1272         for (n = 0; n < a->count; n++)
1273                 item_free_contents(a->items + n);
1274         free(a->items);
1275         free(a);
1276 }
1277
1278 static bool item_compatible(Item *a, Item *b) {
1279         assert(a);
1280         assert(b);
1281         assert(streq(a->path, b->path));
1282
1283         if (takes_ownership(a->type) && takes_ownership(b->type))
1284                 /* check if the items are the same */
1285                 return  streq_ptr(a->argument, b->argument) &&
1286
1287                         a->uid_set == b->uid_set &&
1288                         a->uid == b->uid &&
1289
1290                         a->gid_set == b->gid_set &&
1291                         a->gid == b->gid &&
1292
1293                         a->mode_set == b->mode_set &&
1294                         a->mode == b->mode &&
1295
1296                         a->age_set == b->age_set &&
1297                         a->age == b->age &&
1298
1299                         a->mask_perms == b->mask_perms &&
1300
1301                         a->keep_first_level == b->keep_first_level &&
1302
1303                         a->major_minor == b->major_minor;
1304
1305         return true;
1306 }
1307
1308 static bool should_include_path(const char *path) {
1309         char **prefix;
1310
1311         STRV_FOREACH(prefix, arg_exclude_prefixes)
1312                 if (path_startswith(path, *prefix))
1313                         return false;
1314
1315         STRV_FOREACH(prefix, arg_include_prefixes)
1316                 if (path_startswith(path, *prefix))
1317                         return true;
1318
1319         /* no matches, so we should include this path only if we
1320          * have no whitelist at all */
1321         return strv_length(arg_include_prefixes) == 0;
1322 }
1323
1324 static int parse_line(const char *fname, unsigned line, const char *buffer) {
1325
1326         static const Specifier specifier_table[] = {
1327                 { 'm', specifier_machine_id, NULL },
1328                 { 'b', specifier_boot_id, NULL },
1329                 { 'H', specifier_host_name, NULL },
1330                 { 'v', specifier_kernel_release, NULL },
1331                 {}
1332         };
1333
1334         _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
1335         _cleanup_(item_free_contents) Item i = {};
1336         ItemArray *existing;
1337         Hashmap *h;
1338         int r, c = -1, pos;
1339         bool force = false, boot = false;
1340
1341         assert(fname);
1342         assert(line >= 1);
1343         assert(buffer);
1344
1345         r = sscanf(buffer,
1346                    "%ms %ms %ms %ms %ms %ms %n",
1347                    &action,
1348                    &path,
1349                    &mode,
1350                    &user,
1351                    &group,
1352                    &age,
1353                    &c);
1354         if (r < 2) {
1355                 log_error("[%s:%u] Syntax error.", fname, line);
1356                 return -EIO;
1357         }
1358
1359         if (isempty(action)) {
1360                 log_error("[%s:%u] Command too short '%s'.", fname, line, action);
1361                 return -EINVAL;
1362         }
1363
1364         for (pos = 1; action[pos]; pos++) {
1365                 if (action[pos] == '!' && !boot)
1366                         boot = true;
1367                 else if (action[pos] == '+' && !force)
1368                         force = true;
1369                 else {
1370                         log_error("[%s:%u] Unknown modifiers in command '%s'",
1371                                   fname, line, action);
1372                         return -EINVAL;
1373                 }
1374         }
1375
1376         if (boot && !arg_boot)
1377                 return 0;
1378
1379         i.type = action[0];
1380         i.force = force;
1381
1382         r = specifier_printf(path, specifier_table, NULL, &i.path);
1383         if (r < 0) {
1384                 log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path);
1385                 return r;
1386         }
1387
1388         if (c >= 0)  {
1389                 c += strspn(buffer+c, WHITESPACE);
1390                 if (buffer[c] != 0 && (buffer[c] != '-' || buffer[c+1] != 0)) {
1391                         i.argument = unquote(buffer+c, "\"");
1392                         if (!i.argument)
1393                                 return log_oom();
1394                 }
1395         }
1396
1397         switch (i.type) {
1398
1399         case CREATE_FILE:
1400         case TRUNCATE_FILE:
1401         case CREATE_DIRECTORY:
1402         case CREATE_SUBVOLUME:
1403         case TRUNCATE_DIRECTORY:
1404         case CREATE_FIFO:
1405         case IGNORE_PATH:
1406         case IGNORE_DIRECTORY_PATH:
1407         case REMOVE_PATH:
1408         case RECURSIVE_REMOVE_PATH:
1409         case ADJUST_MODE:
1410         case RELABEL_PATH:
1411         case RECURSIVE_RELABEL_PATH:
1412                 break;
1413
1414         case CREATE_SYMLINK:
1415                 if (!i.argument) {
1416                         i.argument = strappend("/usr/share/factory/", i.path);
1417                         if (!i.argument)
1418                                 return log_oom();
1419                 }
1420                 break;
1421
1422         case WRITE_FILE:
1423                 if (!i.argument) {
1424                         log_error("[%s:%u] Write file requires argument.", fname, line);
1425                         return -EBADMSG;
1426                 }
1427                 break;
1428
1429         case COPY_FILES:
1430                 if (!i.argument) {
1431                         i.argument = strappend("/usr/share/factory/", i.path);
1432                         if (!i.argument)
1433                                 return log_oom();
1434                 } else if (!path_is_absolute(i.argument)) {
1435                         log_error("[%s:%u] Source path is not absolute.", fname, line);
1436                         return -EBADMSG;
1437                 }
1438
1439                 path_kill_slashes(i.argument);
1440                 break;
1441
1442         case CREATE_CHAR_DEVICE:
1443         case CREATE_BLOCK_DEVICE: {
1444                 unsigned major, minor;
1445
1446                 if (!i.argument) {
1447                         log_error("[%s:%u] Device file requires argument.", fname, line);
1448                         return -EBADMSG;
1449                 }
1450
1451                 if (sscanf(i.argument, "%u:%u", &major, &minor) != 2) {
1452                         log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i.argument);
1453                         return -EBADMSG;
1454                 }
1455
1456                 i.major_minor = makedev(major, minor);
1457                 break;
1458         }
1459
1460         case SET_XATTR:
1461                 if (!i.argument) {
1462                         log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
1463                         return -EBADMSG;
1464                 }
1465                 r = get_xattrs_from_arg(&i);
1466                 if (r < 0)
1467                         return r;
1468                 break;
1469
1470         case SET_ACL:
1471                 if (!i.argument) {
1472                         log_error("[%s:%u] Set ACLs requires argument.", fname, line);
1473                         return -EBADMSG;
1474                 }
1475                 r = get_acls_from_arg(&i);
1476                 if (r < 0)
1477                         return r;
1478                 break;
1479
1480         default:
1481                 log_error("[%s:%u] Unknown command type '%c'.", fname, line, i.type);
1482                 return -EBADMSG;
1483         }
1484
1485         if (!path_is_absolute(i.path)) {
1486                 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i.path);
1487                 return -EBADMSG;
1488         }
1489
1490         path_kill_slashes(i.path);
1491
1492         if (!should_include_path(i.path))
1493                 return 0;
1494
1495         if (arg_root) {
1496                 char *p;
1497
1498                 p = strappend(arg_root, i.path);
1499                 if (!p)
1500                         return log_oom();
1501
1502                 free(i.path);
1503                 i.path = p;
1504         }
1505
1506         if (user && !streq(user, "-")) {
1507                 const char *u = user;
1508
1509                 r = get_user_creds(&u, &i.uid, NULL, NULL, NULL);
1510                 if (r < 0) {
1511                         log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1512                         return r;
1513                 }
1514
1515                 i.uid_set = true;
1516         }
1517
1518         if (group && !streq(group, "-")) {
1519                 const char *g = group;
1520
1521                 r = get_group_creds(&g, &i.gid);
1522                 if (r < 0) {
1523                         log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1524                         return r;
1525                 }
1526
1527                 i.gid_set = true;
1528         }
1529
1530         if (mode && !streq(mode, "-")) {
1531                 const char *mm = mode;
1532                 unsigned m;
1533
1534                 if (*mm == '~') {
1535                         i.mask_perms = true;
1536                         mm++;
1537                 }
1538
1539                 if (sscanf(mm, "%o", &m) != 1) {
1540                         log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1541                         return -ENOENT;
1542                 }
1543
1544                 i.mode = m;
1545                 i.mode_set = true;
1546         } else
1547                 i.mode = IN_SET(i.type, CREATE_DIRECTORY, CREATE_SUBVOLUME, TRUNCATE_DIRECTORY)
1548                         ? 0755 : 0644;
1549
1550         if (age && !streq(age, "-")) {
1551                 const char *a = age;
1552
1553                 if (*a == '~') {
1554                         i.keep_first_level = true;
1555                         a++;
1556                 }
1557
1558                 if (parse_sec(a, &i.age) < 0) {
1559                         log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1560                         return -EBADMSG;
1561                 }
1562
1563                 i.age_set = true;
1564         }
1565
1566         h = needs_glob(i.type) ? globs : items;
1567
1568         existing = hashmap_get(h, i.path);
1569         if (existing) {
1570                 unsigned n;
1571
1572                 for (n = 0; n < existing->count; n++) {
1573                         if (!item_compatible(existing->items + n, &i))
1574                                 log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
1575                                             fname, line, i.path);
1576                 }
1577         } else {
1578                 existing = new0(ItemArray, 1);
1579                 r = hashmap_put(h, i.path, existing);
1580                 if (r < 0)
1581                         return log_oom();
1582         }
1583
1584         if (!GREEDY_REALLOC(existing->items, existing->size, existing->count + 1))
1585                 return log_oom();
1586
1587         memcpy(existing->items + existing->count++, &i, sizeof(i));
1588         zero(i);
1589         return 0;
1590 }
1591
1592 static void help(void) {
1593         printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1594                "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1595                "  -h --help                 Show this help\n"
1596                "     --version              Show package version\n"
1597                "     --create               Create marked files/directories\n"
1598                "     --clean                Clean up marked directories\n"
1599                "     --remove               Remove marked files/directories\n"
1600                "     --boot                 Execute actions only safe at boot\n"
1601                "     --prefix=PATH          Only apply rules that apply to paths with the specified prefix\n"
1602                "     --exclude-prefix=PATH  Ignore rules that apply to paths with the specified prefix\n"
1603                "     --root=PATH            Operate on an alternate filesystem root\n",
1604                program_invocation_short_name);
1605 }
1606
1607 static int parse_argv(int argc, char *argv[]) {
1608
1609         enum {
1610                 ARG_VERSION = 0x100,
1611                 ARG_CREATE,
1612                 ARG_CLEAN,
1613                 ARG_REMOVE,
1614                 ARG_BOOT,
1615                 ARG_PREFIX,
1616                 ARG_EXCLUDE_PREFIX,
1617                 ARG_ROOT,
1618         };
1619
1620         static const struct option options[] = {
1621                 { "help",           no_argument,         NULL, 'h'                },
1622                 { "version",        no_argument,         NULL, ARG_VERSION        },
1623                 { "create",         no_argument,         NULL, ARG_CREATE         },
1624                 { "clean",          no_argument,         NULL, ARG_CLEAN          },
1625                 { "remove",         no_argument,         NULL, ARG_REMOVE         },
1626                 { "boot",           no_argument,         NULL, ARG_BOOT           },
1627                 { "prefix",         required_argument,   NULL, ARG_PREFIX         },
1628                 { "exclude-prefix", required_argument,   NULL, ARG_EXCLUDE_PREFIX },
1629                 { "root",           required_argument,   NULL, ARG_ROOT           },
1630                 {}
1631         };
1632
1633         int c;
1634
1635         assert(argc >= 0);
1636         assert(argv);
1637
1638         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1639
1640                 switch (c) {
1641
1642                 case 'h':
1643                         help();
1644                         return 0;
1645
1646                 case ARG_VERSION:
1647                         puts(PACKAGE_STRING);
1648                         puts(SYSTEMD_FEATURES);
1649                         return 0;
1650
1651                 case ARG_CREATE:
1652                         arg_create = true;
1653                         break;
1654
1655                 case ARG_CLEAN:
1656                         arg_clean = true;
1657                         break;
1658
1659                 case ARG_REMOVE:
1660                         arg_remove = true;
1661                         break;
1662
1663                 case ARG_BOOT:
1664                         arg_boot = true;
1665                         break;
1666
1667                 case ARG_PREFIX:
1668                         if (strv_push(&arg_include_prefixes, optarg) < 0)
1669                                 return log_oom();
1670                         break;
1671
1672                 case ARG_EXCLUDE_PREFIX:
1673                         if (strv_push(&arg_exclude_prefixes, optarg) < 0)
1674                                 return log_oom();
1675                         break;
1676
1677                 case ARG_ROOT:
1678                         free(arg_root);
1679                         arg_root = path_make_absolute_cwd(optarg);
1680                         if (!arg_root)
1681                                 return log_oom();
1682
1683                         path_kill_slashes(arg_root);
1684                         break;
1685
1686                 case '?':
1687                         return -EINVAL;
1688
1689                 default:
1690                         assert_not_reached("Unhandled option");
1691                 }
1692
1693         if (!arg_clean && !arg_create && !arg_remove) {
1694                 log_error("You need to specify at least one of --clean, --create or --remove.");
1695                 return -EINVAL;
1696         }
1697
1698         return 1;
1699 }
1700
1701 static int read_config_file(const char *fn, bool ignore_enoent) {
1702         _cleanup_fclose_ FILE *f = NULL;
1703         char line[LINE_MAX];
1704         Iterator iterator;
1705         unsigned v = 0;
1706         Item *i;
1707         int r;
1708
1709         assert(fn);
1710
1711         r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
1712         if (r < 0) {
1713                 if (ignore_enoent && r == -ENOENT)
1714                         return 0;
1715
1716                 return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
1717         }
1718
1719         FOREACH_LINE(line, f, break) {
1720                 char *l;
1721                 int k;
1722
1723                 v++;
1724
1725                 l = strstrip(line);
1726                 if (*l == '#' || *l == 0)
1727                         continue;
1728
1729                 k = parse_line(fn, v, l);
1730                 if (k < 0 && r == 0)
1731                         r = k;
1732         }
1733
1734         /* we have to determine age parameter for each entry of type X */
1735         HASHMAP_FOREACH(i, globs, iterator) {
1736                 Iterator iter;
1737                 Item *j, *candidate_item = NULL;
1738
1739                 if (i->type != IGNORE_DIRECTORY_PATH)
1740                         continue;
1741
1742                 HASHMAP_FOREACH(j, items, iter) {
1743                         if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME)
1744                                 continue;
1745
1746                         if (path_equal(j->path, i->path)) {
1747                                 candidate_item = j;
1748                                 break;
1749                         }
1750
1751                         if ((!candidate_item && path_startswith(i->path, j->path)) ||
1752                             (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
1753                                 candidate_item = j;
1754                 }
1755
1756                 if (candidate_item && candidate_item->age_set) {
1757                         i->age = candidate_item->age;
1758                         i->age_set = true;
1759                 }
1760         }
1761
1762         if (ferror(f)) {
1763                 log_error_errno(errno, "Failed to read from file %s: %m", fn);
1764                 if (r == 0)
1765                         r = -EIO;
1766         }
1767
1768         return r;
1769 }
1770
1771 int main(int argc, char *argv[]) {
1772         int r, k;
1773         ItemArray *a;
1774         Iterator iterator;
1775
1776         r = parse_argv(argc, argv);
1777         if (r <= 0)
1778                 goto finish;
1779
1780         log_set_target(LOG_TARGET_AUTO);
1781         log_parse_environment();
1782         log_open();
1783
1784         umask(0022);
1785
1786         mac_selinux_init(NULL);
1787
1788         items = hashmap_new(&string_hash_ops);
1789         globs = hashmap_new(&string_hash_ops);
1790
1791         if (!items || !globs) {
1792                 r = log_oom();
1793                 goto finish;
1794         }
1795
1796         r = 0;
1797
1798         if (optind < argc) {
1799                 int j;
1800
1801                 for (j = optind; j < argc; j++) {
1802                         k = read_config_file(argv[j], false);
1803                         if (k < 0 && r == 0)
1804                                 r = k;
1805                 }
1806
1807         } else {
1808                 _cleanup_strv_free_ char **files = NULL;
1809                 char **f;
1810
1811                 r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
1812                 if (r < 0) {
1813                         log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
1814                         goto finish;
1815                 }
1816
1817                 STRV_FOREACH(f, files) {
1818                         k = read_config_file(*f, true);
1819                         if (k < 0 && r == 0)
1820                                 r = k;
1821                 }
1822         }
1823
1824         HASHMAP_FOREACH(a, globs, iterator) {
1825                 k = process_item_array(a);
1826                 if (k < 0 && r == 0)
1827                         r = k;
1828         }
1829
1830         HASHMAP_FOREACH(a, items, iterator) {
1831                 k = process_item_array(a);
1832                 if (k < 0 && r == 0)
1833                         r = k;
1834         }
1835
1836 finish:
1837         while ((a = hashmap_steal_first(items)))
1838                 item_array_free(a);
1839
1840         while ((a = hashmap_steal_first(globs)))
1841                 item_array_free(a);
1842
1843         hashmap_free(items);
1844         hashmap_free(globs);
1845
1846         free(arg_include_prefixes);
1847         free(arg_exclude_prefixes);
1848         free(arg_root);
1849
1850         set_free_free(unix_sockets);
1851
1852         mac_selinux_finish();
1853
1854         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1855 }