chiark / gitweb /
docs: remove duplicated install hook
[elogind.git] / src / tmpfiles / tmpfiles.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering, Kay Sievers
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 #include <limits.h>
28 #include <dirent.h>
29 #include <grp.h>
30 #include <pwd.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stddef.h>
34 #include <getopt.h>
35 #include <stdbool.h>
36 #include <time.h>
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <glob.h>
40 #include <fnmatch.h>
41
42 #include "log.h"
43 #include "util.h"
44 #include "mkdir.h"
45 #include "strv.h"
46 #include "label.h"
47 #include "set.h"
48
49 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
50  * them in the file system. This is intended to be used to create
51  * properly owned directories beneath /tmp, /var/tmp, /run, which are
52  * volatile and hence need to be recreated on bootup. */
53
54 typedef enum ItemType {
55         /* These ones take file names */
56         CREATE_FILE = 'f',
57         TRUNCATE_FILE = 'F',
58         WRITE_FILE = 'w',
59         CREATE_DIRECTORY = 'd',
60         TRUNCATE_DIRECTORY = 'D',
61         CREATE_FIFO = 'p',
62         CREATE_SYMLINK = 'L',
63         CREATE_CHAR_DEVICE = 'c',
64         CREATE_BLOCK_DEVICE = 'b',
65
66         /* These ones take globs */
67         IGNORE_PATH = 'x',
68         REMOVE_PATH = 'r',
69         RECURSIVE_REMOVE_PATH = 'R',
70         RELABEL_PATH = 'z',
71         RECURSIVE_RELABEL_PATH = 'Z'
72 } ItemType;
73
74 typedef struct Item {
75         ItemType type;
76
77         char *path;
78         char *argument;
79         uid_t uid;
80         gid_t gid;
81         mode_t mode;
82         usec_t age;
83
84         dev_t major_minor;
85
86         bool uid_set:1;
87         bool gid_set:1;
88         bool mode_set:1;
89         bool age_set:1;
90 } Item;
91
92 static Hashmap *items = NULL, *globs = NULL;
93 static Set *unix_sockets = NULL;
94
95 static bool arg_create = false;
96 static bool arg_clean = false;
97 static bool arg_remove = false;
98
99 static const char *arg_prefix = NULL;
100
101 #define MAX_DEPTH 256
102
103 static bool needs_glob(ItemType t) {
104         return t == IGNORE_PATH || t == REMOVE_PATH || t == RECURSIVE_REMOVE_PATH || t == RELABEL_PATH || t == RECURSIVE_RELABEL_PATH;
105 }
106
107 static struct Item* find_glob(Hashmap *h, const char *match) {
108         Item *j;
109         Iterator i;
110
111         HASHMAP_FOREACH(j, h, i)
112                 if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0)
113                         return j;
114
115         return NULL;
116 }
117
118 static void load_unix_sockets(void) {
119         FILE *f = NULL;
120         char line[LINE_MAX];
121
122         if (unix_sockets)
123                 return;
124
125         /* We maintain a cache of the sockets we found in
126          * /proc/net/unix to speed things up a little. */
127
128         unix_sockets = set_new(string_hash_func, string_compare_func);
129         if (!unix_sockets)
130                 return;
131
132         f = fopen("/proc/net/unix", "re");
133         if (!f)
134                 return;
135
136         /* Skip header */
137         if (!fgets(line, sizeof(line), f))
138                 goto fail;
139
140         for (;;) {
141                 char *p, *s;
142                 int k;
143
144                 if (!fgets(line, sizeof(line), f))
145                         break;
146
147                 truncate_nl(line);
148
149                 p = strchr(line, ':');
150                 if (!p)
151                         continue;
152
153                 if (strlen(p) < 37)
154                         continue;
155
156                 p += 37;
157                 p += strspn(p, WHITESPACE);
158                 p += strcspn(p, WHITESPACE); /* skip one more word */
159                 p += strspn(p, WHITESPACE);
160
161                 if (*p != '/')
162                         continue;
163
164                 s = strdup(p);
165                 if (!s)
166                         goto fail;
167
168                 path_kill_slashes(s);
169
170                 k = set_put(unix_sockets, s);
171                 if (k < 0) {
172                         free(s);
173
174                         if (k != -EEXIST)
175                                 goto fail;
176                 }
177         }
178
179         fclose(f);
180         return;
181
182 fail:
183         set_free_free(unix_sockets);
184         unix_sockets = NULL;
185
186         if (f)
187                 fclose(f);
188 }
189
190 static bool unix_socket_alive(const char *fn) {
191         assert(fn);
192
193         load_unix_sockets();
194
195         if (unix_sockets)
196                 return !!set_get(unix_sockets, (char*) fn);
197
198         /* We don't know, so assume yes */
199         return true;
200 }
201
202 static int dir_cleanup(
203                 const char *p,
204                 DIR *d,
205                 const struct stat *ds,
206                 usec_t cutoff,
207                 dev_t rootdev,
208                 bool mountpoint,
209                 int maxdepth)
210 {
211         struct dirent *dent;
212         struct timespec times[2];
213         bool deleted = false;
214         char *sub_path = NULL;
215         int r = 0;
216
217         while ((dent = readdir(d))) {
218                 struct stat s;
219                 usec_t age;
220
221                 if (streq(dent->d_name, ".") ||
222                     streq(dent->d_name, ".."))
223                         continue;
224
225                 if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
226
227                         if (errno != ENOENT) {
228                                 log_error("stat(%s/%s) failed: %m", p, dent->d_name);
229                                 r = -errno;
230                         }
231
232                         continue;
233                 }
234
235                 /* Stay on the same filesystem */
236                 if (s.st_dev != rootdev)
237                         continue;
238
239                 /* Do not delete read-only files owned by root */
240                 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
241                         continue;
242
243                 free(sub_path);
244                 sub_path = NULL;
245
246                 if (asprintf(&sub_path, "%s/%s", p, dent->d_name) < 0) {
247                         log_error("Out of memory");
248                         r = -ENOMEM;
249                         goto finish;
250                 }
251
252                 /* Is there an item configured for this path? */
253                 if (hashmap_get(items, sub_path))
254                         continue;
255
256                 if (find_glob(globs, sub_path))
257                         continue;
258
259                 if (S_ISDIR(s.st_mode)) {
260
261                         if (mountpoint &&
262                             streq(dent->d_name, "lost+found") &&
263                             s.st_uid == 0)
264                                 continue;
265
266                         if (maxdepth <= 0)
267                                 log_warning("Reached max depth on %s.", sub_path);
268                         else {
269                                 DIR *sub_dir;
270                                 int q;
271
272                                 sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
273                                 if (sub_dir == NULL) {
274                                         if (errno != ENOENT) {
275                                                 log_error("opendir(%s/%s) failed: %m", p, dent->d_name);
276                                                 r = -errno;
277                                         }
278
279                                         continue;
280                                 }
281
282                                 q = dir_cleanup(sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1);
283                                 closedir(sub_dir);
284
285                                 if (q < 0)
286                                         r = q;
287                         }
288
289                         /* Ignore ctime, we change it when deleting */
290                         age = MAX(timespec_load(&s.st_mtim),
291                                   timespec_load(&s.st_atim));
292                         if (age >= cutoff)
293                                 continue;
294
295                         log_debug("rmdir '%s'\n", sub_path);
296
297                         if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
298                                 if (errno != ENOENT && errno != ENOTEMPTY) {
299                                         log_error("rmdir(%s): %m", sub_path);
300                                         r = -errno;
301                                 }
302                         }
303
304                 } else {
305                         /* Skip files for which the sticky bit is
306                          * set. These are semantics we define, and are
307                          * unknown elsewhere. See XDG_RUNTIME_DIR
308                          * specification for details. */
309                         if (s.st_mode & S_ISVTX)
310                                 continue;
311
312                         if (mountpoint && S_ISREG(s.st_mode)) {
313                                 if (streq(dent->d_name, ".journal") &&
314                                     s.st_uid == 0)
315                                         continue;
316
317                                 if (streq(dent->d_name, "aquota.user") ||
318                                     streq(dent->d_name, "aquota.group"))
319                                         continue;
320                         }
321
322                         /* Ignore sockets that are listed in /proc/net/unix */
323                         if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
324                                 continue;
325
326                         /* Ignore device nodes */
327                         if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
328                                 continue;
329
330                         age = MAX3(timespec_load(&s.st_mtim),
331                                    timespec_load(&s.st_atim),
332                                    timespec_load(&s.st_ctim));
333
334                         if (age >= cutoff)
335                                 continue;
336
337                         log_debug("unlink '%s'\n", sub_path);
338
339                         if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
340                                 if (errno != ENOENT) {
341                                         log_error("unlink(%s): %m", sub_path);
342                                         r = -errno;
343                                 }
344                         }
345
346                         deleted = true;
347                 }
348         }
349
350 finish:
351         if (deleted) {
352                 /* Restore original directory timestamps */
353                 times[0] = ds->st_atim;
354                 times[1] = ds->st_mtim;
355
356                 if (futimens(dirfd(d), times) < 0)
357                         log_error("utimensat(%s): %m", p);
358         }
359
360         free(sub_path);
361
362         return r;
363 }
364
365 static int clean_item(Item *i) {
366         DIR *d;
367         struct stat s, ps;
368         bool mountpoint;
369         int r;
370         usec_t cutoff, n;
371
372         assert(i);
373
374         if (i->type != CREATE_DIRECTORY &&
375             i->type != TRUNCATE_DIRECTORY &&
376             i->type != IGNORE_PATH)
377                 return 0;
378
379         if (!i->age_set || i->age <= 0)
380                 return 0;
381
382         n = now(CLOCK_REALTIME);
383         if (n < i->age)
384                 return 0;
385
386         cutoff = n - i->age;
387
388         d = opendir(i->path);
389         if (!d) {
390                 if (errno == ENOENT)
391                         return 0;
392
393                 log_error("Failed to open directory %s: %m", i->path);
394                 return -errno;
395         }
396
397         if (fstat(dirfd(d), &s) < 0) {
398                 log_error("stat(%s) failed: %m", i->path);
399                 r = -errno;
400                 goto finish;
401         }
402
403         if (!S_ISDIR(s.st_mode)) {
404                 log_error("%s is not a directory.", i->path);
405                 r = -ENOTDIR;
406                 goto finish;
407         }
408
409         if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) {
410                 log_error("stat(%s/..) failed: %m", i->path);
411                 r = -errno;
412                 goto finish;
413         }
414
415         mountpoint = s.st_dev != ps.st_dev ||
416                      (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
417
418         r = dir_cleanup(i->path, d, &s, cutoff, s.st_dev, mountpoint, MAX_DEPTH);
419
420 finish:
421         if (d)
422                 closedir(d);
423
424         return r;
425 }
426
427 static int item_set_perms(Item *i, const char *path) {
428         /* not using i->path directly because it may be a glob */
429         if (i->mode_set)
430                 if (chmod(path, i->mode) < 0) {
431                         log_error("chmod(%s) failed: %m", path);
432                         return -errno;
433                 }
434
435         if (i->uid_set || i->gid_set)
436                 if (chown(path,
437                           i->uid_set ? i->uid : (uid_t) -1,
438                           i->gid_set ? i->gid : (gid_t) -1) < 0) {
439
440                         log_error("chown(%s) failed: %m", path);
441                         return -errno;
442                 }
443
444         return label_fix(path, false);
445 }
446
447 static int recursive_relabel_children(Item *i, const char *path) {
448         DIR *d;
449         int ret = 0;
450
451         /* This returns the first error we run into, but nevertheless
452          * tries to go on */
453
454         d = opendir(path);
455         if (!d)
456                 return errno == ENOENT ? 0 : -errno;
457
458         for (;;) {
459                 struct dirent buf, *de;
460                 bool is_dir;
461                 int r;
462                 char *entry_path;
463
464                 r = readdir_r(d, &buf, &de);
465                 if (r != 0) {
466                         if (ret == 0)
467                                 ret = -r;
468                         break;
469                 }
470
471                 if (!de)
472                         break;
473
474                 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
475                         continue;
476
477                 if (asprintf(&entry_path, "%s/%s", path, de->d_name) < 0) {
478                         if (ret == 0)
479                                 ret = -ENOMEM;
480                         continue;
481                 }
482
483                 if (de->d_type == DT_UNKNOWN) {
484                         struct stat st;
485
486                         if (lstat(entry_path, &st) < 0) {
487                                 if (ret == 0 && errno != ENOENT)
488                                         ret = -errno;
489                                 free(entry_path);
490                                 continue;
491                         }
492
493                         is_dir = S_ISDIR(st.st_mode);
494
495                 } else
496                         is_dir = de->d_type == DT_DIR;
497
498                 r = item_set_perms(i, entry_path);
499                 if (r < 0) {
500                         if (ret == 0 && r != -ENOENT)
501                                 ret = r;
502                         free(entry_path);
503                         continue;
504                 }
505
506                 if (is_dir) {
507                         r = recursive_relabel_children(i, entry_path);
508                         if (r < 0 && ret == 0)
509                                 ret = r;
510                 }
511
512                 free(entry_path);
513         }
514
515         closedir(d);
516
517         return ret;
518 }
519
520 static int recursive_relabel(Item *i, const char *path) {
521         int r;
522         struct stat st;
523
524         r = item_set_perms(i, path);
525         if (r < 0)
526                 return r;
527
528         if (lstat(path, &st) < 0)
529                 return -errno;
530
531         if (S_ISDIR(st.st_mode))
532                 r = recursive_relabel_children(i, path);
533
534         return r;
535 }
536
537 static int glob_item(Item *i, int (*action)(Item *, const char *)) {
538         int r = 0, k;
539         glob_t g;
540         char **fn;
541
542         zero(g);
543
544         errno = 0;
545         if ((k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g)) != 0) {
546
547                 if (k != GLOB_NOMATCH) {
548                         if (errno != 0)
549                                 errno = EIO;
550
551                         log_error("glob(%s) failed: %m", i->path);
552                         return -errno;
553                 }
554         }
555
556         STRV_FOREACH(fn, g.gl_pathv)
557                 if ((k = action(i, *fn)) < 0)
558                         r = k;
559
560         globfree(&g);
561         return r;
562 }
563
564 static int create_item(Item *i) {
565         int r, e;
566         mode_t u;
567         struct stat st;
568
569         assert(i);
570
571         switch (i->type) {
572
573         case IGNORE_PATH:
574         case REMOVE_PATH:
575         case RECURSIVE_REMOVE_PATH:
576                 return 0;
577
578         case CREATE_FILE:
579         case TRUNCATE_FILE:
580         case WRITE_FILE: {
581                 int fd, flags;
582
583                 flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
584                         i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;
585
586                 u = umask(0);
587                 label_context_set(i->path, S_IFREG);
588                 fd = open(i->path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
589                 e = errno;
590                 label_context_clear();
591                 umask(u);
592                 errno = e;
593
594                 if (fd < 0) {
595                         if (i->type == WRITE_FILE && errno == ENOENT)
596                                 break;
597
598                         log_error("Failed to create file %s: %m", i->path);
599                         return -errno;
600                 }
601
602                 if (i->argument) {
603                         ssize_t n;
604                         size_t l;
605                         struct iovec iovec[2];
606                         static const char new_line = '\n';
607
608                         l = strlen(i->argument);
609
610                         zero(iovec);
611                         iovec[0].iov_base = i->argument;
612                         iovec[0].iov_len = l;
613
614                         iovec[1].iov_base = (void*) &new_line;
615                         iovec[1].iov_len = 1;
616
617                         n = writev(fd, iovec, 2);
618                         if (n < 0 || (size_t) n != l+1) {
619                                 log_error("Failed to write file %s: %s", i->path, n < 0 ? strerror(-n) : "Short");
620                                 close_nointr_nofail(fd);
621                                 return n < 0 ? n : -EIO;
622                         }
623                 }
624
625                 close_nointr_nofail(fd);
626
627                 if (stat(i->path, &st) < 0) {
628                         log_error("stat(%s) failed: %m", i->path);
629                         return -errno;
630                 }
631
632                 if (!S_ISREG(st.st_mode)) {
633                         log_error("%s is not a file.", i->path);
634                         return -EEXIST;
635                 }
636
637                 r = item_set_perms(i, i->path);
638                 if (r < 0)
639                         return r;
640
641                 break;
642         }
643
644         case TRUNCATE_DIRECTORY:
645         case CREATE_DIRECTORY:
646
647                 u = umask(0);
648                 mkdir_parents(i->path, 0755);
649                 r = mkdir(i->path, i->mode);
650                 umask(u);
651
652                 if (r < 0 && errno != EEXIST) {
653                         log_error("Failed to create directory %s: %m", i->path);
654                         return -errno;
655                 }
656
657                 if (stat(i->path, &st) < 0) {
658                         log_error("stat(%s) failed: %m", i->path);
659                         return -errno;
660                 }
661
662                 if (!S_ISDIR(st.st_mode)) {
663                         log_error("%s is not a directory.", i->path);
664                         return -EEXIST;
665                 }
666
667                 r = item_set_perms(i, i->path);
668                 if (r < 0)
669                         return r;
670
671                 break;
672
673         case CREATE_FIFO:
674
675                 u = umask(0);
676                 r = mkfifo(i->path, i->mode);
677                 umask(u);
678
679                 if (r < 0 && errno != EEXIST) {
680                         log_error("Failed to create fifo %s: %m", i->path);
681                         return -errno;
682                 }
683
684                 if (stat(i->path, &st) < 0) {
685                         log_error("stat(%s) failed: %m", i->path);
686                         return -errno;
687                 }
688
689                 if (!S_ISFIFO(st.st_mode)) {
690                         log_error("%s is not a fifo.", i->path);
691                         return -EEXIST;
692                 }
693
694                 r = item_set_perms(i, i->path);
695                 if (r < 0)
696                         return r;
697
698                 break;
699
700         case CREATE_SYMLINK: {
701                 char *x;
702
703                 label_context_set(i->path, S_IFLNK);
704                 r = symlink(i->argument, i->path);
705                 e = errno;
706                 label_context_clear();
707                 errno = e;
708
709                 if (r < 0 && errno != EEXIST) {
710                         log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
711                         return -errno;
712                 }
713
714                 r = readlink_malloc(i->path, &x);
715                 if (r < 0) {
716                         log_error("readlink(%s) failed: %s", i->path, strerror(-r));
717                         return -errno;
718                 }
719
720                 if (!streq(i->argument, x)) {
721                         free(x);
722                         log_error("%s is not the right symlinks.", i->path);
723                         return -EEXIST;
724                 }
725
726                 free(x);
727                 break;
728         }
729
730         case CREATE_BLOCK_DEVICE:
731         case CREATE_CHAR_DEVICE: {
732
733                 u = umask(0);
734                 label_context_set(i->path, CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);
735                 r = mknod(i->path, i->mode | (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR), i->major_minor);
736                 e = errno;
737                 label_context_clear();
738                 umask(u);
739                 errno = e;
740
741                 if (r < 0 && errno != EEXIST) {
742                         log_error("Failed to create device node %s: %m", i->path);
743                         return -errno;
744                 }
745
746                 if (stat(i->path, &st) < 0) {
747                         log_error("stat(%s) failed: %m", i->path);
748                         return -errno;
749                 }
750
751                 if (i->type == CREATE_BLOCK_DEVICE ? !S_ISBLK(st.st_mode) : !S_ISCHR(st.st_mode)) {
752                         log_error("%s is not a device node.", i->path);
753                         return -EEXIST;
754                 }
755
756                 r = item_set_perms(i, i->path);
757                 if (r < 0)
758                         return r;
759
760                 break;
761         }
762
763         case RELABEL_PATH:
764
765                 r = glob_item(i, item_set_perms);
766                 if (r < 0)
767                         return 0;
768                 break;
769
770         case RECURSIVE_RELABEL_PATH:
771
772                 r = glob_item(i, recursive_relabel);
773                 if (r < 0)
774                         return r;
775         }
776
777         log_debug("%s created successfully.", i->path);
778
779         return 0;
780 }
781
782 static int remove_item_instance(Item *i, const char *instance) {
783         int r;
784
785         assert(i);
786
787         switch (i->type) {
788
789         case CREATE_FILE:
790         case TRUNCATE_FILE:
791         case CREATE_DIRECTORY:
792         case CREATE_FIFO:
793         case CREATE_SYMLINK:
794         case CREATE_BLOCK_DEVICE:
795         case CREATE_CHAR_DEVICE:
796         case IGNORE_PATH:
797         case RELABEL_PATH:
798         case RECURSIVE_RELABEL_PATH:
799         case WRITE_FILE:
800                 break;
801
802         case REMOVE_PATH:
803                 if (remove(instance) < 0 && errno != ENOENT) {
804                         log_error("remove(%s): %m", instance);
805                         return -errno;
806                 }
807
808                 break;
809
810         case TRUNCATE_DIRECTORY:
811         case RECURSIVE_REMOVE_PATH:
812                 r = rm_rf(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
813                 if (r < 0 && r != -ENOENT) {
814                         log_error("rm_rf(%s): %s", instance, strerror(-r));
815                         return r;
816                 }
817
818                 break;
819         }
820
821         return 0;
822 }
823
824 static int remove_item(Item *i) {
825         int r = 0;
826
827         assert(i);
828
829         switch (i->type) {
830
831         case CREATE_FILE:
832         case TRUNCATE_FILE:
833         case CREATE_DIRECTORY:
834         case CREATE_FIFO:
835         case CREATE_SYMLINK:
836         case CREATE_CHAR_DEVICE:
837         case CREATE_BLOCK_DEVICE:
838         case IGNORE_PATH:
839         case RELABEL_PATH:
840         case RECURSIVE_RELABEL_PATH:
841         case WRITE_FILE:
842                 break;
843
844         case REMOVE_PATH:
845         case TRUNCATE_DIRECTORY:
846         case RECURSIVE_REMOVE_PATH:
847                 r = glob_item(i, remove_item_instance);
848                 break;
849         }
850
851         return r;
852 }
853
854 static int process_item(Item *i) {
855         int r, q, p;
856
857         assert(i);
858
859         r = arg_create ? create_item(i) : 0;
860         q = arg_remove ? remove_item(i) : 0;
861         p = arg_clean ? clean_item(i) : 0;
862
863         if (r < 0)
864                 return r;
865
866         if (q < 0)
867                 return q;
868
869         return p;
870 }
871
872 static void item_free(Item *i) {
873         assert(i);
874
875         free(i->path);
876         free(i->argument);
877         free(i);
878 }
879
880 static bool item_equal(Item *a, Item *b) {
881         assert(a);
882         assert(b);
883
884         if (!streq_ptr(a->path, b->path))
885                 return false;
886
887         if (a->type != b->type)
888                 return false;
889
890         if (a->uid_set != b->uid_set ||
891             (a->uid_set && a->uid != b->uid))
892             return false;
893
894         if (a->gid_set != b->gid_set ||
895             (a->gid_set && a->gid != b->gid))
896             return false;
897
898         if (a->mode_set != b->mode_set ||
899             (a->mode_set && a->mode != b->mode))
900             return false;
901
902         if (a->age_set != b->age_set ||
903             (a->age_set && a->age != b->age))
904             return false;
905
906         if ((a->type == CREATE_FILE ||
907              a->type == TRUNCATE_FILE ||
908              a->type == WRITE_FILE ||
909              a->type == CREATE_SYMLINK) &&
910             !streq_ptr(a->argument, b->argument))
911                 return false;
912
913         if ((a->type == CREATE_CHAR_DEVICE ||
914              a->type == CREATE_BLOCK_DEVICE) &&
915             a->major_minor != b->major_minor)
916                 return false;
917
918         return true;
919 }
920
921 static int parse_line(const char *fname, unsigned line, const char *buffer) {
922         Item *i, *existing;
923         char *mode = NULL, *user = NULL, *group = NULL, *age = NULL;
924         char type;
925         Hashmap *h;
926         int r, n = -1;
927
928         assert(fname);
929         assert(line >= 1);
930         assert(buffer);
931
932         i = new0(Item, 1);
933         if (!i) {
934                 log_error("Out of memory");
935                 return -ENOMEM;
936         }
937
938         if (sscanf(buffer,
939                    "%c "
940                    "%ms "
941                    "%ms "
942                    "%ms "
943                    "%ms "
944                    "%ms "
945                    "%n",
946                    &type,
947                    &i->path,
948                    &mode,
949                    &user,
950                    &group,
951                    &age,
952                    &n) < 2) {
953                 log_error("[%s:%u] Syntax error.", fname, line);
954                 r = -EIO;
955                 goto finish;
956         }
957
958         if (n >= 0)  {
959                 n += strspn(buffer+n, WHITESPACE);
960                 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
961                         i->argument = unquote(buffer+n, "\"");
962                         if (!i->argument) {
963                                 log_error("Out of memory");
964                                 return -ENOMEM;
965                         }
966                 }
967         }
968
969         switch(type) {
970
971         case CREATE_FILE:
972         case TRUNCATE_FILE:
973         case CREATE_DIRECTORY:
974         case TRUNCATE_DIRECTORY:
975         case CREATE_FIFO:
976         case IGNORE_PATH:
977         case REMOVE_PATH:
978         case RECURSIVE_REMOVE_PATH:
979         case RELABEL_PATH:
980         case RECURSIVE_RELABEL_PATH:
981                 break;
982
983         case CREATE_SYMLINK:
984                 if (!i->argument) {
985                         log_error("[%s:%u] Symlink file requires argument.", fname, line);
986                         r = -EBADMSG;
987                         goto finish;
988                 }
989                 break;
990
991         case WRITE_FILE:
992                 if (!i->argument) {
993                         log_error("[%s:%u] Write file requires argument.", fname, line);
994                         r = -EBADMSG;
995                         goto finish;
996                 }
997                 break;
998
999         case CREATE_CHAR_DEVICE:
1000         case CREATE_BLOCK_DEVICE: {
1001                 unsigned major, minor;
1002
1003                 if (!i->argument) {
1004                         log_error("[%s:%u] Device file requires argument.", fname, line);
1005                         r = -EBADMSG;
1006                         goto finish;
1007                 }
1008
1009                 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1010                         log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1011                         r = -EBADMSG;
1012                         goto finish;
1013                 }
1014
1015                 i->major_minor = makedev(major, minor);
1016                 break;
1017         }
1018
1019         default:
1020                 log_error("[%s:%u] Unknown file type '%c'.", fname, line, type);
1021                 r = -EBADMSG;
1022                 goto finish;
1023         }
1024
1025         i->type = type;
1026
1027         if (!path_is_absolute(i->path)) {
1028                 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1029                 r = -EBADMSG;
1030                 goto finish;
1031         }
1032
1033         path_kill_slashes(i->path);
1034
1035         if (arg_prefix && !path_startswith(i->path, arg_prefix)) {
1036                 r = 0;
1037                 goto finish;
1038         }
1039
1040         if (user && !streq(user, "-")) {
1041                 const char *u = user;
1042
1043                 r = get_user_creds(&u, &i->uid, NULL, NULL);
1044                 if (r < 0) {
1045                         log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1046                         goto finish;
1047                 }
1048
1049                 i->uid_set = true;
1050         }
1051
1052         if (group && !streq(group, "-")) {
1053                 const char *g = group;
1054
1055                 r = get_group_creds(&g, &i->gid);
1056                 if (r < 0) {
1057                         log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1058                         goto finish;
1059                 }
1060
1061                 i->gid_set = true;
1062         }
1063
1064         if (mode && !streq(mode, "-")) {
1065                 unsigned m;
1066
1067                 if (sscanf(mode, "%o", &m) != 1) {
1068                         log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1069                         r = -ENOENT;
1070                         goto finish;
1071                 }
1072
1073                 i->mode = m;
1074                 i->mode_set = true;
1075         } else
1076                 i->mode =
1077                         i->type == CREATE_DIRECTORY ||
1078                         i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1079
1080         if (age && !streq(age, "-")) {
1081                 if (parse_usec(age, &i->age) < 0) {
1082                         log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1083                         r = -EBADMSG;
1084                         goto finish;
1085                 }
1086
1087                 i->age_set = true;
1088         }
1089
1090         h = needs_glob(i->type) ? globs : items;
1091
1092         existing = hashmap_get(h, i->path);
1093         if (existing) {
1094
1095                 /* Two identical items are fine */
1096                 if (!item_equal(existing, i))
1097                         log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1098
1099                 r = 0;
1100                 goto finish;
1101         }
1102
1103         r = hashmap_put(h, i->path, i);
1104         if (r < 0) {
1105                 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1106                 goto finish;
1107         }
1108
1109         i = NULL;
1110         r = 0;
1111
1112 finish:
1113         free(user);
1114         free(group);
1115         free(mode);
1116         free(age);
1117
1118         if (i)
1119                 item_free(i);
1120
1121         return r;
1122 }
1123
1124 static int help(void) {
1125
1126         printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1127                "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1128                "  -h --help             Show this help\n"
1129                "     --create           Create marked files/directories\n"
1130                "     --clean            Clean up marked directories\n"
1131                "     --remove           Remove marked files/directories\n"
1132                "     --prefix=PATH      Only apply rules that apply to paths with the specified prefix\n",
1133                program_invocation_short_name);
1134
1135         return 0;
1136 }
1137
1138 static int parse_argv(int argc, char *argv[]) {
1139
1140         enum {
1141                 ARG_CREATE,
1142                 ARG_CLEAN,
1143                 ARG_REMOVE,
1144                 ARG_PREFIX
1145         };
1146
1147         static const struct option options[] = {
1148                 { "help",      no_argument,       NULL, 'h'           },
1149                 { "create",    no_argument,       NULL, ARG_CREATE    },
1150                 { "clean",     no_argument,       NULL, ARG_CLEAN     },
1151                 { "remove",    no_argument,       NULL, ARG_REMOVE    },
1152                 { "prefix",    required_argument, NULL, ARG_PREFIX    },
1153                 { NULL,        0,                 NULL, 0             }
1154         };
1155
1156         int c;
1157
1158         assert(argc >= 0);
1159         assert(argv);
1160
1161         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
1162
1163                 switch (c) {
1164
1165                 case 'h':
1166                         help();
1167                         return 0;
1168
1169                 case ARG_CREATE:
1170                         arg_create = true;
1171                         break;
1172
1173                 case ARG_CLEAN:
1174                         arg_clean = true;
1175                         break;
1176
1177                 case ARG_REMOVE:
1178                         arg_remove = true;
1179                         break;
1180
1181                 case ARG_PREFIX:
1182                         arg_prefix = optarg;
1183                         break;
1184
1185                 case '?':
1186                         return -EINVAL;
1187
1188                 default:
1189                         log_error("Unknown option code %c", c);
1190                         return -EINVAL;
1191                 }
1192         }
1193
1194         if (!arg_clean && !arg_create && !arg_remove) {
1195                 log_error("You need to specify at least one of --clean, --create or --remove.");
1196                 return -EINVAL;
1197         }
1198
1199         return 1;
1200 }
1201
1202 static int read_config_file(const char *fn, bool ignore_enoent) {
1203         FILE *f;
1204         unsigned v = 0;
1205         int r = 0;
1206
1207         assert(fn);
1208
1209         f = fopen(fn, "re");
1210         if (!f) {
1211
1212                 if (ignore_enoent && errno == ENOENT)
1213                         return 0;
1214
1215                 log_error("Failed to open %s: %m", fn);
1216                 return -errno;
1217         }
1218
1219         log_debug("apply: %s\n", fn);
1220         for (;;) {
1221                 char line[LINE_MAX], *l;
1222                 int k;
1223
1224                 if (!(fgets(line, sizeof(line), f)))
1225                         break;
1226
1227                 v++;
1228
1229                 l = strstrip(line);
1230                 if (*l == '#' || *l == 0)
1231                         continue;
1232
1233                 if ((k = parse_line(fn, v, l)) < 0)
1234                         if (r == 0)
1235                                 r = k;
1236         }
1237
1238         if (ferror(f)) {
1239                 log_error("Failed to read from file %s: %m", fn);
1240                 if (r == 0)
1241                         r = -EIO;
1242         }
1243
1244         fclose(f);
1245
1246         return r;
1247 }
1248
1249 int main(int argc, char *argv[]) {
1250         int r;
1251         Item *i;
1252         Iterator iterator;
1253
1254         r = parse_argv(argc, argv);
1255         if (r <= 0)
1256                 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1257
1258         log_set_target(LOG_TARGET_AUTO);
1259         log_parse_environment();
1260         log_open();
1261
1262         umask(0022);
1263
1264         label_init(NULL);
1265
1266         items = hashmap_new(string_hash_func, string_compare_func);
1267         globs = hashmap_new(string_hash_func, string_compare_func);
1268
1269         if (!items || !globs) {
1270                 log_error("Out of memory");
1271                 r = EXIT_FAILURE;
1272                 goto finish;
1273         }
1274
1275         r = EXIT_SUCCESS;
1276
1277         if (optind < argc) {
1278                 int j;
1279
1280                 for (j = optind; j < argc; j++)
1281                         if (read_config_file(argv[j], false) < 0)
1282                                 r = EXIT_FAILURE;
1283
1284         } else {
1285                 char **files, **f;
1286
1287                 r = conf_files_list(&files, ".conf",
1288                                     "/etc/tmpfiles.d",
1289                                     "/run/tmpfiles.d",
1290                                     "/usr/local/lib/tmpfiles.d",
1291                                     "/usr/lib/tmpfiles.d",
1292                                     NULL);
1293                 if (r < 0) {
1294                         r = EXIT_FAILURE;
1295                         log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1296                         goto finish;
1297                 }
1298
1299                 STRV_FOREACH(f, files) {
1300                         if (read_config_file(*f, true) < 0)
1301                                 r = EXIT_FAILURE;
1302                 }
1303
1304                 strv_free(files);
1305         }
1306
1307         HASHMAP_FOREACH(i, globs, iterator)
1308                 process_item(i);
1309
1310         HASHMAP_FOREACH(i, items, iterator)
1311                 process_item(i);
1312
1313 finish:
1314         while ((i = hashmap_steal_first(items)))
1315                 item_free(i);
1316
1317         while ((i = hashmap_steal_first(globs)))
1318                 item_free(i);
1319
1320         hashmap_free(items);
1321         hashmap_free(globs);
1322
1323         set_free_free(unix_sockets);
1324
1325         label_finish();
1326
1327         return r;
1328 }