]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/fs-util.c
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 "dirent-util.h"
27 #include "path-util.h"
28 #include "string-util.h"
32 int unlink_noerrno ( const char * path
) {
43 int rmdir_parents ( const char * path
, const char * stop
) {
52 /* Skip trailing slashes */
53 while ( l
> 0 && path
[ l
- 1 ] == '/' )
59 /* Skip last component */
60 while ( l
> 0 && path
[ l
- 1 ] != '/' )
63 /* Skip trailing slashes */
64 while ( l
> 0 && path
[ l
- 1 ] == '/' )
74 if ( path_startswith ( stop
, t
)) {
91 int rename_noreplace ( int olddirfd
, const char * oldpath
, int newdirfd
, const char * newpath
) {
95 ret
= renameat2 ( olddirfd
, oldpath
, newdirfd
, newpath
, RENAME_NOREPLACE
);
99 /* renameat2() exists since Linux 3.15, btrfs added support for it later.
100 * If it is not implemented, fallback to another method. */
101 if (! IN_SET ( errno
, EINVAL
, ENOSYS
))
104 /* The link()/unlink() fallback does not work on directories. But
105 * renameat() without RENAME_NOREPLACE gives the same semantics on
106 * directories, except when newpath is an *empty* directory. This is
108 ret
= fstatat ( olddirfd
, oldpath
, & buf
, AT_SYMLINK_NOFOLLOW
);
109 if ( ret
>= 0 && S_ISDIR ( buf
. st_mode
)) {
110 ret
= renameat ( olddirfd
, oldpath
, newdirfd
, newpath
);
111 return ret
>= 0 ? 0 : - errno
;
114 /* If it is not a directory, use the link()/unlink() fallback. */
115 ret
= linkat ( olddirfd
, oldpath
, newdirfd
, newpath
, 0 );
119 ret
= unlinkat ( olddirfd
, oldpath
, 0 );
121 /* backup errno before the following unlinkat() alters it */
123 ( void ) unlinkat ( newdirfd
, newpath
, 0 );
131 int readlinkat_malloc ( int fd
, const char * p
, char ** ret
) {
146 n
= readlinkat ( fd
, p
, c
, l
- 1 );
153 if (( size_t ) n
< l
- 1 ) {
164 int readlink_malloc ( const char * p
, char ** ret
) {
165 return readlinkat_malloc ( AT_FDCWD
, p
, ret
);
168 int readlink_value ( const char * p
, char ** ret
) {
169 _cleanup_free_
char * link
= NULL
;
173 r
= readlink_malloc ( p
, & link
);
177 value
= basename ( link
);
181 value
= strdup ( value
);
190 int readlink_and_make_absolute ( const char * p
, char ** r
) {
191 _cleanup_free_
char * target
= NULL
;
198 j
= readlink_malloc ( p
, & target
);
202 k
= file_in_same_dir ( p
, target
);
210 int readlink_and_canonicalize ( const char * p
, char ** r
) {
217 j
= readlink_and_make_absolute ( p
, & t
);
221 s
= canonicalize_file_name ( t
);
228 path_kill_slashes (* r
);
233 int chmod_and_chown ( const char * path
, mode_t mode
, uid_t uid
, gid_t gid
) {
236 /* Under the assumption that we are running privileged we
237 * first change the access mode and only then hand out
238 * ownership to avoid a window where access is too open. */
240 if ( mode
!= MODE_INVALID
)
241 if ( chmod ( path
, mode
) < 0 )
244 if ( uid
!= UID_INVALID
|| gid
!= GID_INVALID
)
245 if ( chown ( path
, uid
, gid
) < 0 )
251 int fchmod_and_fchown ( int fd
, mode_t mode
, uid_t uid
, gid_t gid
) {
254 /* Under the assumption that we are running privileged we
255 * first change the access mode and only then hand out
256 * ownership to avoid a window where access is too open. */
258 if ( mode
!= MODE_INVALID
)
259 if ( fchmod ( fd
, mode
) < 0 )
262 if ( uid
!= UID_INVALID
|| gid
!= GID_INVALID
)
263 if ( fchown ( fd
, uid
, gid
) < 0 )
269 int fchmod_umask ( int fd
, mode_t m
) {
274 r
= fchmod ( fd
, m
& (~ u
)) < 0 ? - errno
: 0 ;
280 int fd_warn_permissions ( const char * path
, int fd
) {
283 if ( fstat ( fd
, & st
) < 0 )
286 if ( st
. st_mode
& 0111 )
287 log_warning ( "Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway." , path
);
289 if ( st
. st_mode
& 0002 )
290 log_warning ( "Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway." , path
);
292 if ( getpid () == 1 && ( st
. st_mode
& 0044 ) != 0044 )
293 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
);
298 int touch_file ( const char * path
, bool parents
, usec_t stamp
, uid_t uid
, gid_t gid
, mode_t mode
) {
299 _cleanup_close_
int fd
;
305 mkdir_parents ( path
, 0755 );
307 fd
= open ( path
, O_WRONLY
| O_CREAT
| O_CLOEXEC
| O_NOCTTY
, mode
> 0 ? mode
: 0644 );
312 r
= fchmod ( fd
, mode
);
317 if ( uid
!= UID_INVALID
|| gid
!= GID_INVALID
) {
318 r
= fchown ( fd
, uid
, gid
);
323 if ( stamp
!= USEC_INFINITY
) {
324 struct timespec ts
[ 2 ];
326 timespec_store (& ts
[ 0 ], stamp
);
328 r
= futimens ( fd
, ts
);
330 r
= futimens ( fd
, NULL
);
337 int touch ( const char * path
) {
338 return touch_file ( path
, false , USEC_INFINITY
, UID_INVALID
, GID_INVALID
, 0 );
341 int symlink_idempotent ( const char * from
, const char * to
) {
342 _cleanup_free_
char * p
= NULL
;
348 if ( symlink ( from
, to
) < 0 ) {
352 r
= readlink_malloc ( to
, & p
);
363 int symlink_atomic ( const char * from
, const char * to
) {
364 _cleanup_free_
char * t
= NULL
;
370 r
= tempfn_random ( to
, NULL
, & t
);
374 if ( symlink ( from
, t
) < 0 )
377 if ( rename ( t
, to
) < 0 ) {
385 int mknod_atomic ( const char * path
, mode_t mode
, dev_t dev
) {
386 _cleanup_free_
char * t
= NULL
;
391 r
= tempfn_random ( path
, NULL
, & t
);
395 if ( mknod ( t
, mode
, dev
) < 0 )
398 if ( rename ( t
, path
) < 0 ) {
406 int mkfifo_atomic ( const char * path
, mode_t mode
) {
407 _cleanup_free_
char * t
= NULL
;
412 r
= tempfn_random ( path
, NULL
, & t
);
416 if ( mkfifo ( t
, mode
) < 0 )
419 if ( rename ( t
, path
) < 0 ) {
427 int get_files_in_directory ( const char * path
, char *** list
) {
428 _cleanup_closedir_
DIR * d
= NULL
;
429 size_t bufsize
= 0 , n
= 0 ;
430 _cleanup_strv_free_
char ** l
= NULL
;
434 /* Returns all files in a directory in *list, and the number
435 * of files as return value. If list is NULL returns only the
447 if (! de
&& errno
!= 0 )
452 dirent_ensure_type ( d
, de
);
454 if (! dirent_is_file ( de
))
458 /* one extra slot is needed for the terminating NULL */
459 if (! GREEDY_REALLOC ( l
, bufsize
, n
+ 2 ))
462 l
[ n
] = strdup ( de
-> d_name
);
473 l
= NULL
; /* avoid freeing */