]>
git.proxmox.com Git - 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 "string-util.h"
43 #include "time-util.h"
44 #include "user-util.h"
47 int unlink_noerrno ( const char * path
) {
58 int rmdir_parents ( const char * path
, const char * stop
) {
67 /* Skip trailing slashes */
68 while ( l
> 0 && path
[ l
- 1 ] == '/' )
74 /* Skip last component */
75 while ( l
> 0 && path
[ l
- 1 ] != '/' )
78 /* Skip trailing slashes */
79 while ( l
> 0 && path
[ l
- 1 ] == '/' )
89 if ( path_startswith ( stop
, t
)) {
106 int rename_noreplace ( int olddirfd
, const char * oldpath
, int newdirfd
, const char * newpath
) {
110 ret
= renameat2 ( olddirfd
, oldpath
, newdirfd
, newpath
, RENAME_NOREPLACE
);
114 /* renameat2() exists since Linux 3.15, btrfs added support for it later.
115 * If it is not implemented, fallback to another method. */
116 if (! IN_SET ( errno
, EINVAL
, ENOSYS
))
119 /* The link()/unlink() fallback does not work on directories. But
120 * renameat() without RENAME_NOREPLACE gives the same semantics on
121 * directories, except when newpath is an *empty* directory. This is
123 ret
= fstatat ( olddirfd
, oldpath
, & buf
, AT_SYMLINK_NOFOLLOW
);
124 if ( ret
>= 0 && S_ISDIR ( buf
. st_mode
)) {
125 ret
= renameat ( olddirfd
, oldpath
, newdirfd
, newpath
);
126 return ret
>= 0 ? 0 : - errno
;
129 /* If it is not a directory, use the link()/unlink() fallback. */
130 ret
= linkat ( olddirfd
, oldpath
, newdirfd
, newpath
, 0 );
134 ret
= unlinkat ( olddirfd
, oldpath
, 0 );
136 /* backup errno before the following unlinkat() alters it */
138 ( void ) unlinkat ( newdirfd
, newpath
, 0 );
146 int readlinkat_malloc ( int fd
, const char * p
, char ** ret
) {
161 n
= readlinkat ( fd
, p
, c
, l
- 1 );
168 if (( size_t ) n
< l
- 1 ) {
179 int readlink_malloc ( const char * p
, char ** ret
) {
180 return readlinkat_malloc ( AT_FDCWD
, p
, ret
);
183 int readlink_value ( const char * p
, char ** ret
) {
184 _cleanup_free_
char * link
= NULL
;
188 r
= readlink_malloc ( p
, & link
);
192 value
= basename ( link
);
196 value
= strdup ( value
);
205 int readlink_and_make_absolute ( const char * p
, char ** r
) {
206 _cleanup_free_
char * target
= NULL
;
213 j
= readlink_malloc ( p
, & target
);
217 k
= file_in_same_dir ( p
, target
);
225 int readlink_and_canonicalize ( const char * p
, char ** r
) {
232 j
= readlink_and_make_absolute ( p
, & t
);
236 s
= canonicalize_file_name ( t
);
243 path_kill_slashes (* r
);
248 int readlink_and_make_absolute_root ( const char * root
, const char * path
, char ** ret
) {
249 _cleanup_free_
char * target
= NULL
, * t
= NULL
;
253 full
= prefix_roota ( root
, path
);
254 r
= readlink_malloc ( full
, & target
);
258 t
= file_in_same_dir ( path
, target
);
268 int chmod_and_chown ( const char * path
, mode_t mode
, uid_t uid
, gid_t gid
) {
271 /* Under the assumption that we are running privileged we
272 * first change the access mode and only then hand out
273 * ownership to avoid a window where access is too open. */
275 if ( mode
!= MODE_INVALID
)
276 if ( chmod ( path
, mode
) < 0 )
279 if ( uid
!= UID_INVALID
|| gid
!= GID_INVALID
)
280 if ( chown ( path
, uid
, gid
) < 0 )
286 int fchmod_and_fchown ( int fd
, mode_t mode
, uid_t uid
, gid_t gid
) {
289 /* Under the assumption that we are running privileged we
290 * first change the access mode and only then hand out
291 * ownership to avoid a window where access is too open. */
293 if ( mode
!= MODE_INVALID
)
294 if ( fchmod ( fd
, mode
) < 0 )
297 if ( uid
!= UID_INVALID
|| gid
!= GID_INVALID
)
298 if ( fchown ( fd
, uid
, gid
) < 0 )
304 int fchmod_umask ( int fd
, mode_t m
) {
309 r
= fchmod ( fd
, m
& (~ u
)) < 0 ? - errno
: 0 ;
315 int fd_warn_permissions ( const char * path
, int fd
) {
318 if ( fstat ( fd
, & st
) < 0 )
321 if ( st
. st_mode
& 0111 )
322 log_warning ( "Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway." , path
);
324 if ( st
. st_mode
& 0002 )
325 log_warning ( "Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway." , path
);
327 if ( getpid () == 1 && ( st
. st_mode
& 0044 ) != 0044 )
328 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
);
333 int touch_file ( const char * path
, bool parents
, usec_t stamp
, uid_t uid
, gid_t gid
, mode_t mode
) {
334 _cleanup_close_
int fd
;
340 mkdir_parents ( path
, 0755 );
342 fd
= open ( path
, O_WRONLY
| O_CREAT
| O_CLOEXEC
| O_NOCTTY
,
343 ( mode
== 0 || mode
== MODE_INVALID
) ? 0644 : mode
);
347 if ( mode
!= MODE_INVALID
) {
348 r
= fchmod ( fd
, mode
);
353 if ( uid
!= UID_INVALID
|| gid
!= GID_INVALID
) {
354 r
= fchown ( fd
, uid
, gid
);
359 if ( stamp
!= USEC_INFINITY
) {
360 struct timespec ts
[ 2 ];
362 timespec_store (& ts
[ 0 ], stamp
);
364 r
= futimens ( fd
, ts
);
366 r
= futimens ( fd
, NULL
);
373 int touch ( const char * path
) {
374 return touch_file ( path
, false , USEC_INFINITY
, UID_INVALID
, GID_INVALID
, MODE_INVALID
);
377 int symlink_idempotent ( const char * from
, const char * to
) {
378 _cleanup_free_
char * p
= NULL
;
384 if ( symlink ( from
, to
) < 0 ) {
388 r
= readlink_malloc ( to
, & p
);
399 int symlink_atomic ( const char * from
, const char * to
) {
400 _cleanup_free_
char * t
= NULL
;
406 r
= tempfn_random ( to
, NULL
, & t
);
410 if ( symlink ( from
, t
) < 0 )
413 if ( rename ( t
, to
) < 0 ) {
421 int mknod_atomic ( const char * path
, mode_t mode
, dev_t dev
) {
422 _cleanup_free_
char * t
= NULL
;
427 r
= tempfn_random ( path
, NULL
, & t
);
431 if ( mknod ( t
, mode
, dev
) < 0 )
434 if ( rename ( t
, path
) < 0 ) {
442 int mkfifo_atomic ( const char * path
, mode_t mode
) {
443 _cleanup_free_
char * t
= NULL
;
448 r
= tempfn_random ( path
, NULL
, & t
);
452 if ( mkfifo ( t
, mode
) < 0 )
455 if ( rename ( t
, path
) < 0 ) {
463 int get_files_in_directory ( const char * path
, char *** list
) {
464 _cleanup_closedir_
DIR * d
= NULL
;
465 size_t bufsize
= 0 , n
= 0 ;
466 _cleanup_strv_free_
char ** l
= NULL
;
470 /* Returns all files in a directory in *list, and the number
471 * of files as return value. If list is NULL returns only the
483 if (! de
&& errno
> 0 )
488 dirent_ensure_type ( d
, de
);
490 if (! dirent_is_file ( de
))
494 /* one extra slot is needed for the terminating NULL */
495 if (! GREEDY_REALLOC ( l
, bufsize
, n
+ 2 ))
498 l
[ n
] = strdup ( de
-> d_name
);
509 l
= NULL
; /* avoid freeing */