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 /// UNNEEDED by elogind
48 int rmdir_parents(const char *path, const char *stop) {
57 /* Skip trailing slashes */
58 while (l > 0 && path[l-1] == '/')
64 /* Skip last component */
65 while (l > 0 && path[l-1] != '/')
68 /* Skip trailing slashes */
69 while (l > 0 && path[l-1] == '/')
79 if (path_startswith(stop, t)) {
96 int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
100 ret = renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE);
104 /* renameat2() exists since Linux 3.15, btrfs added support for it later.
105 * If it is not implemented, fallback to another method. */
106 if (!IN_SET(errno, EINVAL, ENOSYS))
109 /* The link()/unlink() fallback does not work on directories. But
110 * renameat() without RENAME_NOREPLACE gives the same semantics on
111 * directories, except when newpath is an *empty* directory. This is
113 ret = fstatat(olddirfd, oldpath, &buf, AT_SYMLINK_NOFOLLOW);
114 if (ret >= 0 && S_ISDIR(buf.st_mode)) {
115 ret = renameat(olddirfd, oldpath, newdirfd, newpath);
116 return ret >= 0 ? 0 : -errno;
119 /* If it is not a directory, use the link()/unlink() fallback. */
120 ret = linkat(olddirfd, oldpath, newdirfd, newpath, 0);
124 ret = unlinkat(olddirfd, oldpath, 0);
126 /* backup errno before the following unlinkat() alters it */
128 (void) unlinkat(newdirfd, newpath, 0);
137 int readlinkat_malloc(int fd, const char *p, char **ret) {
152 n = readlinkat(fd, p, c, l-1);
159 if ((size_t) n < l-1) {
170 int readlink_malloc(const char *p, char **ret) {
171 return readlinkat_malloc(AT_FDCWD, p, ret);
174 /// UNNEEDED by elogind
176 int readlink_value(const char *p, char **ret) {
177 _cleanup_free_ char *link = NULL;
181 r = readlink_malloc(p, &link);
185 value = basename(link);
189 value = strdup(value);
198 int readlink_and_make_absolute(const char *p, char **r) {
199 _cleanup_free_ char *target = NULL;
206 j = readlink_malloc(p, &target);
210 k = file_in_same_dir(p, target);
218 int readlink_and_canonicalize(const char *p, char **r) {
225 j = readlink_and_make_absolute(p, &t);
229 s = canonicalize_file_name(t);
236 path_kill_slashes(*r);
241 int readlink_and_make_absolute_root(const char *root, const char *path, char **ret) {
242 _cleanup_free_ char *target = NULL, *t = NULL;
246 full = prefix_roota(root, path);
247 r = readlink_malloc(full, &target);
251 t = file_in_same_dir(path, target);
262 int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
265 /* Under the assumption that we are running privileged we
266 * first change the access mode and only then hand out
267 * ownership to avoid a window where access is too open. */
269 if (mode != MODE_INVALID)
270 if (chmod(path, mode) < 0)
273 if (uid != UID_INVALID || gid != GID_INVALID)
274 if (chown(path, uid, gid) < 0)
280 /// UNNEEDED by elogind
282 int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) {
285 /* Under the assumption that we are running privileged we
286 * first change the access mode and only then hand out
287 * ownership to avoid a window where access is too open. */
289 if (mode != MODE_INVALID)
290 if (fchmod(fd, mode) < 0)
293 if (uid != UID_INVALID || gid != GID_INVALID)
294 if (fchown(fd, uid, gid) < 0)
301 int fchmod_umask(int fd, mode_t m) {
306 r = fchmod(fd, m & (~u)) < 0 ? -errno : 0;
312 int fd_warn_permissions(const char *path, int fd) {
315 if (fstat(fd, &st) < 0)
318 if (st.st_mode & 0111)
319 log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path);
321 if (st.st_mode & 0002)
322 log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path);
324 if (getpid() == 1 && (st.st_mode & 0044) != 0044)
325 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);
330 int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
331 _cleanup_close_ int fd;
337 mkdir_parents(path, 0755);
339 fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode > 0 ? mode : 0644);
343 if (mode != MODE_INVALID) {
344 r = fchmod(fd, mode);
349 if (uid != UID_INVALID || gid != GID_INVALID) {
350 r = fchown(fd, uid, gid);
355 if (stamp != USEC_INFINITY) {
356 struct timespec ts[2];
358 timespec_store(&ts[0], stamp);
360 r = futimens(fd, ts);
362 r = futimens(fd, NULL);
369 int touch(const char *path) {
370 return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
373 /// UNNEEDED by elogind
375 int symlink_idempotent(const char *from, const char *to) {
376 _cleanup_free_ char *p = NULL;
382 if (symlink(from, to) < 0) {
386 r = readlink_malloc(to, &p);
397 int symlink_atomic(const char *from, const char *to) {
398 _cleanup_free_ char *t = NULL;
404 r = tempfn_random(to, NULL, &t);
408 if (symlink(from, t) < 0)
411 if (rename(t, to) < 0) {
419 int mknod_atomic(const char *path, mode_t mode, dev_t dev) {
420 _cleanup_free_ char *t = NULL;
425 r = tempfn_random(path, NULL, &t);
429 if (mknod(t, mode, dev) < 0)
432 if (rename(t, path) < 0) {
440 int mkfifo_atomic(const char *path, mode_t mode) {
441 _cleanup_free_ char *t = NULL;
446 r = tempfn_random(path, NULL, &t);
450 if (mkfifo(t, mode) < 0)
453 if (rename(t, path) < 0) {
462 int get_files_in_directory(const char *path, char ***list) {
463 _cleanup_closedir_ DIR *d = NULL;
464 size_t bufsize = 0, n = 0;
465 _cleanup_strv_free_ char **l = NULL;
469 /* Returns all files in a directory in *list, and the number
470 * of files as return value. If list is NULL returns only the
482 if (!de && errno != 0)
487 dirent_ensure_type(d, de);
489 if (!dirent_is_file(de))
493 /* one extra slot is needed for the terminating NULL */
494 if (!GREEDY_REALLOC(l, bufsize, n + 2))
497 l[n] = strdup(de->d_name);
508 l = NULL; /* avoid freeing */