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