1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
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 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
37 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
38 * them in the file system. This is intended to be used to create
39 * properly owned directories beneath /tmp, /var/tmp, /var/run and
40 * /var/lock which are volatile and hence need to be recreated on
43 static int process_line(const char *fname, unsigned line, const char *buffer, const char *prefix) {
47 char *user = NULL, *group = NULL;
50 bool uid_set = false, gid_set = false;
57 if ((n = sscanf(buffer,
68 log_error("[%s:%u] Syntax error.", fname, line);
73 if (type != 'f' && type != 'd') {
74 log_error("[%s:%u] Unknown file type '%c'.", fname, line, type);
79 if (prefix && !path_startswith(path, prefix)) {
84 if (user && !streq(user, "-")) {
88 if (streq(user, "root") || streq(user, "0"))
90 else if (safe_atolu(user, &lu) >= 0)
92 else if ((p = getpwnam(user)))
95 log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
103 if (group && !streq(group, "-")) {
107 if (streq(group, "root") || streq(group, "0"))
109 else if (safe_atolu(group, &lu) >= 0)
111 else if ((g = getgrnam(group)))
114 log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
123 mode = type == 'f' ? 0644 : 0755;
130 fd = open(path, O_CREAT|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, mode);
134 log_error("Failed to create file %s: %m", path);
139 if (fstat(fd, &st) < 0) {
140 log_error("stat(%s) failed: %m", path);
145 if (!S_ISREG(st.st_mode)) {
146 log_error("%s is not a file.", path);
151 if (fchmod(fd, mode) < 0) {
152 log_error("chmod(%s) failed: %m", path);
157 if (uid_set || gid_set) {
160 uid_set ? uid : (uid_t) -1,
161 gid_set ? gid : (gid_t) -1) < 0) {
162 log_error("chown(%s) failed: %m", path);
168 } else if (type == 'd') {
173 r = mkdir(path, mode);
176 if (r < 0 && errno != EEXIST) {
177 log_error("Failed to create directory %s: %m", path);
182 if (stat(path, &st) < 0) {
183 log_error("stat(%s) failed: %m", path);
188 if (!S_ISDIR(st.st_mode)) {
189 log_error("%s is not a directory.", path);
194 if (chmod(path, mode) < 0) {
195 log_error("chmod(%s) failed: %m", path);
200 if (uid_set || gid_set) {
203 uid_set ? uid : (uid_t) -1,
204 gid_set ? gid : (gid_t) -1) < 0) {
205 log_error("chown(%s) failed: %m", path);
212 if ((r = label_fix(path)) < 0)
215 log_debug("%s created successfully.", path);
224 close_nointr_nofail(fd);
229 static int scandir_filter(const struct dirent *d) {
232 if (ignore_file(d->d_name))
235 if (d->d_type != DT_REG &&
239 return endswith(d->d_name, ".conf");
242 int main(int argc, char *argv[]) {
243 struct dirent **de = NULL;
244 int r = EXIT_FAILURE, n, i;
245 const char *prefix = NULL;
248 log_error("This program takes no more than one argument.");
255 log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
256 log_parse_environment();
261 if ((n = scandir("/etc/tmpfiles.d/", &de, scandir_filter, alphasort)) < 0) {
266 log_error("Failed to enumerate /etc/tmpfiles.d/ files: %m");
273 for (i = 0; i < n; i++) {
279 k = asprintf(&fn, "/etc/tmpfiles.d/%s", de[i]->d_name);
283 log_error("Failed to allocate file name.");
288 if (!(f = fopen(fn, "re"))) {
289 log_error("Failed to open %s: %m", fn);
297 char line[LINE_MAX], *l;
299 if (!(fgets(line, sizeof(line), f)))
305 if (*l == '#' || *l == 0)
308 if (process_line(fn, j, l, prefix) < 0)
314 log_error("Failed to read from file %s: %m", fn);