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