chiark / gitweb /
mkdir: append _label to all mkdir() calls that explicitly set the selinux context
[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
621                         /* It's OK if we don't write the trailing
622                          * newline, hence we check for l, instead of
623                          * l+1 here. Files in /sys often refuse
624                          * writing of the trailing newline. */
625                         if (n < 0 || (size_t) n < l) {
626                                 log_error("Failed to write file %s: %s", i->path, n < 0 ? strerror(-n) : "Short write");
627                                 close_nointr_nofail(fd);
628                                 return n < 0 ? n : -EIO;
629                         }
630                 }
631
632                 close_nointr_nofail(fd);
633
634                 if (stat(i->path, &st) < 0) {
635                         log_error("stat(%s) failed: %m", i->path);
636                         return -errno;
637                 }
638
639                 if (!S_ISREG(st.st_mode)) {
640                         log_error("%s is not a file.", i->path);
641                         return -EEXIST;
642                 }
643
644                 r = item_set_perms(i, i->path);
645                 if (r < 0)
646                         return r;
647
648                 break;
649         }
650
651         case TRUNCATE_DIRECTORY:
652         case CREATE_DIRECTORY:
653
654                 u = umask(0);
655                 mkdir_parents_label(i->path, 0755);
656                 r = mkdir(i->path, i->mode);
657                 umask(u);
658
659                 if (r < 0 && errno != EEXIST) {
660                         log_error("Failed to create directory %s: %m", i->path);
661                         return -errno;
662                 }
663
664                 if (stat(i->path, &st) < 0) {
665                         log_error("stat(%s) failed: %m", i->path);
666                         return -errno;
667                 }
668
669                 if (!S_ISDIR(st.st_mode)) {
670                         log_error("%s is not a directory.", i->path);
671                         return -EEXIST;
672                 }
673
674                 r = item_set_perms(i, i->path);
675                 if (r < 0)
676                         return r;
677
678                 break;
679
680         case CREATE_FIFO:
681
682                 u = umask(0);
683                 r = mkfifo(i->path, i->mode);
684                 umask(u);
685
686                 if (r < 0 && errno != EEXIST) {
687                         log_error("Failed to create fifo %s: %m", i->path);
688                         return -errno;
689                 }
690
691                 if (stat(i->path, &st) < 0) {
692                         log_error("stat(%s) failed: %m", i->path);
693                         return -errno;
694                 }
695
696                 if (!S_ISFIFO(st.st_mode)) {
697                         log_error("%s is not a fifo.", i->path);
698                         return -EEXIST;
699                 }
700
701                 r = item_set_perms(i, i->path);
702                 if (r < 0)
703                         return r;
704
705                 break;
706
707         case CREATE_SYMLINK: {
708                 char *x;
709
710                 label_context_set(i->path, S_IFLNK);
711                 r = symlink(i->argument, i->path);
712                 e = errno;
713                 label_context_clear();
714                 errno = e;
715
716                 if (r < 0 && errno != EEXIST) {
717                         log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
718                         return -errno;
719                 }
720
721                 r = readlink_malloc(i->path, &x);
722                 if (r < 0) {
723                         log_error("readlink(%s) failed: %s", i->path, strerror(-r));
724                         return -errno;
725                 }
726
727                 if (!streq(i->argument, x)) {
728                         free(x);
729                         log_error("%s is not the right symlinks.", i->path);
730                         return -EEXIST;
731                 }
732
733                 free(x);
734                 break;
735         }
736
737         case CREATE_BLOCK_DEVICE:
738         case CREATE_CHAR_DEVICE: {
739
740                 u = umask(0);
741                 label_context_set(i->path, CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);
742                 r = mknod(i->path, i->mode | (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR), i->major_minor);
743                 e = errno;
744                 label_context_clear();
745                 umask(u);
746                 errno = e;
747
748                 if (r < 0 && errno != EEXIST) {
749                         log_error("Failed to create device node %s: %m", i->path);
750                         return -errno;
751                 }
752
753                 if (stat(i->path, &st) < 0) {
754                         log_error("stat(%s) failed: %m", i->path);
755                         return -errno;
756                 }
757
758                 if (i->type == CREATE_BLOCK_DEVICE ? !S_ISBLK(st.st_mode) : !S_ISCHR(st.st_mode)) {
759                         log_error("%s is not a device node.", i->path);
760                         return -EEXIST;
761                 }
762
763                 r = item_set_perms(i, i->path);
764                 if (r < 0)
765                         return r;
766
767                 break;
768         }
769
770         case RELABEL_PATH:
771
772                 r = glob_item(i, item_set_perms);
773                 if (r < 0)
774                         return 0;
775                 break;
776
777         case RECURSIVE_RELABEL_PATH:
778
779                 r = glob_item(i, recursive_relabel);
780                 if (r < 0)
781                         return r;
782         }
783
784         log_debug("%s created successfully.", i->path);
785
786         return 0;
787 }
788
789 static int remove_item_instance(Item *i, const char *instance) {
790         int r;
791
792         assert(i);
793
794         switch (i->type) {
795
796         case CREATE_FILE:
797         case TRUNCATE_FILE:
798         case CREATE_DIRECTORY:
799         case CREATE_FIFO:
800         case CREATE_SYMLINK:
801         case CREATE_BLOCK_DEVICE:
802         case CREATE_CHAR_DEVICE:
803         case IGNORE_PATH:
804         case RELABEL_PATH:
805         case RECURSIVE_RELABEL_PATH:
806         case WRITE_FILE:
807                 break;
808
809         case REMOVE_PATH:
810                 if (remove(instance) < 0 && errno != ENOENT) {
811                         log_error("remove(%s): %m", instance);
812                         return -errno;
813                 }
814
815                 break;
816
817         case TRUNCATE_DIRECTORY:
818         case RECURSIVE_REMOVE_PATH:
819                 r = rm_rf(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
820                 if (r < 0 && r != -ENOENT) {
821                         log_error("rm_rf(%s): %s", instance, strerror(-r));
822                         return r;
823                 }
824
825                 break;
826         }
827
828         return 0;
829 }
830
831 static int remove_item(Item *i) {
832         int r = 0;
833
834         assert(i);
835
836         switch (i->type) {
837
838         case CREATE_FILE:
839         case TRUNCATE_FILE:
840         case CREATE_DIRECTORY:
841         case CREATE_FIFO:
842         case CREATE_SYMLINK:
843         case CREATE_CHAR_DEVICE:
844         case CREATE_BLOCK_DEVICE:
845         case IGNORE_PATH:
846         case RELABEL_PATH:
847         case RECURSIVE_RELABEL_PATH:
848         case WRITE_FILE:
849                 break;
850
851         case REMOVE_PATH:
852         case TRUNCATE_DIRECTORY:
853         case RECURSIVE_REMOVE_PATH:
854                 r = glob_item(i, remove_item_instance);
855                 break;
856         }
857
858         return r;
859 }
860
861 static int process_item(Item *i) {
862         int r, q, p;
863
864         assert(i);
865
866         r = arg_create ? create_item(i) : 0;
867         q = arg_remove ? remove_item(i) : 0;
868         p = arg_clean ? clean_item(i) : 0;
869
870         if (r < 0)
871                 return r;
872
873         if (q < 0)
874                 return q;
875
876         return p;
877 }
878
879 static void item_free(Item *i) {
880         assert(i);
881
882         free(i->path);
883         free(i->argument);
884         free(i);
885 }
886
887 static bool item_equal(Item *a, Item *b) {
888         assert(a);
889         assert(b);
890
891         if (!streq_ptr(a->path, b->path))
892                 return false;
893
894         if (a->type != b->type)
895                 return false;
896
897         if (a->uid_set != b->uid_set ||
898             (a->uid_set && a->uid != b->uid))
899             return false;
900
901         if (a->gid_set != b->gid_set ||
902             (a->gid_set && a->gid != b->gid))
903             return false;
904
905         if (a->mode_set != b->mode_set ||
906             (a->mode_set && a->mode != b->mode))
907             return false;
908
909         if (a->age_set != b->age_set ||
910             (a->age_set && a->age != b->age))
911             return false;
912
913         if ((a->type == CREATE_FILE ||
914              a->type == TRUNCATE_FILE ||
915              a->type == WRITE_FILE ||
916              a->type == CREATE_SYMLINK) &&
917             !streq_ptr(a->argument, b->argument))
918                 return false;
919
920         if ((a->type == CREATE_CHAR_DEVICE ||
921              a->type == CREATE_BLOCK_DEVICE) &&
922             a->major_minor != b->major_minor)
923                 return false;
924
925         return true;
926 }
927
928 static int parse_line(const char *fname, unsigned line, const char *buffer) {
929         Item *i, *existing;
930         char *mode = NULL, *user = NULL, *group = NULL, *age = NULL;
931         char type;
932         Hashmap *h;
933         int r, n = -1;
934
935         assert(fname);
936         assert(line >= 1);
937         assert(buffer);
938
939         i = new0(Item, 1);
940         if (!i) {
941                 log_error("Out of memory");
942                 return -ENOMEM;
943         }
944
945         if (sscanf(buffer,
946                    "%c "
947                    "%ms "
948                    "%ms "
949                    "%ms "
950                    "%ms "
951                    "%ms "
952                    "%n",
953                    &type,
954                    &i->path,
955                    &mode,
956                    &user,
957                    &group,
958                    &age,
959                    &n) < 2) {
960                 log_error("[%s:%u] Syntax error.", fname, line);
961                 r = -EIO;
962                 goto finish;
963         }
964
965         if (n >= 0)  {
966                 n += strspn(buffer+n, WHITESPACE);
967                 if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) {
968                         i->argument = unquote(buffer+n, "\"");
969                         if (!i->argument) {
970                                 log_error("Out of memory");
971                                 return -ENOMEM;
972                         }
973                 }
974         }
975
976         switch(type) {
977
978         case CREATE_FILE:
979         case TRUNCATE_FILE:
980         case CREATE_DIRECTORY:
981         case TRUNCATE_DIRECTORY:
982         case CREATE_FIFO:
983         case IGNORE_PATH:
984         case REMOVE_PATH:
985         case RECURSIVE_REMOVE_PATH:
986         case RELABEL_PATH:
987         case RECURSIVE_RELABEL_PATH:
988                 break;
989
990         case CREATE_SYMLINK:
991                 if (!i->argument) {
992                         log_error("[%s:%u] Symlink file requires argument.", fname, line);
993                         r = -EBADMSG;
994                         goto finish;
995                 }
996                 break;
997
998         case WRITE_FILE:
999                 if (!i->argument) {
1000                         log_error("[%s:%u] Write file requires argument.", fname, line);
1001                         r = -EBADMSG;
1002                         goto finish;
1003                 }
1004                 break;
1005
1006         case CREATE_CHAR_DEVICE:
1007         case CREATE_BLOCK_DEVICE: {
1008                 unsigned major, minor;
1009
1010                 if (!i->argument) {
1011                         log_error("[%s:%u] Device file requires argument.", fname, line);
1012                         r = -EBADMSG;
1013                         goto finish;
1014                 }
1015
1016                 if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) {
1017                         log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument);
1018                         r = -EBADMSG;
1019                         goto finish;
1020                 }
1021
1022                 i->major_minor = makedev(major, minor);
1023                 break;
1024         }
1025
1026         default:
1027                 log_error("[%s:%u] Unknown file type '%c'.", fname, line, type);
1028                 r = -EBADMSG;
1029                 goto finish;
1030         }
1031
1032         i->type = type;
1033
1034         if (!path_is_absolute(i->path)) {
1035                 log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
1036                 r = -EBADMSG;
1037                 goto finish;
1038         }
1039
1040         path_kill_slashes(i->path);
1041
1042         if (arg_prefix && !path_startswith(i->path, arg_prefix)) {
1043                 r = 0;
1044                 goto finish;
1045         }
1046
1047         if (user && !streq(user, "-")) {
1048                 const char *u = user;
1049
1050                 r = get_user_creds(&u, &i->uid, NULL, NULL);
1051                 if (r < 0) {
1052                         log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
1053                         goto finish;
1054                 }
1055
1056                 i->uid_set = true;
1057         }
1058
1059         if (group && !streq(group, "-")) {
1060                 const char *g = group;
1061
1062                 r = get_group_creds(&g, &i->gid);
1063                 if (r < 0) {
1064                         log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
1065                         goto finish;
1066                 }
1067
1068                 i->gid_set = true;
1069         }
1070
1071         if (mode && !streq(mode, "-")) {
1072                 unsigned m;
1073
1074                 if (sscanf(mode, "%o", &m) != 1) {
1075                         log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
1076                         r = -ENOENT;
1077                         goto finish;
1078                 }
1079
1080                 i->mode = m;
1081                 i->mode_set = true;
1082         } else
1083                 i->mode =
1084                         i->type == CREATE_DIRECTORY ||
1085                         i->type == TRUNCATE_DIRECTORY ? 0755 : 0644;
1086
1087         if (age && !streq(age, "-")) {
1088                 if (parse_usec(age, &i->age) < 0) {
1089                         log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
1090                         r = -EBADMSG;
1091                         goto finish;
1092                 }
1093
1094                 i->age_set = true;
1095         }
1096
1097         h = needs_glob(i->type) ? globs : items;
1098
1099         existing = hashmap_get(h, i->path);
1100         if (existing) {
1101
1102                 /* Two identical items are fine */
1103                 if (!item_equal(existing, i))
1104                         log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
1105
1106                 r = 0;
1107                 goto finish;
1108         }
1109
1110         r = hashmap_put(h, i->path, i);
1111         if (r < 0) {
1112                 log_error("Failed to insert item %s: %s", i->path, strerror(-r));
1113                 goto finish;
1114         }
1115
1116         i = NULL;
1117         r = 0;
1118
1119 finish:
1120         free(user);
1121         free(group);
1122         free(mode);
1123         free(age);
1124
1125         if (i)
1126                 item_free(i);
1127
1128         return r;
1129 }
1130
1131 static int help(void) {
1132
1133         printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
1134                "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
1135                "  -h --help             Show this help\n"
1136                "     --create           Create marked files/directories\n"
1137                "     --clean            Clean up marked directories\n"
1138                "     --remove           Remove marked files/directories\n"
1139                "     --prefix=PATH      Only apply rules that apply to paths with the specified prefix\n",
1140                program_invocation_short_name);
1141
1142         return 0;
1143 }
1144
1145 static int parse_argv(int argc, char *argv[]) {
1146
1147         enum {
1148                 ARG_CREATE,
1149                 ARG_CLEAN,
1150                 ARG_REMOVE,
1151                 ARG_PREFIX
1152         };
1153
1154         static const struct option options[] = {
1155                 { "help",      no_argument,       NULL, 'h'           },
1156                 { "create",    no_argument,       NULL, ARG_CREATE    },
1157                 { "clean",     no_argument,       NULL, ARG_CLEAN     },
1158                 { "remove",    no_argument,       NULL, ARG_REMOVE    },
1159                 { "prefix",    required_argument, NULL, ARG_PREFIX    },
1160                 { NULL,        0,                 NULL, 0             }
1161         };
1162
1163         int c;
1164
1165         assert(argc >= 0);
1166         assert(argv);
1167
1168         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
1169
1170                 switch (c) {
1171
1172                 case 'h':
1173                         help();
1174                         return 0;
1175
1176                 case ARG_CREATE:
1177                         arg_create = true;
1178                         break;
1179
1180                 case ARG_CLEAN:
1181                         arg_clean = true;
1182                         break;
1183
1184                 case ARG_REMOVE:
1185                         arg_remove = true;
1186                         break;
1187
1188                 case ARG_PREFIX:
1189                         arg_prefix = optarg;
1190                         break;
1191
1192                 case '?':
1193                         return -EINVAL;
1194
1195                 default:
1196                         log_error("Unknown option code %c", c);
1197                         return -EINVAL;
1198                 }
1199         }
1200
1201         if (!arg_clean && !arg_create && !arg_remove) {
1202                 log_error("You need to specify at least one of --clean, --create or --remove.");
1203                 return -EINVAL;
1204         }
1205
1206         return 1;
1207 }
1208
1209 static int read_config_file(const char *fn, bool ignore_enoent) {
1210         FILE *f;
1211         unsigned v = 0;
1212         int r = 0;
1213
1214         assert(fn);
1215
1216         f = fopen(fn, "re");
1217         if (!f) {
1218
1219                 if (ignore_enoent && errno == ENOENT)
1220                         return 0;
1221
1222                 log_error("Failed to open %s: %m", fn);
1223                 return -errno;
1224         }
1225
1226         log_debug("apply: %s\n", fn);
1227         for (;;) {
1228                 char line[LINE_MAX], *l;
1229                 int k;
1230
1231                 if (!(fgets(line, sizeof(line), f)))
1232                         break;
1233
1234                 v++;
1235
1236                 l = strstrip(line);
1237                 if (*l == '#' || *l == 0)
1238                         continue;
1239
1240                 if ((k = parse_line(fn, v, l)) < 0)
1241                         if (r == 0)
1242                                 r = k;
1243         }
1244
1245         if (ferror(f)) {
1246                 log_error("Failed to read from file %s: %m", fn);
1247                 if (r == 0)
1248                         r = -EIO;
1249         }
1250
1251         fclose(f);
1252
1253         return r;
1254 }
1255
1256 int main(int argc, char *argv[]) {
1257         int r;
1258         Item *i;
1259         Iterator iterator;
1260
1261         r = parse_argv(argc, argv);
1262         if (r <= 0)
1263                 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1264
1265         log_set_target(LOG_TARGET_AUTO);
1266         log_parse_environment();
1267         log_open();
1268
1269         umask(0022);
1270
1271         label_init(NULL);
1272
1273         items = hashmap_new(string_hash_func, string_compare_func);
1274         globs = hashmap_new(string_hash_func, string_compare_func);
1275
1276         if (!items || !globs) {
1277                 log_error("Out of memory");
1278                 r = EXIT_FAILURE;
1279                 goto finish;
1280         }
1281
1282         r = EXIT_SUCCESS;
1283
1284         if (optind < argc) {
1285                 int j;
1286
1287                 for (j = optind; j < argc; j++)
1288                         if (read_config_file(argv[j], false) < 0)
1289                                 r = EXIT_FAILURE;
1290
1291         } else {
1292                 char **files, **f;
1293
1294                 r = conf_files_list(&files, ".conf",
1295                                     "/etc/tmpfiles.d",
1296                                     "/run/tmpfiles.d",
1297                                     "/usr/local/lib/tmpfiles.d",
1298                                     "/usr/lib/tmpfiles.d",
1299                                     NULL);
1300                 if (r < 0) {
1301                         log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
1302                         r = EXIT_FAILURE;
1303                         goto finish;
1304                 }
1305
1306                 STRV_FOREACH(f, files) {
1307                         if (read_config_file(*f, true) < 0)
1308                                 r = EXIT_FAILURE;
1309                 }
1310
1311                 strv_free(files);
1312         }
1313
1314         HASHMAP_FOREACH(i, globs, iterator)
1315                 process_item(i);
1316
1317         HASHMAP_FOREACH(i, items, iterator)
1318                 process_item(i);
1319
1320 finish:
1321         while ((i = hashmap_steal_first(items)))
1322                 item_free(i);
1323
1324         while ((i = hashmap_steal_first(globs)))
1325                 item_free(i);
1326
1327         hashmap_free(items);
1328         hashmap_free(globs);
1329
1330         set_free_free(unix_sockets);
1331
1332         label_finish();
1333
1334         return r;
1335 }