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