]>
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/>.
32 #include "alloc-util.h"
33 #include "dirent-util.h"
41 #include "parse-util.h"
42 #include "path-util.h"
43 #include "string-util.h"
45 #include "time-util.h"
46 #include "user-util.h"
49 int unlink_noerrno ( const char * path
) {
60 int rmdir_parents ( const char * path
, const char * stop
) {
69 /* Skip trailing slashes */
70 while ( l
> 0 && path
[ l
- 1 ] == '/' )
76 /* Skip last component */
77 while ( l
> 0 && path
[ l
- 1 ] != '/' )
80 /* Skip trailing slashes */
81 while ( l
> 0 && path
[ l
- 1 ] == '/' )
91 if ( path_startswith ( stop
, t
)) {
108 int rename_noreplace ( int olddirfd
, const char * oldpath
, int newdirfd
, const char * newpath
) {
112 ret
= renameat2 ( olddirfd
, oldpath
, newdirfd
, newpath
, RENAME_NOREPLACE
);
116 /* renameat2() exists since Linux 3.15, btrfs added support for it later.
117 * If it is not implemented, fallback to another method. */
118 if (! IN_SET ( errno
, EINVAL
, ENOSYS
))
121 /* The link()/unlink() fallback does not work on directories. But
122 * renameat() without RENAME_NOREPLACE gives the same semantics on
123 * directories, except when newpath is an *empty* directory. This is
125 ret
= fstatat ( olddirfd
, oldpath
, & buf
, AT_SYMLINK_NOFOLLOW
);
126 if ( ret
>= 0 && S_ISDIR ( buf
. st_mode
)) {
127 ret
= renameat ( olddirfd
, oldpath
, newdirfd
, newpath
);
128 return ret
>= 0 ? 0 : - errno
;
131 /* If it is not a directory, use the link()/unlink() fallback. */
132 ret
= linkat ( olddirfd
, oldpath
, newdirfd
, newpath
, 0 );
136 ret
= unlinkat ( olddirfd
, oldpath
, 0 );
138 /* backup errno before the following unlinkat() alters it */
140 ( void ) unlinkat ( newdirfd
, newpath
, 0 );
148 int readlinkat_malloc ( int fd
, const char * p
, char ** ret
) {
163 n
= readlinkat ( fd
, p
, c
, l
- 1 );
170 if (( size_t ) n
< l
- 1 ) {
181 int readlink_malloc ( const char * p
, char ** ret
) {
182 return readlinkat_malloc ( AT_FDCWD
, p
, ret
);
185 int readlink_value ( const char * p
, char ** ret
) {
186 _cleanup_free_
char * link
= NULL
;
190 r
= readlink_malloc ( p
, & link
);
194 value
= basename ( link
);
198 value
= strdup ( value
);
207 int readlink_and_make_absolute ( const char * p
, char ** r
) {
208 _cleanup_free_
char * target
= NULL
;
215 j
= readlink_malloc ( p
, & target
);
219 k
= file_in_same_dir ( p
, target
);
227 int readlink_and_canonicalize ( const char * p
, char ** r
) {
234 j
= readlink_and_make_absolute ( p
, & t
);
238 s
= canonicalize_file_name ( t
);
245 path_kill_slashes (* r
);
250 int readlink_and_make_absolute_root ( const char * root
, const char * path
, char ** ret
) {
251 _cleanup_free_
char * target
= NULL
, * t
= NULL
;
255 full
= prefix_roota ( root
, path
);
256 r
= readlink_malloc ( full
, & target
);
260 t
= file_in_same_dir ( path
, target
);
270 int chmod_and_chown ( const char * path
, mode_t mode
, uid_t uid
, gid_t gid
) {
273 /* Under the assumption that we are running privileged we
274 * first change the access mode and only then hand out
275 * ownership to avoid a window where access is too open. */
277 if ( mode
!= MODE_INVALID
)
278 if ( chmod ( path
, mode
) < 0 )
281 if ( uid
!= UID_INVALID
|| gid
!= GID_INVALID
)
282 if ( chown ( path
, uid
, gid
) < 0 )
288 int fchmod_and_fchown ( int fd
, mode_t mode
, uid_t uid
, gid_t gid
) {
291 /* Under the assumption that we are running privileged we
292 * first change the access mode and only then hand out
293 * ownership to avoid a window where access is too open. */
295 if ( mode
!= MODE_INVALID
)
296 if ( fchmod ( fd
, mode
) < 0 )
299 if ( uid
!= UID_INVALID
|| gid
!= GID_INVALID
)
300 if ( fchown ( fd
, uid
, gid
) < 0 )
306 int fchmod_umask ( int fd
, mode_t m
) {
311 r
= fchmod ( fd
, m
& (~ u
)) < 0 ? - errno
: 0 ;
317 int fd_warn_permissions ( const char * path
, int fd
) {
320 if ( fstat ( fd
, & st
) < 0 )
323 if ( st
. st_mode
& 0111 )
324 log_warning ( "Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway." , path
);
326 if ( st
. st_mode
& 0002 )
327 log_warning ( "Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway." , path
);
329 if ( getpid () == 1 && ( st
. st_mode
& 0044 ) != 0044 )
330 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
);
335 int touch_file ( const char * path
, bool parents
, usec_t stamp
, uid_t uid
, gid_t gid
, mode_t mode
) {
336 _cleanup_close_
int fd
;
342 mkdir_parents ( path
, 0755 );
344 fd
= open ( path
, O_WRONLY
| O_CREAT
| O_CLOEXEC
| O_NOCTTY
,
345 ( mode
== 0 || mode
== MODE_INVALID
) ? 0644 : mode
);
349 if ( mode
!= MODE_INVALID
) {
350 r
= fchmod ( fd
, mode
);
355 if ( uid
!= UID_INVALID
|| gid
!= GID_INVALID
) {
356 r
= fchown ( fd
, uid
, gid
);
361 if ( stamp
!= USEC_INFINITY
) {
362 struct timespec ts
[ 2 ];
364 timespec_store (& ts
[ 0 ], stamp
);
366 r
= futimens ( fd
, ts
);
368 r
= futimens ( fd
, NULL
);
375 int touch ( const char * path
) {
376 return touch_file ( path
, false , USEC_INFINITY
, UID_INVALID
, GID_INVALID
, MODE_INVALID
);
379 int symlink_idempotent ( const char * from
, const char * to
) {
380 _cleanup_free_
char * p
= NULL
;
386 if ( symlink ( from
, to
) < 0 ) {
390 r
= readlink_malloc ( to
, & p
);
401 int symlink_atomic ( const char * from
, const char * to
) {
402 _cleanup_free_
char * t
= NULL
;
408 r
= tempfn_random ( to
, NULL
, & t
);
412 if ( symlink ( from
, t
) < 0 )
415 if ( rename ( t
, to
) < 0 ) {
423 int mknod_atomic ( const char * path
, mode_t mode
, dev_t dev
) {
424 _cleanup_free_
char * t
= NULL
;
429 r
= tempfn_random ( path
, NULL
, & t
);
433 if ( mknod ( t
, mode
, dev
) < 0 )
436 if ( rename ( t
, path
) < 0 ) {
444 int mkfifo_atomic ( const char * path
, mode_t mode
) {
445 _cleanup_free_
char * t
= NULL
;
450 r
= tempfn_random ( path
, NULL
, & t
);
454 if ( mkfifo ( t
, mode
) < 0 )
457 if ( rename ( t
, path
) < 0 ) {
465 int get_files_in_directory ( const char * path
, char *** list
) {
466 _cleanup_closedir_
DIR * d
= NULL
;
467 size_t bufsize
= 0 , n
= 0 ;
468 _cleanup_strv_free_
char ** l
= NULL
;
472 /* Returns all files in a directory in *list, and the number
473 * of files as return value. If list is NULL returns only the
485 if (! de
&& errno
> 0 )
490 dirent_ensure_type ( d
, de
);
492 if (! dirent_is_file ( de
))
496 /* one extra slot is needed for the terminating NULL */
497 if (! GREEDY_REALLOC ( l
, bufsize
, n
+ 2 ))
500 l
[ n
] = strdup ( de
-> d_name
);
511 l
= NULL
; /* avoid freeing */