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