2 * Copyright (C) 2019 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 * SPDX-License-Identifier: GPL-2.0-only
8 #include <common/compat/directory-handle.h>
9 #include <common/error.h>
10 #include <common/macros.h>
11 #include <common/runas.h>
12 #include <common/credentials.h>
13 #include <lttng/constant.h>
14 #include <common/dynamic-array.h>
16 #include <sys/types.h>
23 * This compatibility layer shares a common "base" that is implemented
24 * in terms of an internal API. This file contains two implementations
25 * of the internal API below.
28 int lttng_directory_handle_mkdir(
29 const struct lttng_directory_handle
*handle
,
30 const char *path
, mode_t mode
);
32 int _run_as_mkdir(const struct lttng_directory_handle
*handle
, const char *path
,
33 mode_t mode
, uid_t uid
, gid_t gid
);
35 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
36 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
);
38 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
39 const char *filename
, int flags
, mode_t mode
);
41 int _run_as_open(const struct lttng_directory_handle
*handle
,
43 int flags
, mode_t mode
, uid_t uid
, gid_t gid
);
45 int lttng_directory_handle_unlink(
46 const struct lttng_directory_handle
*handle
,
47 const char *filename
);
49 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
50 const char *filename
, uid_t uid
, gid_t gid
);
52 int _lttng_directory_handle_rename(
53 const struct lttng_directory_handle
*old_handle
,
55 const struct lttng_directory_handle
*new_handle
,
56 const char *new_name
);
58 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
60 const struct lttng_directory_handle
*new_handle
,
61 const char *new_name
, uid_t uid
, gid_t gid
);
63 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
66 int lttng_directory_handle_rmdir(
67 const struct lttng_directory_handle
*handle
, const char *name
);
69 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
70 const char *name
, uid_t uid
, gid_t gid
);
72 int _run_as_rmdir_recursive(
73 const struct lttng_directory_handle
*handle
, const char *name
,
74 uid_t uid
, gid_t gid
, int flags
);
76 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
);
78 void lttng_directory_handle_release(struct urcu_ref
*ref
);
83 * Special inode number reserved to represent the "current working directory".
84 * ino_t is spec'ed as being an unsigned integral type.
86 #define RESERVED_AT_FDCWD_INO \
88 uint64_t reserved_val; \
89 switch (sizeof(ino_t)) { \
91 reserved_val = UINT32_MAX; \
94 reserved_val = UINT64_MAX; \
99 (ino_t) reserved_val; \
102 struct lttng_directory_handle
*lttng_directory_handle_create(const char *path
)
104 const struct lttng_directory_handle cwd_handle
= {
108 /* Open a handle to the CWD if NULL is passed. */
109 return lttng_directory_handle_create_from_handle(path
, &cwd_handle
);
112 struct lttng_directory_handle
*lttng_directory_handle_create_from_handle(
114 const struct lttng_directory_handle
*ref_handle
)
117 struct lttng_directory_handle
*handle
= NULL
;
120 handle
= lttng_directory_handle_copy(ref_handle
);
124 ERR("Failed to initialize directory handle: provided path is an empty string");
128 dirfd
= openat(ref_handle
->dirfd
, path
, O_RDONLY
| O_DIRECTORY
| O_CLOEXEC
);
130 PERROR("Failed to initialize directory handle to \"%s\"", path
);
134 handle
= lttng_directory_handle_create_from_dirfd(dirfd
);
142 PERROR("Failed to close directory file descriptor");
147 struct lttng_directory_handle
*lttng_directory_handle_create_from_dirfd(
151 struct lttng_directory_handle
*handle
= zmalloc(sizeof(*handle
));
152 struct stat stat_buf
;
158 if (dirfd
!= AT_FDCWD
) {
159 ret
= fstat(dirfd
, &stat_buf
);
161 PERROR("Failed to fstat directory file descriptor %i", dirfd
);
162 lttng_directory_handle_release(&handle
->ref
);
167 handle
->directory_inode
= RESERVED_AT_FDCWD_INO
;
169 handle
->dirfd
= dirfd
;
170 urcu_ref_init(&handle
->ref
);
176 void lttng_directory_handle_release(struct urcu_ref
*ref
)
179 struct lttng_directory_handle
*handle
=
180 container_of(ref
, struct lttng_directory_handle
, ref
);
182 if (handle
->destroy_cb
) {
183 handle
->destroy_cb(handle
, handle
->destroy_cb_data
);
186 if (handle
->dirfd
== AT_FDCWD
|| handle
->dirfd
== -1) {
189 ret
= close(handle
->dirfd
);
191 PERROR("Failed to close directory file descriptor of directory handle");
194 lttng_directory_handle_invalidate(handle
);
198 struct lttng_directory_handle
*lttng_directory_handle_copy(
199 const struct lttng_directory_handle
*handle
)
201 struct lttng_directory_handle
*new_handle
= NULL
;
203 if (handle
->dirfd
== AT_FDCWD
) {
204 new_handle
= lttng_directory_handle_create_from_dirfd(AT_FDCWD
);
206 const int new_dirfd
= dup(handle
->dirfd
);
208 if (new_dirfd
== -1) {
209 PERROR("Failed to duplicate directory file descriptor of directory handle");
212 new_handle
= lttng_directory_handle_create_from_dirfd(
214 if (!new_handle
&& close(new_dirfd
)) {
215 PERROR("Failed to close directory file descriptor of directory handle");
222 bool lttng_directory_handle_equals(const struct lttng_directory_handle
*lhs
,
223 const struct lttng_directory_handle
*rhs
)
225 return lhs
->directory_inode
== rhs
->directory_inode
;
229 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
)
234 int lttng_directory_handle_stat(const struct lttng_directory_handle
*handle
,
235 const char *path
, struct stat
*st
)
237 return fstatat(handle
->dirfd
, path
, st
, 0);
240 bool lttng_directory_handle_uses_fd(
241 const struct lttng_directory_handle
*handle
)
243 return handle
->dirfd
!= AT_FDCWD
;
247 int lttng_directory_handle_mkdir(
248 const struct lttng_directory_handle
*handle
,
249 const char *path
, mode_t mode
)
251 return mkdirat(handle
->dirfd
, path
, mode
);
255 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
256 const char *filename
, int flags
, mode_t mode
)
258 return openat(handle
->dirfd
, filename
, flags
, mode
);
262 int _run_as_open(const struct lttng_directory_handle
*handle
,
263 const char *filename
,
264 int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
266 return run_as_openat(handle
->dirfd
, filename
, flags
, mode
, uid
, gid
);
270 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
271 const char *filename
, uid_t uid
, gid_t gid
)
273 return run_as_unlinkat(handle
->dirfd
, filename
, uid
, gid
);
277 int lttng_directory_handle_unlink(
278 const struct lttng_directory_handle
*handle
,
279 const char *filename
)
281 return unlinkat(handle
->dirfd
, filename
, 0);
285 int _run_as_mkdir(const struct lttng_directory_handle
*handle
,
286 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
288 return run_as_mkdirat(handle
->dirfd
, path
, mode
, uid
, gid
);
292 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
293 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
295 return run_as_mkdirat_recursive(handle
->dirfd
, path
, mode
, uid
, gid
);
299 int _lttng_directory_handle_rename(
300 const struct lttng_directory_handle
*old_handle
,
301 const char *old_name
,
302 const struct lttng_directory_handle
*new_handle
,
303 const char *new_name
)
305 return renameat(old_handle
->dirfd
, old_name
,
306 new_handle
->dirfd
, new_name
);
310 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
311 const char *old_name
,
312 const struct lttng_directory_handle
*new_handle
,
313 const char *new_name
, uid_t uid
, gid_t gid
)
315 return run_as_renameat(old_handle
->dirfd
, old_name
, new_handle
->dirfd
,
320 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
323 DIR *dir_stream
= NULL
;
324 int fd
= openat(handle
->dirfd
, path
, O_RDONLY
);
330 dir_stream
= fdopendir(fd
);
334 PERROR("Failed to open directory stream");
337 PERROR("Failed to close file descriptor to %s", path
);
347 int lttng_directory_handle_rmdir(
348 const struct lttng_directory_handle
*handle
, const char *name
)
350 int ret
= unlinkat(handle
->dirfd
, name
, AT_REMOVEDIR
);
352 PERROR("Failed to remove directory `%s`", name
);
359 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
360 const char *name
, uid_t uid
, gid_t gid
)
362 return run_as_rmdirat(handle
->dirfd
, name
, uid
, gid
);
366 int _run_as_rmdir_recursive(
367 const struct lttng_directory_handle
*handle
, const char *name
,
368 uid_t uid
, gid_t gid
, int flags
)
370 return run_as_rmdirat_recursive(handle
->dirfd
, name
, uid
, gid
, flags
);
373 #else /* HAVE_DIRFD */
376 int get_full_path(const struct lttng_directory_handle
*handle
,
377 const char *subdirectory
, char *fullpath
, size_t size
)
380 const bool subdirectory_is_absolute
=
381 subdirectory
&& *subdirectory
== '/';
382 const char * const base
= subdirectory_is_absolute
?
383 subdirectory
: handle
->base_path
;
384 const char * const end
= subdirectory
&& !subdirectory_is_absolute
?
386 const size_t base_len
= strlen(base
);
387 const size_t end_len
= end
? strlen(end
) : 0;
388 const bool add_separator_slash
= end
&& base
[base_len
- 1] != '/';
389 const bool add_trailing_slash
= end
&& end
[end_len
- 1] != '/';
391 ret
= snprintf(fullpath
, size
, "%s%s%s%s",
393 add_separator_slash
? "/" : "",
395 add_trailing_slash
? "/" : "");
396 if (ret
== -1 || ret
>= size
) {
397 ERR("Failed to format subdirectory from directory handle");
407 struct lttng_directory_handle
*_lttng_directory_handle_create(char *path
)
409 struct lttng_directory_handle
*handle
= zmalloc(sizeof(*handle
));
414 urcu_ref_init(&handle
->ref
);
415 handle
->base_path
= path
;
420 struct lttng_directory_handle
*lttng_directory_handle_create(
424 const char *cwd
= "";
425 size_t cwd_len
, path_len
;
426 char cwd_buf
[LTTNG_PATH_MAX
] = {};
427 char handle_buf
[LTTNG_PATH_MAX
] = {};
428 struct lttng_directory_handle
*new_handle
= NULL
;
429 bool add_cwd_slash
= false, add_trailing_slash
= false;
430 const struct lttng_directory_handle cwd_handle
= {
431 .base_path
= handle_buf
,
434 path_len
= path
? strlen(path
) : 0;
435 add_trailing_slash
= path
&& path
[path_len
- 1] != '/';
436 if (!path
|| (path
&& *path
!= '/')) {
437 cwd
= getcwd(cwd_buf
, sizeof(cwd_buf
));
439 PERROR("Failed to initialize directory handle, can't get current working directory");
443 cwd_len
= strlen(cwd
);
445 ERR("Failed to initialize directory handle, current working directory path has a length of 0");
449 add_cwd_slash
= cwd
[cwd_len
- 1] != '/';
452 ret
= snprintf(handle_buf
, sizeof(handle_buf
), "%s%s%s%s",
454 add_cwd_slash
? "/" : "",
456 add_trailing_slash
? "/" : "");
457 if (ret
== -1 || ret
>= LTTNG_PATH_MAX
) {
458 ERR("Failed to initialize directory handle, failed to format directory path");
462 new_handle
= lttng_directory_handle_create_from_handle(path
, &cwd_handle
);
467 struct lttng_directory_handle
*lttng_directory_handle_create_from_handle(
469 const struct lttng_directory_handle
*ref_handle
)
472 size_t path_len
, handle_path_len
;
473 bool add_trailing_slash
;
474 struct stat stat_buf
;
475 struct lttng_directory_handle
*new_handle
= NULL
;
476 char *new_path
= NULL
;
478 LTTNG_ASSERT(ref_handle
&& ref_handle
->base_path
);
480 ret
= lttng_directory_handle_stat(ref_handle
, path
, &stat_buf
);
482 PERROR("Failed to create directory handle");
484 } else if (!S_ISDIR(stat_buf
.st_mode
)) {
485 char full_path
[LTTNG_PATH_MAX
];
487 /* Best effort for logging purposes. */
488 ret
= get_full_path(ref_handle
, path
, full_path
,
494 ERR("Failed to initialize directory handle to \"%s\": not a directory",
499 new_handle
= lttng_directory_handle_copy(ref_handle
);
503 path_len
= strlen(path
);
505 ERR("Failed to initialize directory handle: provided path is an empty string");
510 new_path
= strdup(path
);
514 /* Takes ownership of new_path. */
515 new_handle
= _lttng_directory_handle_create(new_path
);
520 add_trailing_slash
= path
[path_len
- 1] != '/';
522 handle_path_len
= strlen(ref_handle
->base_path
) + path_len
+
523 !!add_trailing_slash
;
524 if (handle_path_len
>= LTTNG_PATH_MAX
) {
525 ERR("Failed to initialize directory handle as the resulting path's length (%zu bytes) exceeds the maximal allowed length (%d bytes)",
526 handle_path_len
, LTTNG_PATH_MAX
);
529 new_path
= zmalloc(handle_path_len
);
531 PERROR("Failed to initialize directory handle");
535 ret
= sprintf(new_handle
->base_path
, "%s%s%s",
536 ref_handle
->base_path
,
538 add_trailing_slash
? "/" : "");
539 if (ret
== -1 || ret
>= handle_path_len
) {
540 ERR("Failed to initialize directory handle: path formatting failed");
543 new_handle
= _lttng_directory_handle_create(new_path
);
550 struct lttng_directory_handle
*lttng_directory_handle_create_from_dirfd(
553 LTTNG_ASSERT(dirfd
== AT_FDCWD
);
554 return lttng_directory_handle_create(NULL
);
558 void lttng_directory_handle_release(struct urcu_ref
*ref
)
560 struct lttng_directory_handle
*handle
=
561 container_of(ref
, struct lttng_directory_handle
, ref
);
563 free(handle
->base_path
);
564 lttng_directory_handle_invalidate(handle
);
568 struct lttng_directory_handle
*lttng_directory_handle_copy(
569 const struct lttng_directory_handle
*handle
)
571 struct lttng_directory_handle
*new_handle
= NULL
;
572 char *new_path
= NULL
;
574 if (handle
->base_path
) {
575 new_path
= strdup(handle
->base_path
);
580 new_handle
= _lttng_directory_handle_create(new_path
);
585 bool lttng_directory_handle_equals(const struct lttng_directory_handle
*lhs
,
586 const struct lttng_directory_handle
*rhs
)
588 return strcmp(lhs
->base_path
, rhs
->base_path
) == 0;
592 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
)
594 handle
->base_path
= NULL
;
597 int lttng_directory_handle_stat(const struct lttng_directory_handle
*handle
,
598 const char *subdirectory
, struct stat
*st
)
601 char fullpath
[LTTNG_PATH_MAX
];
603 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
609 ret
= stat(fullpath
, st
);
614 bool lttng_directory_handle_uses_fd(
615 const struct lttng_directory_handle
*handle
)
621 int lttng_directory_handle_mkdir(const struct lttng_directory_handle
*handle
,
622 const char *subdirectory
, mode_t mode
)
625 char fullpath
[LTTNG_PATH_MAX
];
627 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
633 ret
= mkdir(fullpath
, mode
);
639 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
640 const char *filename
, int flags
, mode_t mode
)
643 char fullpath
[LTTNG_PATH_MAX
];
645 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
651 ret
= open(fullpath
, flags
, mode
);
657 int lttng_directory_handle_unlink(
658 const struct lttng_directory_handle
*handle
,
659 const char *filename
)
662 char fullpath
[LTTNG_PATH_MAX
];
664 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
670 ret
= unlink(fullpath
);
676 int _run_as_mkdir(const struct lttng_directory_handle
*handle
, const char *path
,
677 mode_t mode
, uid_t uid
, gid_t gid
)
680 char fullpath
[LTTNG_PATH_MAX
];
682 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
688 ret
= run_as_mkdir(fullpath
, mode
, uid
, gid
);
694 int _run_as_open(const struct lttng_directory_handle
*handle
,
695 const char *filename
,
696 int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
699 char fullpath
[LTTNG_PATH_MAX
];
701 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
707 ret
= run_as_open(fullpath
, flags
, mode
, uid
, gid
);
713 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
714 const char *filename
, uid_t uid
, gid_t gid
)
717 char fullpath
[LTTNG_PATH_MAX
];
719 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
725 ret
= run_as_unlink(fullpath
, uid
, gid
);
731 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
732 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
735 char fullpath
[LTTNG_PATH_MAX
];
737 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
743 ret
= run_as_mkdir_recursive(fullpath
, mode
, uid
, gid
);
749 int _lttng_directory_handle_rename(
750 const struct lttng_directory_handle
*old_handle
,
751 const char *old_name
,
752 const struct lttng_directory_handle
*new_handle
,
753 const char *new_name
)
756 char old_fullpath
[LTTNG_PATH_MAX
];
757 char new_fullpath
[LTTNG_PATH_MAX
];
759 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
760 sizeof(old_fullpath
));
765 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
766 sizeof(new_fullpath
));
772 ret
= rename(old_fullpath
, new_fullpath
);
778 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
779 const char *old_name
,
780 const struct lttng_directory_handle
*new_handle
,
781 const char *new_name
, uid_t uid
, gid_t gid
)
784 char old_fullpath
[LTTNG_PATH_MAX
];
785 char new_fullpath
[LTTNG_PATH_MAX
];
787 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
788 sizeof(old_fullpath
));
793 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
794 sizeof(new_fullpath
));
800 ret
= run_as_rename(old_fullpath
, new_fullpath
, uid
, gid
);
806 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
810 DIR *dir_stream
= NULL
;
811 char fullpath
[LTTNG_PATH_MAX
];
813 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
819 dir_stream
= opendir(fullpath
);
825 int lttng_directory_handle_rmdir(
826 const struct lttng_directory_handle
*handle
, const char *name
)
829 char fullpath
[LTTNG_PATH_MAX
];
831 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
837 ret
= rmdir(fullpath
);
843 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
844 const char *name
, uid_t uid
, gid_t gid
)
847 char fullpath
[LTTNG_PATH_MAX
];
849 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
855 ret
= run_as_rmdir(fullpath
, uid
, gid
);
861 int _run_as_rmdir_recursive(
862 const struct lttng_directory_handle
*handle
, const char *name
,
863 uid_t uid
, gid_t gid
, int flags
)
866 char fullpath
[LTTNG_PATH_MAX
];
868 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
874 ret
= run_as_rmdir_recursive(fullpath
, uid
, gid
, flags
);
879 #endif /* HAVE_DIRFD */
881 /* Common implementation. */
884 * On some filesystems (e.g. nfs), mkdir will validate access rights before
885 * checking for the existence of the path element. This means that on a setup
886 * where "/home/" is a mounted NFS share, and running as an unpriviledged user,
887 * recursively creating a path of the form "/home/my_user/trace/" will fail with
888 * EACCES on mkdir("/home", ...).
890 * Checking the path for existence allows us to work around this behaviour.
893 int create_directory_check_exists(const struct lttng_directory_handle
*handle
,
894 const char *path
, mode_t mode
)
899 ret
= lttng_directory_handle_stat(handle
, path
, &st
);
901 if (S_ISDIR(st
.st_mode
)) {
902 /* Directory exists, skip. */
905 /* Exists, but is not a directory. */
910 } else if (errno
!= ENOENT
) {
915 * Let mkdir handle other errors as the caller expects mkdir
918 ret
= lttng_directory_handle_mkdir(handle
, path
, mode
);
924 int create_directory_recursive(const struct lttng_directory_handle
*handle
,
925 const char *path
, mode_t mode
)
927 char *p
, tmp
[LTTNG_PATH_MAX
];
933 ret
= lttng_strncpy(tmp
, path
, sizeof(tmp
));
935 ERR("Failed to create directory: provided path's length (%zu bytes) exceeds the maximal allowed length (%zu bytes)",
936 strlen(path
) + 1, sizeof(tmp
));
941 if (tmp
[len
- 1] == '/') {
945 for (p
= tmp
+ 1; *p
; p
++) {
948 if (tmp
[strlen(tmp
) - 1] == '.' &&
949 tmp
[strlen(tmp
) - 2] == '.' &&
950 tmp
[strlen(tmp
) - 3] == '/') {
951 ERR("Using '/../' is not permitted in the trace path (%s)",
956 ret
= create_directory_check_exists(handle
, tmp
, mode
);
958 if (errno
!= EACCES
) {
959 PERROR("Failed to create directory \"%s\"",
969 ret
= create_directory_check_exists(handle
, tmp
, mode
);
971 PERROR("mkdirat recursive last element");
978 bool lttng_directory_handle_get(struct lttng_directory_handle
*handle
)
980 return urcu_ref_get_unless_zero(&handle
->ref
);
983 void lttng_directory_handle_put(struct lttng_directory_handle
*handle
)
988 LTTNG_ASSERT(handle
->ref
.refcount
);
989 urcu_ref_put(&handle
->ref
, lttng_directory_handle_release
);
992 int lttng_directory_handle_create_subdirectory_as_user(
993 const struct lttng_directory_handle
*handle
,
994 const char *subdirectory
,
995 mode_t mode
, const struct lttng_credentials
*creds
)
1000 /* Run as current user. */
1001 ret
= create_directory_check_exists(handle
,
1002 subdirectory
, mode
);
1004 ret
= _run_as_mkdir(handle
, subdirectory
, mode
,
1005 lttng_credentials_get_uid(creds
),
1006 lttng_credentials_get_gid(creds
));
1012 int lttng_directory_handle_create_subdirectory_recursive_as_user(
1013 const struct lttng_directory_handle
*handle
,
1014 const char *subdirectory_path
,
1015 mode_t mode
, const struct lttng_credentials
*creds
)
1020 /* Run as current user. */
1021 ret
= create_directory_recursive(handle
,
1022 subdirectory_path
, mode
);
1024 ret
= _run_as_mkdir_recursive(handle
, subdirectory_path
,
1025 mode
, lttng_credentials_get_uid(creds
), lttng_credentials_get_gid(creds
));
1031 int lttng_directory_handle_create_subdirectory(
1032 const struct lttng_directory_handle
*handle
,
1033 const char *subdirectory
,
1036 return lttng_directory_handle_create_subdirectory_as_user(
1037 handle
, subdirectory
, mode
, NULL
);
1040 int lttng_directory_handle_create_subdirectory_recursive(
1041 const struct lttng_directory_handle
*handle
,
1042 const char *subdirectory_path
,
1045 return lttng_directory_handle_create_subdirectory_recursive_as_user(
1046 handle
, subdirectory_path
, mode
, NULL
);
1049 int lttng_directory_handle_open_file_as_user(
1050 const struct lttng_directory_handle
*handle
,
1051 const char *filename
,
1052 int flags
, mode_t mode
,
1053 const struct lttng_credentials
*creds
)
1058 /* Run as current user. */
1059 ret
= lttng_directory_handle_open(handle
, filename
, flags
,
1062 ret
= _run_as_open(handle
, filename
, flags
, mode
,
1063 lttng_credentials_get_uid(creds
), lttng_credentials_get_gid(creds
));
1068 int lttng_directory_handle_open_file(
1069 const struct lttng_directory_handle
*handle
,
1070 const char *filename
,
1071 int flags
, mode_t mode
)
1073 return lttng_directory_handle_open_file_as_user(handle
, filename
, flags
,
1077 int lttng_directory_handle_unlink_file_as_user(
1078 const struct lttng_directory_handle
*handle
,
1079 const char *filename
,
1080 const struct lttng_credentials
*creds
)
1085 /* Run as current user. */
1086 ret
= lttng_directory_handle_unlink(handle
, filename
);
1088 ret
= _run_as_unlink(handle
, filename
, lttng_credentials_get_uid(creds
), lttng_credentials_get_gid(creds
));
1093 int lttng_directory_handle_unlink_file(
1094 const struct lttng_directory_handle
*handle
,
1095 const char *filename
)
1097 return lttng_directory_handle_unlink_file_as_user(handle
,
1101 int lttng_directory_handle_rename(
1102 const struct lttng_directory_handle
*old_handle
,
1103 const char *old_name
,
1104 const struct lttng_directory_handle
*new_handle
,
1105 const char *new_name
)
1107 return lttng_directory_handle_rename_as_user(old_handle
, old_name
,
1108 new_handle
, new_name
, NULL
);
1111 int lttng_directory_handle_rename_as_user(
1112 const struct lttng_directory_handle
*old_handle
,
1113 const char *old_name
,
1114 const struct lttng_directory_handle
*new_handle
,
1115 const char *new_name
,
1116 const struct lttng_credentials
*creds
)
1121 /* Run as current user. */
1122 ret
= _lttng_directory_handle_rename(old_handle
,
1123 old_name
, new_handle
, new_name
);
1125 ret
= _run_as_rename(old_handle
, old_name
, new_handle
,
1126 new_name
, lttng_credentials_get_uid(creds
), lttng_credentials_get_gid(creds
));
1131 int lttng_directory_handle_remove_subdirectory(
1132 const struct lttng_directory_handle
*handle
,
1135 return lttng_directory_handle_remove_subdirectory_as_user(handle
, name
,
1139 int lttng_directory_handle_remove_subdirectory_as_user(
1140 const struct lttng_directory_handle
*handle
,
1142 const struct lttng_credentials
*creds
)
1147 /* Run as current user. */
1148 ret
= lttng_directory_handle_rmdir(handle
, name
);
1150 ret
= _run_as_rmdir(handle
, name
, lttng_credentials_get_uid(creds
), lttng_credentials_get_gid(creds
));
1155 struct rmdir_frame
{
1156 ssize_t parent_frame_idx
;
1159 /* Size including '\0'. */
1164 void rmdir_frame_fini(void *data
)
1167 struct rmdir_frame
*frame
= data
;
1169 ret
= closedir(frame
->dir
);
1171 PERROR("Failed to close directory stream");
1176 int remove_directory_recursive(const struct lttng_directory_handle
*handle
,
1177 const char *path
, int flags
)
1180 struct lttng_dynamic_array frames
;
1181 size_t current_frame_idx
= 0;
1182 struct rmdir_frame initial_frame
= {
1183 .parent_frame_idx
= -1,
1184 .dir
= lttng_directory_handle_opendir(handle
, path
),
1186 .path_size
= strlen(path
) + 1,
1188 struct lttng_dynamic_buffer current_path
;
1189 const char separator
= '/';
1191 lttng_dynamic_buffer_init(¤t_path
);
1192 lttng_dynamic_array_init(&frames
, sizeof(struct rmdir_frame
),
1195 if (flags
& ~(LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
|
1196 LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG
)) {
1197 ERR("Unknown flags %d", flags
);
1202 if (!initial_frame
.dir
) {
1203 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
&&
1205 DBG("Cannot rmdir \"%s\": root does not exist", path
);
1209 PERROR("Failed to rmdir \"%s\"", path
);
1215 ret
= lttng_dynamic_array_add_element(&frames
, &initial_frame
);
1217 ERR("Failed to push context frame during recursive directory removal");
1218 rmdir_frame_fini(&initial_frame
);
1222 ret
= lttng_dynamic_buffer_append(
1223 ¤t_path
, path
, initial_frame
.path_size
);
1225 ERR("Failed to set initial path during recursive directory removal");
1230 while (lttng_dynamic_array_get_count(&frames
) > 0) {
1231 struct dirent
*entry
;
1232 struct rmdir_frame
*current_frame
=
1233 lttng_dynamic_array_get_element(
1234 &frames
, current_frame_idx
);
1236 LTTNG_ASSERT(current_frame
->dir
);
1237 ret
= lttng_dynamic_buffer_set_size(
1238 ¤t_path
, current_frame
->path_size
);
1240 current_path
.data
[current_path
.size
- 1] = '\0';
1242 while ((entry
= readdir(current_frame
->dir
))) {
1245 if (!strcmp(entry
->d_name
, ".") ||
1246 !strcmp(entry
->d_name
, "..")) {
1250 /* Set current_path to the entry's path. */
1251 ret
= lttng_dynamic_buffer_set_size(
1252 ¤t_path
, current_path
.size
- 1);
1254 ret
= lttng_dynamic_buffer_append(¤t_path
,
1255 &separator
, sizeof(separator
));
1259 ret
= lttng_dynamic_buffer_append(¤t_path
,
1261 strlen(entry
->d_name
) + 1);
1266 if (lttng_directory_handle_stat(
1267 handle
, current_path
.data
, &st
)) {
1268 if ((flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
) &&
1272 PERROR("Failed to stat \"%s\"",
1278 if (!S_ISDIR(st
.st_mode
)) {
1279 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
) {
1280 current_frame
->empty
= false;
1283 /* Not empty, abort. */
1284 DBG("Directory \"%s\" is not empty; refusing to remove directory",
1290 struct rmdir_frame new_frame
= {
1291 .path_size
= current_path
.size
,
1292 .dir
= lttng_directory_handle_opendir(
1296 .parent_frame_idx
= current_frame_idx
,
1299 if (!new_frame
.dir
) {
1300 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
&&
1302 DBG("Non-existing directory stream during recursive directory removal");
1305 PERROR("Failed to open directory stream during recursive directory removal");
1310 ret
= lttng_dynamic_array_add_element(
1311 &frames
, &new_frame
);
1313 ERR("Failed to push context frame during recursive directory removal");
1314 rmdir_frame_fini(&new_frame
);
1317 current_frame_idx
++;
1318 /* We break iteration on readdir. */
1326 /* Pop rmdir frame. */
1327 if (current_frame
->empty
) {
1328 ret
= lttng_directory_handle_rmdir(
1329 handle
, current_path
.data
);
1331 if ((flags
& LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG
) ||
1333 PERROR("Failed to remove \"%s\" during recursive directory removal",
1337 DBG("Non-existing directory stream during recursive directory removal");
1339 } else if (current_frame
->parent_frame_idx
>= 0) {
1340 struct rmdir_frame
*parent_frame
;
1342 parent_frame
= lttng_dynamic_array_get_element(&frames
,
1343 current_frame
->parent_frame_idx
);
1344 LTTNG_ASSERT(parent_frame
);
1345 parent_frame
->empty
= false;
1347 ret
= lttng_dynamic_array_remove_element(
1348 &frames
, current_frame_idx
);
1350 ERR("Failed to pop context frame during recursive directory removal");
1353 current_frame_idx
--;
1356 lttng_dynamic_array_reset(&frames
);
1357 lttng_dynamic_buffer_reset(¤t_path
);
1361 int lttng_directory_handle_remove_subdirectory_recursive(
1362 const struct lttng_directory_handle
*handle
,
1366 return lttng_directory_handle_remove_subdirectory_recursive_as_user(
1367 handle
, name
, NULL
, flags
);
1370 int lttng_directory_handle_remove_subdirectory_recursive_as_user(
1371 const struct lttng_directory_handle
*handle
,
1373 const struct lttng_credentials
*creds
,
1379 /* Run as current user. */
1380 ret
= remove_directory_recursive(handle
, name
, flags
);
1382 ret
= _run_as_rmdir_recursive(handle
, name
, lttng_credentials_get_uid(creds
),
1383 lttng_credentials_get_gid(creds
), flags
);