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