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 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.
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.
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/>.
22 #include "alloc-util.h"
23 #include "dirent-util.h"
28 #include "parse-util.h"
29 #include "path-util.h"
30 #include "string-util.h"
32 #include "user-util.h"
35 int unlink_noerrno(const char *path) {
46 #if 0 /// UNNEEDED by elogind
47 int rmdir_parents(const char *path, const char *stop) {
56 /* Skip trailing slashes */
57 while (l > 0 && path[l-1] == '/')
63 /* Skip last component */
64 while (l > 0 && path[l-1] != '/')
67 /* Skip trailing slashes */
68 while (l > 0 && path[l-1] == '/')
78 if (path_startswith(stop, t)) {
95 int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
99 ret = renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE);
103 /* renameat2() exists since Linux 3.15, btrfs added support for it later.
104 * If it is not implemented, fallback to another method. */
105 if (!IN_SET(errno, EINVAL, ENOSYS))
108 /* The link()/unlink() fallback does not work on directories. But
109 * renameat() without RENAME_NOREPLACE gives the same semantics on
110 * directories, except when newpath is an *empty* directory. This is
112 ret = fstatat(olddirfd, oldpath, &buf, AT_SYMLINK_NOFOLLOW);
113 if (ret >= 0 && S_ISDIR(buf.st_mode)) {
114 ret = renameat(olddirfd, oldpath, newdirfd, newpath);
115 return ret >= 0 ? 0 : -errno;
118 /* If it is not a directory, use the link()/unlink() fallback. */
119 ret = linkat(olddirfd, oldpath, newdirfd, newpath, 0);
123 ret = unlinkat(olddirfd, oldpath, 0);
125 /* backup errno before the following unlinkat() alters it */
127 (void) unlinkat(newdirfd, newpath, 0);
136 int readlinkat_malloc(int fd, const char *p, char **ret) {
151 n = readlinkat(fd, p, c, l-1);
158 if ((size_t) n < l-1) {
169 int readlink_malloc(const char *p, char **ret) {
170 return readlinkat_malloc(AT_FDCWD, p, ret);
173 #if 0 /// UNNEEDED by elogind
174 int readlink_value(const char *p, char **ret) {
175 _cleanup_free_ char *link = NULL;
179 r = readlink_malloc(p, &link);
183 value = basename(link);
187 value = strdup(value);
196 int readlink_and_make_absolute(const char *p, char **r) {
197 _cleanup_free_ char *target = NULL;
204 j = readlink_malloc(p, &target);
208 k = file_in_same_dir(p, target);
216 int readlink_and_canonicalize(const char *p, char **r) {
223 j = readlink_and_make_absolute(p, &t);
227 s = canonicalize_file_name(t);
234 path_kill_slashes(*r);
239 int readlink_and_make_absolute_root(const char *root, const char *path, char **ret) {
240 _cleanup_free_ char *target = NULL, *t = NULL;
244 full = prefix_roota(root, path);
245 r = readlink_malloc(full, &target);
249 t = file_in_same_dir(path, target);
260 int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
263 /* Under the assumption that we are running privileged we
264 * first change the access mode and only then hand out
265 * ownership to avoid a window where access is too open. */
267 if (mode != MODE_INVALID)
268 if (chmod(path, mode) < 0)
271 if (uid != UID_INVALID || gid != GID_INVALID)
272 if (chown(path, uid, gid) < 0)
278 #if 0 /// UNNEEDED by elogind
279 int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) {
282 /* Under the assumption that we are running privileged we
283 * first change the access mode and only then hand out
284 * ownership to avoid a window where access is too open. */
286 if (mode != MODE_INVALID)
287 if (fchmod(fd, mode) < 0)
290 if (uid != UID_INVALID || gid != GID_INVALID)
291 if (fchown(fd, uid, gid) < 0)
298 int fchmod_umask(int fd, mode_t m) {
303 r = fchmod(fd, m & (~u)) < 0 ? -errno : 0;
309 int fd_warn_permissions(const char *path, int fd) {
312 if (fstat(fd, &st) < 0)
315 if (st.st_mode & 0111)
316 log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path);
318 if (st.st_mode & 0002)
319 log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path);
321 if (getpid() == 1 && (st.st_mode & 0044) != 0044)
322 log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path);
327 int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
328 _cleanup_close_ int fd;
334 mkdir_parents(path, 0755);
336 fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode > 0 ? mode : 0644);
340 if (mode != MODE_INVALID) {
341 r = fchmod(fd, mode);
346 if (uid != UID_INVALID || gid != GID_INVALID) {
347 r = fchown(fd, uid, gid);
352 if (stamp != USEC_INFINITY) {
353 struct timespec ts[2];
355 timespec_store(&ts[0], stamp);
357 r = futimens(fd, ts);
359 r = futimens(fd, NULL);
366 int touch(const char *path) {
367 return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
370 #if 0 /// UNNEEDED by elogind
371 int symlink_idempotent(const char *from, const char *to) {
372 _cleanup_free_ char *p = NULL;
378 if (symlink(from, to) < 0) {
382 r = readlink_malloc(to, &p);
393 int symlink_atomic(const char *from, const char *to) {
394 _cleanup_free_ char *t = NULL;
400 r = tempfn_random(to, NULL, &t);
404 if (symlink(from, t) < 0)
407 if (rename(t, to) < 0) {
415 int mknod_atomic(const char *path, mode_t mode, dev_t dev) {
416 _cleanup_free_ char *t = NULL;
421 r = tempfn_random(path, NULL, &t);
425 if (mknod(t, mode, dev) < 0)
428 if (rename(t, path) < 0) {
436 int mkfifo_atomic(const char *path, mode_t mode) {
437 _cleanup_free_ char *t = NULL;
442 r = tempfn_random(path, NULL, &t);
446 if (mkfifo(t, mode) < 0)
449 if (rename(t, path) < 0) {
458 int get_files_in_directory(const char *path, char ***list) {
459 _cleanup_closedir_ DIR *d = NULL;
460 size_t bufsize = 0, n = 0;
461 _cleanup_strv_free_ char **l = NULL;
465 /* Returns all files in a directory in *list, and the number
466 * of files as return value. If list is NULL returns only the
478 if (!de && errno != 0)
483 dirent_ensure_type(d, de);
485 if (!dirent_is_file(de))
489 /* one extra slot is needed for the terminating NULL */
490 if (!GREEDY_REALLOC(l, bufsize, n + 2))
493 l[n] = strdup(de->d_name);
504 l = NULL; /* avoid freeing */