]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/fs-util.c
2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
30 #include "alloc-util.h"
31 #include "dirent-util.h"
39 #include "parse-util.h"
40 #include "path-util.h"
41 #include "stat-util.h"
42 #include "stdio-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_umask ( int fd
, mode_t m
) {
293 r
= fchmod ( fd
, m
& (~ u
)) < 0 ? - errno
: 0 ;
299 int fd_warn_permissions ( const char * path
, int fd
) {
302 if ( fstat ( fd
, & st
) < 0 )
305 if ( st
. st_mode
& 0111 )
306 log_warning ( "Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway." , path
);
308 if ( st
. st_mode
& 0002 )
309 log_warning ( "Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway." , path
);
311 if ( getpid () == 1 && ( st
. st_mode
& 0044 ) != 0044 )
312 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
);
317 int touch_file ( const char * path
, bool parents
, usec_t stamp
, uid_t uid
, gid_t gid
, mode_t mode
) {
318 _cleanup_close_
int fd
;
324 mkdir_parents ( path
, 0755 );
326 fd
= open ( path
, O_WRONLY
| O_CREAT
| O_CLOEXEC
| O_NOCTTY
,
327 ( mode
== 0 || mode
== MODE_INVALID
) ? 0644 : mode
);
331 if ( mode
!= MODE_INVALID
) {
332 r
= fchmod ( fd
, mode
);
337 if ( uid
!= UID_INVALID
|| gid
!= GID_INVALID
) {
338 r
= fchown ( fd
, uid
, gid
);
343 if ( stamp
!= USEC_INFINITY
) {
344 struct timespec ts
[ 2 ];
346 timespec_store (& ts
[ 0 ], stamp
);
348 r
= futimens ( fd
, ts
);
350 r
= futimens ( fd
, NULL
);
357 int touch ( const char * path
) {
358 return touch_file ( path
, false , USEC_INFINITY
, UID_INVALID
, GID_INVALID
, MODE_INVALID
);
361 int symlink_idempotent ( const char * from
, const char * to
) {
362 _cleanup_free_
char * p
= NULL
;
368 if ( symlink ( from
, to
) < 0 ) {
372 r
= readlink_malloc ( to
, & p
);
383 int symlink_atomic ( const char * from
, const char * to
) {
384 _cleanup_free_
char * t
= NULL
;
390 r
= tempfn_random ( to
, NULL
, & t
);
394 if ( symlink ( from
, t
) < 0 )
397 if ( rename ( t
, to
) < 0 ) {
405 int mknod_atomic ( const char * path
, mode_t mode
, dev_t dev
) {
406 _cleanup_free_
char * t
= NULL
;
411 r
= tempfn_random ( path
, NULL
, & t
);
415 if ( mknod ( t
, mode
, dev
) < 0 )
418 if ( rename ( t
, path
) < 0 ) {
426 int mkfifo_atomic ( const char * path
, mode_t mode
) {
427 _cleanup_free_
char * t
= NULL
;
432 r
= tempfn_random ( path
, NULL
, & t
);
436 if ( mkfifo ( t
, mode
) < 0 )
439 if ( rename ( t
, path
) < 0 ) {
447 int get_files_in_directory ( const char * path
, char *** list
) {
448 _cleanup_closedir_
DIR * d
= NULL
;
449 size_t bufsize
= 0 , n
= 0 ;
450 _cleanup_strv_free_
char ** l
= NULL
;
454 /* Returns all files in a directory in *list, and the number
455 * of files as return value. If list is NULL returns only the
467 if (! de
&& errno
> 0 )
472 dirent_ensure_type ( d
, de
);
474 if (! dirent_is_file ( de
))
478 /* one extra slot is needed for the terminating NULL */
479 if (! GREEDY_REALLOC ( l
, bufsize
, n
+ 2 ))
482 l
[ n
] = strdup ( de
-> d_name
);
493 l
= NULL
; /* avoid freeing */
499 int var_tmp ( char ** ret
) {
500 const char * tmp_dir
= NULL
;
501 const char * env_tmp_dir
= NULL
;
507 env_tmp_dir
= getenv ( "TMPDIR" );
508 if ( env_tmp_dir
!= NULL
) {
509 r
= is_dir ( env_tmp_dir
, true );
510 if ( r
< 0 && r
!= - ENOENT
)
513 tmp_dir
= env_tmp_dir
;
517 tmp_dir
= "/var/tmp" ;
527 int inotify_add_watch_fd ( int fd
, int what
, uint32_t mask
) {
528 char path
[ strlen ( "/proc/self/fd/" ) + DECIMAL_STR_MAX ( int ) + 1 ];
531 /* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */
532 xsprintf ( path
, "/proc/self/fd/%i" , what
);
534 r
= inotify_add_watch ( fd
, path
, mask
);