chiark / gitweb /
tmpfiles: support globs
[elogind.git] / src / tmpfiles.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering, Kay Sievers
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 #include <limits.h>
28 #include <dirent.h>
29 #include <grp.h>
30 #include <pwd.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stddef.h>
34 #include <getopt.h>
35 #include <stdbool.h>
36 #include <time.h>
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <glob.h>
40 #include <fnmatch.h>
41
42 #include "log.h"
43 #include "util.h"
44 #include "strv.h"
45 #include "label.h"
46 #include "set.h"
47
48 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
49  * them in the file system. This is intended to be used to create
50  * properly owned directories beneath /tmp, /var/tmp, /var/run and
51  * /var/lock which are volatile and hence need to be recreated on
52  * bootup. */
53
54 enum {
55         /* These ones take file names */
56         CREATE_FILE = 'f',
57         TRUNCATE_FILE = 'F',
58         CREATE_DIRECTORY = 'd',
59         TRUNCATE_DIRECTORY = 'D',
60
61         /* These ones take globs */
62         IGNORE_PATH = 'x',
63         REMOVE_PATH = 'r',
64         RECURSIVE_REMOVE_PATH = 'R'
65 };
66
67 typedef struct Item {
68         char type;
69
70         char *path;
71         uid_t uid;
72         gid_t gid;
73         mode_t mode;
74         usec_t age;
75
76         bool uid_set:1;
77         bool gid_set:1;
78         bool mode_set:1;
79         bool age_set:1;
80 } Item;
81
82 static Hashmap *items = NULL, *globs = NULL;
83
84 static bool arg_create = false;
85 static bool arg_clean = false;
86 static bool arg_remove = false;
87
88 #define MAX_DEPTH 256
89
90 static bool needs_glob(int t) {
91         return t == IGNORE_PATH || t == REMOVE_PATH || t == RECURSIVE_REMOVE_PATH;
92 }
93
94 static struct Item* find_glob(Hashmap *h, const char *match) {
95         Item *j;
96         Iterator i;
97
98         HASHMAP_FOREACH(j, h, i)
99                 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
100                         return j;
101
102         return NULL;
103 }
104
105 static int dir_cleanup(
106                 const char *p,
107                 DIR *d,
108                 const struct stat *ds,
109                 usec_t cutoff,
110                 dev_t rootdev,
111                 bool mountpoint,
112                 int maxdepth)
113 {
114         struct dirent *dent;
115         struct timespec times[2];
116         bool deleted = false;
117         char *sub_path = NULL;
118         int r = 0;
119
120         while ((dent = readdir(d))) {
121                 struct stat s;
122                 usec_t age;
123
124                 if (streq(dent->d_name, ".") ||
125                     streq(dent->d_name, ".."))
126                         continue;
127
128                 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
129
130                         if (errno != ENOENT) {
131                                 log_error("stat(%s/%s) failed: %m", p, dent->d_name);
132                                 r = -errno;
133                         }
134
135                         continue;
136                 }
137
138                 /* Stay on the same filesystem */
139                 if (s.st_dev != rootdev)
140                         continue;
141
142                 /* Do not delete read-only files owned by root */
143                 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
144                         continue;
145
146                 free(sub_path);
147                 sub_path = NULL;
148
149                 if (asprintf(&sub_path, "%s/%s", p, dent->d_name) < 0) {
150                         log_error("Out of memory");
151                         r = -ENOMEM;
152                         goto finish;
153                 }
154
155                 /* Is there an item configured for this path? */
156                 if (hashmap_get(items, sub_path))
157                         continue;
158
159                 if (find_glob(globs, sub_path))
160                         continue;
161
162                 if (S_ISDIR(s.st_mode)) {
163
164                         if (mountpoint &&
165                             streq(dent->d_name, "lost+found") &&
166                             s.st_uid == 0)
167                                 continue;
168
169                         if (maxdepth <= 0)
170                                 log_warning("Reached max depth on %s.", sub_path);
171                         else {
172                                 DIR *sub_dir;
173                                 int q;
174
175                                 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW);
176                                 if (sub_dir == NULL) {
177                                         if (errno != ENOENT) {
178                                                 log_error("opendir(%s/%s) failed: %m", p, dent->d_name);
179                                                 r = -errno;
180                                         }
181
182                                         continue;
183                                 }
184
185                                 q = dir_cleanup(sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1);
186                                 closedir(sub_dir);
187
188                                 if (q < 0)
189                                         r = q;
190                         }
191
192                         /* Ignore ctime, we change it when deleting */
193                         age = MAX(timespec_load(&s.st_mtim),
194                                   timespec_load(&s.st_atim));
195                         if (age >= cutoff)
196                                 continue;
197
198                         log_debug("rmdir '%s'\n", sub_path);
199
200                         if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
201                                 if (errno != ENOENT && errno != ENOTEMPTY) {
202                                         log_error("rmdir(%s): %m", sub_path);
203                                         r = -errno;
204                                 }
205                         }
206
207                 } else {
208                         /* Skip files for which the sticky bit is
209                          * set. These are semantics we define, and are
210                          * unknown elsewhere. See XDG_RUNTIME_DIR
211                          * specification for details. */
212                         if (s.st_mode & S_ISVTX)
213                                 continue;
214
215                         if (mountpoint) {
216                                 if (streq(dent->d_name, ".journal") &&
217                                     s.st_uid == 0)
218                                         continue;
219
220                                 if (streq(dent->d_name, "aquota.user") ||
221                                     streq(dent->d_name, "aquota.group"))
222                                         continue;
223                         }
224
225                         age = MAX3(timespec_load(&s.st_mtim),
226                                    timespec_load(&s.st_atim),
227                                    timespec_load(&s.st_ctim));
228
229                         if (age >= cutoff)
230                                 continue;
231
232                         log_debug("unlink '%s'\n", sub_path);
233
234                         if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
235                                 if (errno != ENOENT) {
236                                         log_error("unlink(%s): %m", sub_path);
237                                         r = -errno;
238                                 }
239                         }
240
241                         deleted = true;
242                 }
243         }
244
245 finish:
246         if (deleted) {
247                 /* Restore original directory timestamps */
248                 times[0] = ds->st_atim;
249                 times[1] = ds->st_mtim;
250
251                 if (futimens(dirfd(d), times) < 0)
252                         log_error("utimensat(%s): %m", p);
253         }
254
255         free(sub_path);
256
257         return r;
258 }
259
260 static int clean_item(Item *i) {
261         DIR *d;
262         struct stat s, ps;
263         bool mountpoint;
264         int r;
265         usec_t cutoff, n;
266
267         assert(i);
268
269         if (i->type != CREATE_DIRECTORY &&
270             i->type != TRUNCATE_DIRECTORY &&
271             i->type != IGNORE_PATH)
272                 return 0;
273
274         if (!i->age_set || i->age <= 0)
275                 return 0;
276
277         n = now(CLOCK_REALTIME);
278         if (n < i->age)
279                 return 0;
280
281         cutoff = n - i->age;
282
283         d = opendir(i->path);
284         if (!d) {
285                 if (errno == ENOENT)
286                         return 0;
287
288                 log_error("Failed to open directory %s: %m", i->path);
289                 return -errno;
290         }
291
292         if (fstat(dirfd(d), &s) < 0) {
293                 log_error("stat(%s) failed: %m", i->path);
294                 r = -errno;
295                 goto finish;
296         }
297
298         if (!S_ISDIR(s.st_mode)) {
299                 log_error("%s is not a directory.", i->path);
300                 r = -ENOTDIR;
301                 goto finish;
302         }
303
304         if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) {
305                 log_error("stat(%s/..) failed: %m", i->path);
306                 r = -errno;
307                 goto finish;
308         }
309
310         mountpoint = s.st_dev != ps.st_dev ||
311                      (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
312
313         r = dir_cleanup(i->path, d, &s, cutoff, s.st_dev, mountpoint, MAX_DEPTH);
314
315 finish:
316         if (d)
317                 closedir(d);
318
319         return r;
320 }
321
322 static int create_item(Item *i) {
323         int fd = -1, r;
324         mode_t u;
325         struct stat st;
326
327         assert(i);
328
329         switch (i->type) {
330
331         case IGNORE_PATH:
332         case REMOVE_PATH:
333         case RECURSIVE_REMOVE_PATH:
334                 return 0;
335
336         case CREATE_FILE:
337         case TRUNCATE_FILE:
338
339                 u = umask(0);
340                 fd = open(i->path, O_CREAT|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW|
341                           (i->type == TRUNCATE_FILE ? O_TRUNC : 0), i->mode);
342                 umask(u);
343
344                 if (fd < 0) {
345                         log_error("Failed to create file %s: %m", i->path);
346                         r = -errno;
347                         goto finish;
348                 }
349
350                 if (fstat(fd, &st) < 0) {
351                         log_error("stat(%s) failed: %m", i->path);
352                         r = -errno;
353                         goto finish;
354                 }
355
356                 if (!S_ISREG(st.st_mode)) {
357                         log_error("%s is not a file.", i->path);
358                         r = -EEXIST;
359                         goto finish;
360                 }
361
362                 if (i->mode_set)
363                         if (fchmod(fd, i->mode) < 0) {
364                                 log_error("chmod(%s) failed: %m", i->path);
365                                 r = -errno;
366                                 goto finish;
367                         }
368
369                 if (i->uid_set || i->gid_set)
370                         if (fchown(fd,
371                                    i->uid_set ? i->uid : (uid_t) -1,
372                                    i->gid_set ? i->gid : (gid_t) -1) < 0) {
373                                 log_error("chown(%s) failed: %m", i->path);
374                                 r = -errno;
375                                 goto finish;
376                         }
377
378                 break;
379
380         case TRUNCATE_DIRECTORY:
381         case CREATE_DIRECTORY:
382
383                 u = umask(0);
384                 r = mkdir(i->path, i->mode);
385                 umask(u);
386
387                 if (r < 0 && errno != EEXIST) {
388                         log_error("Failed to create directory %s: %m", i->path);
389                         r = -errno;
390                         goto finish;
391                 }
392
393                 if (stat(i->path, &st) < 0) {
394                         log_error("stat(%s) failed: %m", i->path);
395                         r = -errno;
396                         goto finish;
397                 }
398
399                 if (!S_ISDIR(st.st_mode)) {
400                         log_error("%s is not a directory.", i->path);
401                         r = -EEXIST;
402                         goto finish;
403                 }
404
405                 if (i->mode_set)
406                         if (chmod(i->path, i->mode) < 0) {
407                                 log_error("chmod(%s) failed: %m", i->path);
408                                 r = -errno;
409                                 goto finish;
410                         }
411
412                 if (i->uid_set || i->gid_set)
413                         if (chown(i->path,
414                                   i->uid_set ? i->uid : (uid_t) -1,
415                                   i->gid_set ? i->gid : (gid_t) -1) < 0) {
416
417                                 log_error("chown(%s) failed: %m", i->path);
418                                 r = -errno;
419                                 goto finish;
420                         }
421
422                 break;
423         }
424
425         if ((r = label_fix(i->path)) < 0)
426                 goto finish;
427
428         log_debug("%s created successfully.", i->path);
429
430 finish:
431         if (fd >= 0)
432                 close_nointr_nofail(fd);
433
434         return r;
435 }
436
437 static int remove_item(Item *i, const char *instance) {
438         int r;
439
440         assert(i);
441
442         switch (i->type) {
443
444         case CREATE_FILE:
445         case TRUNCATE_FILE:
446         case CREATE_DIRECTORY:
447         case IGNORE_PATH:
448                 break;
449
450         case REMOVE_PATH:
451                 if (remove(instance) < 0 && errno != ENOENT) {
452                         log_error("remove(%s): %m", instance);
453                         return -errno;
454                 }
455
456                 break;
457
458         case TRUNCATE_DIRECTORY:
459         case RECURSIVE_REMOVE_PATH:
460                 if ((r = rm_rf(instance, false, i->type == RECURSIVE_REMOVE_PATH)) < 0 &&
461                     r != -ENOENT) {
462                         log_error("rm_rf(%s): %s", instance, strerror(-r));
463                         return r;
464                 }
465
466                 break;
467         }
468
469         return 0;
470 }
471
472 static int remove_item_glob(Item *i) {
473         assert(i);
474
475         switch (i->type) {
476
477         case CREATE_FILE:
478         case TRUNCATE_FILE:
479         case CREATE_DIRECTORY:
480         case IGNORE_PATH:
481                 break;
482
483         case REMOVE_PATH:
484         case TRUNCATE_DIRECTORY:
485         case RECURSIVE_REMOVE_PATH: {
486                 int r = 0, k;
487                 glob_t g;
488                 char **fn;
489
490                 zero(g);
491
492                 errno = 0;
493                 if ((k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g)) != 0) {
494
495                         if (k != GLOB_NOMATCH) {
496                                 if (errno != 0)
497                                         errno = EIO;
498
499                                 log_error("glob(%s) failed: %m", i->path);
500                                 return -errno;
501                         }
502                 }
503
504                 STRV_FOREACH(fn, g.gl_pathv)
505                         if ((k = remove_item(i, *fn)) < 0)
506                                 r = k;
507
508                 globfree(&g);
509                 return r;
510         }
511         }
512
513         return 0;
514 }
515
516 static int process_item(Item *i) {
517         int r, q, p;
518
519         assert(i);
520
521         r = arg_create ? create_item(i) : 0;
522         q = arg_remove ? remove_item_glob(i) : 0;
523         p = arg_clean ? clean_item(i) : 0;
524
525         if (r < 0)
526                 return r;
527
528         if (q < 0)
529                 return q;
530
531         return p;
532 }
533
534 static void item_free(Item *i) {
535         assert(i);
536
537         free(i->path);
538         free(i);
539 }
540
541 static int parse_line(const char *fname, unsigned line, const char *buffer, const char *prefix) {
542         Item *i;
543         char *mode = NULL, *user = NULL, *group = NULL, *age = NULL;
544         int r;
545
546         assert(fname);
547         assert(line >= 1);
548         assert(buffer);
549
550         if (!(i = new0(Item, 1))) {
551                 log_error("Out of memory");
552                 return -ENOMEM;
553         }
554
555         if (sscanf(buffer,
556                    "%c "
557                    "%ms "
558                    "%ms "
559                    "%ms "
560                    "%ms "
561                    "%ms",
562                    &i->type,
563                    &i->path,
564                    &mode,
565                    &user,
566                    &group,
567                    &age) < 2) {
568                 log_error("[%s:%u] Syntax error.", fname, line);
569                 r = -EIO;
570                 goto finish;
571         }
572
573         if (i->type != CREATE_FILE &&
574             i->type != TRUNCATE_FILE &&
575             i->type != CREATE_DIRECTORY &&
576             i->type != TRUNCATE_DIRECTORY &&
577             i->type != IGNORE_PATH &&
578             i->type != REMOVE_PATH &&
579             i->type != RECURSIVE_REMOVE_PATH) {
580                 log_error("[%s:%u] Unknown file type '%c'.", fname, line, i->type);
581                 r = -EBADMSG;
582                 goto finish;
583         }
584
585         if (!path_is_absolute(i->path)) {
586                 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
587                 r = -EBADMSG;
588                 goto finish;
589         }
590
591         path_kill_slashes(i->path);
592
593         if (prefix && !path_startswith(i->path, prefix)) {
594                 r = 0;
595                 goto finish;
596         }
597
598         if (user && !streq(user, "-")) {
599                 unsigned long lu;
600                 struct passwd *p;
601
602                 if (streq(user, "root") || streq(user, "0"))
603                         i->uid = 0;
604                 else if (safe_atolu(user, &lu) >= 0)
605                         i->uid = (uid_t) lu;
606                 else if ((p = getpwnam(user)))
607                         i->uid = p->pw_uid;
608                 else {
609                         log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
610                         r = -ENOENT;
611                         goto finish;
612                 }
613
614                 i->uid_set = true;
615         }
616
617         if (group && !streq(group, "-")) {
618                 unsigned long lu;
619                 struct group *g;
620
621                 if (streq(group, "root") || streq(group, "0"))
622                         i->gid = 0;
623                 else if (safe_atolu(group, &lu) >= 0)
624                         i->gid = (gid_t) lu;
625                 else if ((g = getgrnam(group)))
626                         i->gid = g->gr_gid;
627                 else {
628                         log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
629                         r = -ENOENT;
630                         goto finish;
631                 }
632
633                 i->gid_set = true;
634         }
635
636         if (mode && !streq(mode, "-")) {
637                 unsigned m;
638
639                 if (sscanf(mode, "%o", &m) != 1) {
640                         log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
641                         r = -ENOENT;
642                         goto finish;
643                 }
644
645                 i->mode = m;
646                 i->mode_set = true;
647         } else
648                 i->mode = i->type == CREATE_DIRECTORY ? 0755 : 0644;
649
650         if (age && !streq(age, "-")) {
651                 if (parse_usec(age, &i->age) < 0) {
652                         log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
653                         r = -EBADMSG;
654                         goto finish;
655                 }
656
657                 i->age_set = true;
658         }
659
660         if ((r = hashmap_put(needs_glob(i->type) ? globs : items, i->path, i)) < 0) {
661                 if (r == -EEXIST) {
662                         log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
663                         r = 0;
664                         goto finish;
665                 }
666
667                 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
668                 goto finish;
669         }
670
671         i = NULL;
672         r = 0;
673
674 finish:
675         free(user);
676         free(group);
677         free(mode);
678         free(age);
679
680         if (i)
681                 item_free(i);
682
683         return r;
684 }
685
686 static int scandir_filter(const struct dirent *d) {
687         assert(d);
688
689         if (ignore_file(d->d_name))
690                 return 0;
691
692         if (d->d_type != DT_REG &&
693             d->d_type != DT_LNK)
694                 return 0;
695
696         return endswith(d->d_name, ".conf");
697 }
698
699 static int help(void) {
700
701         printf("%s [OPTIONS...]\n\n"
702                "Create and clean up temporary directories.\n\n"
703                "  -h --help             Show this help\n"
704                "     --create           Create marked files/directories\n"
705                "     --clean            Clean up marked directories\n"
706                "     --remove           Remove marked files/directories\n",
707                program_invocation_short_name);
708
709         return 0;
710 }
711
712 static int parse_argv(int argc, char *argv[]) {
713
714         enum {
715                 ARG_CREATE,
716                 ARG_CLEAN,
717                 ARG_REMOVE
718         };
719
720         static const struct option options[] = {
721                 { "help",      no_argument,       NULL, 'h'           },
722                 { "create",    no_argument,       NULL, ARG_CREATE    },
723                 { "clean",     no_argument,       NULL, ARG_CLEAN     },
724                 { "remove",    no_argument,       NULL, ARG_REMOVE    },
725                 { NULL,        0,                 NULL, 0             }
726         };
727
728         int c;
729
730         assert(argc >= 0);
731         assert(argv);
732
733         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
734
735                 switch (c) {
736
737                 case 'h':
738                         help();
739                         return 0;
740
741                 case ARG_CREATE:
742                         arg_create = true;
743                         break;
744
745                 case ARG_CLEAN:
746                         arg_clean = true;
747                         break;
748
749                 case ARG_REMOVE:
750                         arg_remove = true;
751                         break;
752
753                 case '?':
754                         return -EINVAL;
755
756                 default:
757                         log_error("Unknown option code %c", c);
758                         return -EINVAL;
759                 }
760         }
761
762         if (!arg_clean && !arg_create && !arg_remove) {
763                 help();
764                 return -EINVAL;
765         }
766
767         return 1;
768 }
769
770 int main(int argc, char *argv[]) {
771         struct dirent **de = NULL;
772         int r, n, j;
773         const char *prefix = NULL;
774         Item *i;
775         Iterator iterator;
776
777         if ((r = parse_argv(argc, argv)) <= 0)
778                 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
779
780         if (optind < argc)
781                 prefix = argv[optind];
782         else
783                 prefix = "/";
784
785         log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
786         log_parse_environment();
787         log_open();
788
789         label_init();
790
791         items = hashmap_new(string_hash_func, string_compare_func);
792         globs = hashmap_new(string_hash_func, string_compare_func);
793
794         if (!items || !globs) {
795                 log_error("Out of memory");
796                 r = EXIT_FAILURE;
797                 goto finish;
798         }
799
800         if ((n = scandir("/etc/tmpfiles.d/", &de, scandir_filter, alphasort)) < 0) {
801
802                 if (errno == ENOENT)
803                         r = EXIT_SUCCESS;
804                 else {
805                         log_error("Failed to enumerate /etc/tmpfiles.d/ files: %m");
806                         r = EXIT_FAILURE;
807                 }
808
809                 goto finish;
810         }
811
812         r = EXIT_SUCCESS;
813
814         for (j = 0; j < n; j++) {
815                 int k;
816                 char *fn;
817                 FILE *f;
818                 unsigned v;
819
820                 k = asprintf(&fn, "/etc/tmpfiles.d/%s", de[j]->d_name);
821                 free(de[j]);
822
823                 if (k < 0) {
824                         log_error("Failed to allocate file name.");
825                         r = EXIT_FAILURE;
826                         continue;
827                 }
828
829                 if (!(f = fopen(fn, "re"))) {
830
831                         if (errno != ENOENT) {
832                                 log_error("Failed to open %s: %m", fn);
833                                 r = EXIT_FAILURE;
834                         }
835
836                         free(fn);
837                         continue;
838                 }
839
840                 v = 0;
841                 for (;;) {
842                         char line[LINE_MAX], *l;
843
844                         if (!(fgets(line, sizeof(line), f)))
845                                 break;
846
847                         v++;
848
849                         l = strstrip(line);
850                         if (*l == '#' || *l == 0)
851                                 continue;
852
853                         if (parse_line(fn, v, l, prefix) < 0)
854                                 r = EXIT_FAILURE;
855                 }
856
857                 if (ferror(f)) {
858                         r = EXIT_FAILURE;
859                         log_error("Failed to read from file %s: %m", fn);
860                 }
861
862                 free(fn);
863
864                 fclose(f);
865         }
866
867         free(de);
868
869         HASHMAP_FOREACH(i, globs, iterator)
870                 if (process_item(i) < 0)
871                         r = EXIT_FAILURE;
872
873         HASHMAP_FOREACH(i, items, iterator)
874                 if (process_item(i) < 0)
875                         r = EXIT_FAILURE;
876
877 finish:
878         while ((i = hashmap_steal_first(items)))
879                 item_free(i);
880
881         hashmap_free(items);
882         hashmap_free(globs);
883
884         label_finish();
885
886         return r;
887 }