Fix: remove assertions of the existence of a trace chunk
[lttng-tools.git] / src / common / compat / directory-handle.c
CommitLineData
18710679
JG
1/*
2 * Copyright (C) 2019 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2 only,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18#include <common/compat/directory-handle.h>
19#include <common/error.h>
20#include <common/macros.h>
21#include <common/runas.h>
22#include <common/credentials.h>
23#include <lttng/constant.h>
93bed9fe 24#include <common/dynamic-array.h>
18710679
JG
25
26#include <assert.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <fcntl.h>
30#include <unistd.h>
93bed9fe 31#include <dirent.h>
18710679 32
2912cead
JG
33/*
34 * This compatibility layer shares a common "base" that is implemented
35 * in terms of an internal API. This file contains two implementations
36 * of the internal API below.
37 */
18710679
JG
38static
39int lttng_directory_handle_stat(const struct lttng_directory_handle *handle,
40 const char *path, struct stat *st);
41static
42int lttng_directory_handle_mkdir(
43 const struct lttng_directory_handle *handle,
44 const char *path, mode_t mode);
45static
46int _run_as_mkdir(const struct lttng_directory_handle *handle, const char *path,
47 mode_t mode, uid_t uid, gid_t gid);
48static
49int _run_as_mkdir_recursive(const struct lttng_directory_handle *handle,
50 const char *path, mode_t mode, uid_t uid, gid_t gid);
46307ffe 51static
2912cead
JG
52int lttng_directory_handle_open(const struct lttng_directory_handle *handle,
53 const char *filename, int flags, mode_t mode);
54static
55int _run_as_open(const struct lttng_directory_handle *handle,
56 const char *filename,
57 int flags, mode_t mode, uid_t uid, gid_t gid);
58static
59int lttng_directory_handle_unlink(
60 const struct lttng_directory_handle *handle,
61 const char *filename);
62static
63int _run_as_unlink(const struct lttng_directory_handle *handle,
64 const char *filename, uid_t uid, gid_t gid);
65static
93bed9fe
JG
66int _lttng_directory_handle_rename(
67 const struct lttng_directory_handle *old_handle,
68 const char *old_name,
69 const struct lttng_directory_handle *new_handle,
70 const char *new_name);
71static
72int _run_as_rename(const struct lttng_directory_handle *old_handle,
73 const char *old_name,
74 const struct lttng_directory_handle *new_handle,
75 const char *new_name, uid_t uid, gid_t gid);
76static
77DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle *handle,
78 const char *path);
79static
80int lttng_directory_handle_rmdir(
81 const struct lttng_directory_handle *handle, const char *name);
82static
83int _run_as_rmdir(const struct lttng_directory_handle *handle,
84 const char *name, uid_t uid, gid_t gid);
85static
86int _run_as_rmdir_recursive(
87 const struct lttng_directory_handle *handle, const char *name,
88 uid_t uid, gid_t gid);
89static
46307ffe 90void lttng_directory_handle_invalidate(struct lttng_directory_handle *handle);
18710679
JG
91
92#ifdef COMPAT_DIRFD
93
94LTTNG_HIDDEN
fd774fc6 95int lttng_directory_handle_init(struct lttng_directory_handle *new_handle,
18710679 96 const char *path)
fd774fc6
JG
97{
98 const struct lttng_directory_handle cwd_handle = {
99 .dirfd = AT_FDCWD,
100 };
101
102 /* Open a handle to the CWD if NULL is passed. */
103 return lttng_directory_handle_init_from_handle(new_handle,
104 path,
105 &cwd_handle);
106}
107
108LTTNG_HIDDEN
109int lttng_directory_handle_init_from_handle(
110 struct lttng_directory_handle *new_handle, const char *path,
111 const struct lttng_directory_handle *handle)
18710679
JG
112{
113 int ret;
114
115 if (!path) {
fd774fc6 116 ret = lttng_directory_handle_copy(handle, new_handle);
18710679
JG
117 goto end;
118 }
fd774fc6
JG
119 if (!*path) {
120 ERR("Failed to initialize directory handle: provided path is an empty string");
121 ret = -1;
122 goto end;
123 }
124 ret = openat(handle->dirfd, path, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
18710679
JG
125 if (ret == -1) {
126 PERROR("Failed to initialize directory handle to \"%s\"", path);
127 goto end;
128 }
fd774fc6 129 new_handle->dirfd = ret;
18710679
JG
130 ret = 0;
131end:
132 return ret;
133}
134
135LTTNG_HIDDEN
136int lttng_directory_handle_init_from_dirfd(
137 struct lttng_directory_handle *handle, int dirfd)
138{
139 handle->dirfd = dirfd;
140 return 0;
141}
142
143LTTNG_HIDDEN
144void lttng_directory_handle_fini(struct lttng_directory_handle *handle)
145{
146 int ret;
147
46307ffe
JG
148 if (handle->dirfd == AT_FDCWD || handle->dirfd == -1) {
149 goto end;
18710679
JG
150 }
151 ret = close(handle->dirfd);
152 if (ret == -1) {
153 PERROR("Failed to close directory file descriptor of directory handle");
154 }
46307ffe
JG
155end:
156 lttng_directory_handle_invalidate(handle);
18710679
JG
157}
158
578e21bd
JG
159LTTNG_HIDDEN
160int lttng_directory_handle_copy(const struct lttng_directory_handle *handle,
161 struct lttng_directory_handle *new_copy)
162{
163 int ret = 0;
164
165 if (handle->dirfd == AT_FDCWD) {
166 new_copy->dirfd = handle->dirfd;
167 } else {
168 new_copy->dirfd = dup(handle->dirfd);
169 if (new_copy->dirfd == -1) {
170 PERROR("Failed to duplicate directory fd of directory handle");
171 ret = -1;
172 }
173 }
174 return ret;
175}
176
46307ffe
JG
177static
178void lttng_directory_handle_invalidate(struct lttng_directory_handle *handle)
179{
180 handle->dirfd = -1;
181}
182
18710679
JG
183static
184int lttng_directory_handle_stat(const struct lttng_directory_handle *handle,
185 const char *path, struct stat *st)
186{
187 return fstatat(handle->dirfd, path, st, 0);
188}
189
190static
191int lttng_directory_handle_mkdir(
192 const struct lttng_directory_handle *handle,
193 const char *path, mode_t mode)
194{
195 return mkdirat(handle->dirfd, path, mode);
196}
197
198static
2912cead
JG
199int lttng_directory_handle_open(const struct lttng_directory_handle *handle,
200 const char *filename, int flags, mode_t mode)
201{
202 return openat(handle->dirfd, filename, flags, mode);
203}
204
205static
206int _run_as_open(const struct lttng_directory_handle *handle,
207 const char *filename,
208 int flags, mode_t mode, uid_t uid, gid_t gid)
209{
210 return run_as_openat(handle->dirfd, filename, flags, mode, uid, gid);
211}
212
213static
214int _run_as_unlink(const struct lttng_directory_handle *handle,
215 const char *filename, uid_t uid, gid_t gid)
216{
217 return run_as_unlinkat(handle->dirfd, filename, uid, gid);
218}
219
220static
221int lttng_directory_handle_unlink(
222 const struct lttng_directory_handle *handle,
223 const char *filename)
224{
225 return unlinkat(handle->dirfd, filename, 0);
226}
227
228static
229int _run_as_mkdir(const struct lttng_directory_handle *handle,
230 const char *path, mode_t mode, uid_t uid, gid_t gid)
18710679
JG
231{
232 return run_as_mkdirat(handle->dirfd, path, mode, uid, gid);
233}
234
235static
236int _run_as_mkdir_recursive(const struct lttng_directory_handle *handle,
237 const char *path, mode_t mode, uid_t uid, gid_t gid)
238{
239 return run_as_mkdirat_recursive(handle->dirfd, path, mode, uid, gid);
240}
241
93bed9fe
JG
242static
243int _lttng_directory_handle_rename(
244 const struct lttng_directory_handle *old_handle,
245 const char *old_name,
246 const struct lttng_directory_handle *new_handle,
247 const char *new_name)
248{
249 return renameat(old_handle->dirfd, old_name,
250 new_handle->dirfd, new_name);
251}
252
253static
254int _run_as_rename(const struct lttng_directory_handle *old_handle,
255 const char *old_name,
256 const struct lttng_directory_handle *new_handle,
257 const char *new_name, uid_t uid, gid_t gid)
258{
259 return run_as_renameat(old_handle->dirfd, old_name, new_handle->dirfd,
260 new_name, uid, gid);
261}
262
263static
264DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle *handle,
265 const char *path)
266{
267 DIR *dir_stream = NULL;
268 int fd = openat(handle->dirfd, path, O_RDONLY);
269
270 if (fd < 0) {
271 goto end;
272 }
273
274 dir_stream = fdopendir(fd);
275 if (!dir_stream) {
276 int ret;
277
278 PERROR("Failed to open directory stream");
279 ret = close(fd);
280 if (ret) {
281 PERROR("Failed to close file descriptor to %s", path);
282 }
283 goto end;
284 }
285
286end:
287 return dir_stream;
288}
289
290static
291int lttng_directory_handle_rmdir(
292 const struct lttng_directory_handle *handle, const char *name)
293{
294 return unlinkat(handle->dirfd, name, AT_REMOVEDIR);
295}
296
297static
298int _run_as_rmdir(const struct lttng_directory_handle *handle,
299 const char *name, uid_t uid, gid_t gid)
300{
301 return run_as_rmdirat(handle->dirfd, name, uid, gid);
302}
303
304static
305int _run_as_rmdir_recursive(
306 const struct lttng_directory_handle *handle, const char *name,
307 uid_t uid, gid_t gid)
308{
309 return run_as_rmdirat_recursive(handle->dirfd, name, uid, gid);
310}
311
18710679
JG
312#else /* COMPAT_DIRFD */
313
fd774fc6
JG
314static
315int get_full_path(const struct lttng_directory_handle *handle,
316 const char *subdirectory, char *fullpath, size_t size)
317{
318 int ret;
93bed9fe
JG
319 const bool subdirectory_is_absolute =
320 subdirectory && *subdirectory == '/';
321 const char * const base = subdirectory_is_absolute ?
322 subdirectory : handle->base_path;
323 const char * const end = subdirectory && !subdirectory_is_absolute ?
324 subdirectory : NULL;
325 const size_t base_len = strlen(base);
326 const size_t end_len = end ? strlen(end) : 0;
327 const bool add_separator_slash = end && base[base_len - 1] != '/';
328 const bool add_trailing_slash = end && end[end_len - 1] != '/';
329
330 ret = snprintf(fullpath, size, "%s%s%s%s",
331 base,
332 add_separator_slash ? "/" : "",
333 end ? end : "",
334 add_trailing_slash ? "/" : "");
fd774fc6
JG
335 if (ret == -1 || ret >= size) {
336 ERR("Failed to format subdirectory from directory handle");
337 ret = -1;
93bed9fe 338 goto end;
fd774fc6
JG
339 }
340 ret = 0;
93bed9fe 341end:
fd774fc6
JG
342 return ret;
343}
344
18710679
JG
345LTTNG_HIDDEN
346int lttng_directory_handle_init(struct lttng_directory_handle *handle,
347 const char *path)
348{
349 int ret;
93bed9fe 350 const char *cwd = "";
fd774fc6
JG
351 size_t cwd_len, path_len;
352 char cwd_buf[LTTNG_PATH_MAX] = {};
353 char handle_buf[LTTNG_PATH_MAX] = {};
93bed9fe 354 bool add_cwd_slash = false, add_trailing_slash = false;
fd774fc6
JG
355 const struct lttng_directory_handle cwd_handle = {
356 .base_path = handle_buf,
357 };
358
fd774fc6 359 path_len = path ? strlen(path) : 0;
fd774fc6 360 add_trailing_slash = path && path[path_len - 1] != '/';
93bed9fe
JG
361 if (!path || (path && *path != '/')) {
362 cwd = getcwd(cwd_buf, sizeof(cwd_buf));
363 if (!cwd) {
364 PERROR("Failed to initialize directory handle, can't get current working directory");
365 ret = -1;
366 goto end;
367 }
368 cwd_len = strlen(cwd);
369 if (cwd_len == 0) {
370 ERR("Failed to initialize directory handle, current working directory path has a length of 0");
371 ret = -1;
372 goto end;
373 }
374 add_cwd_slash = cwd[cwd_len - 1] != '/';
375 }
fd774fc6
JG
376
377 ret = snprintf(handle_buf, sizeof(handle_buf), "%s%s%s%s",
378 cwd,
379 add_cwd_slash ? "/" : "",
380 path ? : "",
381 add_trailing_slash ? "/" : "");
382 if (ret == -1 || ret >= LTTNG_PATH_MAX) {
383 ERR("Failed to initialize directory handle, failed to format directory path");
384 goto end;
18710679 385 }
93bed9fe 386
fd774fc6
JG
387 ret = lttng_directory_handle_init_from_handle(handle, path,
388 &cwd_handle);
389end:
390 return ret;
391}
18710679 392
fd774fc6
JG
393LTTNG_HIDDEN
394int lttng_directory_handle_init_from_handle(
395 struct lttng_directory_handle *new_handle, const char *path,
396 const struct lttng_directory_handle *handle)
397{
398 int ret;
399 size_t path_len, handle_path_len;
400 bool add_trailing_slash;
401 struct stat stat_buf;
18710679 402
fd774fc6
JG
403 assert(handle && handle->base_path);
404
405 ret = lttng_directory_handle_stat(handle, path, &stat_buf);
406 if (ret == -1) {
407 PERROR("Failed to create directory handle");
408 goto end;
409 } else if (!S_ISDIR(stat_buf.st_mode)) {
410 char full_path[LTTNG_PATH_MAX];
411
412 /* Best effort for logging purposes. */
413 ret = get_full_path(handle, path, full_path,
414 sizeof(full_path));
415 if (ret) {
416 full_path[0] = '\0';
18710679 417 }
fd774fc6
JG
418
419 ERR("Failed to initialize directory handle to \"%s\": not a directory",
420 full_path);
421 ret = -1;
422 goto end;
423 }
424 if (!path) {
425 ret = lttng_directory_handle_copy(handle, new_handle);
426 goto end;
427 }
428
429 path_len = strlen(path);
430 if (path_len == 0) {
431 ERR("Failed to initialize directory handle: provided path is an empty string");
432 ret = -1;
433 goto end;
434 }
435 if (*path == '/') {
436 new_handle->base_path = strdup(path);
437 ret = new_handle->base_path ? 0 : -1;
438 goto end;
18710679
JG
439 }
440
fd774fc6
JG
441 add_trailing_slash = path[path_len - 1] != '/';
442
443 handle_path_len = strlen(handle->base_path) + path_len +
444 !!add_trailing_slash;
18710679
JG
445 if (handle_path_len >= LTTNG_PATH_MAX) {
446 ERR("Failed to initialize directory handle as the resulting path's length (%zu bytes) exceeds the maximal allowed length (%d bytes)",
447 handle_path_len, LTTNG_PATH_MAX);
448 ret = -1;
449 goto end;
450 }
fd774fc6
JG
451 new_handle->base_path = zmalloc(handle_path_len);
452 if (!new_handle->base_path) {
18710679
JG
453 PERROR("Failed to initialize directory handle");
454 ret = -1;
455 goto end;
456 }
457
fd774fc6
JG
458 ret = sprintf(new_handle->base_path, "%s%s%s",
459 handle->base_path,
460 path,
461 add_trailing_slash ? "/" : "");
18710679
JG
462 if (ret == -1 || ret >= handle_path_len) {
463 ERR("Failed to initialize directory handle: path formatting failed");
464 ret = -1;
465 goto end;
466 }
467end:
468 return ret;
469}
470
471LTTNG_HIDDEN
472int lttng_directory_handle_init_from_dirfd(
473 struct lttng_directory_handle *handle, int dirfd)
474{
475 assert(dirfd == AT_FDCWD);
476 return lttng_directory_handle_init(handle, NULL);
477}
478
479LTTNG_HIDDEN
480void lttng_directory_handle_fini(struct lttng_directory_handle *handle)
481{
482 free(handle->base_path);
46307ffe 483 lttng_directory_handle_invalidate(handle);
18710679
JG
484}
485
578e21bd
JG
486LTTNG_HIDDEN
487int lttng_directory_handle_copy(const struct lttng_directory_handle *handle,
488 struct lttng_directory_handle *new_copy)
489{
490 new_copy->base_path = strdup(handle->base_path);
491 return new_copy->base_path ? 0 : -1;
492}
493
46307ffe
JG
494static
495void lttng_directory_handle_invalidate(struct lttng_directory_handle *handle)
496{
497 handle->base_path = NULL;
498}
499
18710679
JG
500static
501int lttng_directory_handle_stat(const struct lttng_directory_handle *handle,
502 const char *subdirectory, struct stat *st)
503{
504 int ret;
505 char fullpath[LTTNG_PATH_MAX];
506
507 ret = get_full_path(handle, subdirectory, fullpath, sizeof(fullpath));
508 if (ret) {
509 errno = ENOMEM;
510 goto end;
511 }
512
513 ret = stat(fullpath, st);
514end:
515 return ret;
516}
517
518static
519int lttng_directory_handle_mkdir(const struct lttng_directory_handle *handle,
520 const char *subdirectory, mode_t mode)
521{
522 int ret;
523 char fullpath[LTTNG_PATH_MAX];
524
525 ret = get_full_path(handle, subdirectory, fullpath, sizeof(fullpath));
526 if (ret) {
527 errno = ENOMEM;
528 goto end;
529 }
530
531 ret = mkdir(fullpath, mode);
532end:
533 return ret;
534}
535
2912cead
JG
536static
537int lttng_directory_handle_open(const struct lttng_directory_handle *handle,
538 const char *filename, int flags, mode_t mode)
539{
540 int ret;
541 char fullpath[LTTNG_PATH_MAX];
542
543 ret = get_full_path(handle, filename, fullpath, sizeof(fullpath));
544 if (ret) {
545 errno = ENOMEM;
546 goto end;
547 }
548
549 ret = open(fullpath, flags, mode);
550end:
551 return ret;
552}
553
554static
555int lttng_directory_handle_unlink(
556 const struct lttng_directory_handle *handle,
557 const char *filename)
558{
559 int ret;
560 char fullpath[LTTNG_PATH_MAX];
561
562 ret = get_full_path(handle, filename, fullpath, sizeof(fullpath));
563 if (ret) {
564 errno = ENOMEM;
565 goto end;
566 }
567
568 ret = unlink(fullpath);
569end:
570 return ret;
571}
572
18710679
JG
573static
574int _run_as_mkdir(const struct lttng_directory_handle *handle, const char *path,
575 mode_t mode, uid_t uid, gid_t gid)
576{
577 int ret;
578 char fullpath[LTTNG_PATH_MAX];
579
580 ret = get_full_path(handle, path, fullpath, sizeof(fullpath));
581 if (ret) {
582 errno = ENOMEM;
583 goto end;
584 }
585
586 ret = run_as_mkdir(fullpath, mode, uid, gid);
587end:
588 return ret;
589}
590
2912cead
JG
591static
592int _run_as_open(const struct lttng_directory_handle *handle,
593 const char *filename,
594 int flags, mode_t mode, uid_t uid, gid_t gid)
595{
596 int ret;
597 char fullpath[LTTNG_PATH_MAX];
598
599 ret = get_full_path(handle, filename, fullpath, sizeof(fullpath));
600 if (ret) {
601 errno = ENOMEM;
602 goto end;
603 }
604
605 ret = run_as_open(fullpath, flags, mode, uid, gid);
606end:
607 return ret;
608}
609
610static
611int _run_as_unlink(const struct lttng_directory_handle *handle,
612 const char *filename, uid_t uid, gid_t gid)
613{
614 int ret;
615 char fullpath[LTTNG_PATH_MAX];
616
617 ret = get_full_path(handle, filename, fullpath, sizeof(fullpath));
618 if (ret) {
619 errno = ENOMEM;
620 goto end;
621 }
622
623 ret = run_as_unlink(fullpath, uid, gid);
624end:
625 return ret;
626}
627
18710679
JG
628static
629int _run_as_mkdir_recursive(const struct lttng_directory_handle *handle,
630 const char *path, mode_t mode, uid_t uid, gid_t gid)
631{
632 int ret;
633 char fullpath[LTTNG_PATH_MAX];
634
635 ret = get_full_path(handle, path, fullpath, sizeof(fullpath));
636 if (ret) {
637 errno = ENOMEM;
638 goto end;
639 }
640
641 ret = run_as_mkdir_recursive(fullpath, mode, uid, gid);
642end:
643 return ret;
644}
645
93bed9fe
JG
646static
647int _lttng_directory_handle_rename(
648 const struct lttng_directory_handle *old_handle,
649 const char *old_name,
650 const struct lttng_directory_handle *new_handle,
651 const char *new_name)
652{
653 int ret;
654 char old_fullpath[LTTNG_PATH_MAX];
655 char new_fullpath[LTTNG_PATH_MAX];
656
657 ret = get_full_path(old_handle, old_name, old_fullpath,
658 sizeof(old_fullpath));
659 if (ret) {
660 errno = ENOMEM;
661 goto end;
662 }
663 ret = get_full_path(new_handle, new_name, new_fullpath,
664 sizeof(new_fullpath));
665 if (ret) {
666 errno = ENOMEM;
667 goto end;
668 }
669
670 ret = rename(old_fullpath, new_fullpath);
671end:
672 return ret;
673}
674
675static
676int _run_as_rename(const struct lttng_directory_handle *old_handle,
677 const char *old_name,
678 const struct lttng_directory_handle *new_handle,
679 const char *new_name, uid_t uid, gid_t gid)
680{
681 int ret;
682 char old_fullpath[LTTNG_PATH_MAX];
683 char new_fullpath[LTTNG_PATH_MAX];
684
685 ret = get_full_path(old_handle, old_name, old_fullpath,
686 sizeof(old_fullpath));
687 if (ret) {
688 errno = ENOMEM;
689 goto end;
690 }
691 ret = get_full_path(new_handle, new_name, new_fullpath,
692 sizeof(new_fullpath));
693 if (ret) {
694 errno = ENOMEM;
695 goto end;
696 }
697
698 ret = run_as_rename(old_fullpath, new_fullpath, uid, gid);
699end:
700 return ret;
701}
702
703static
704DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle *handle,
705 const char *path)
706{
707 int ret;
708 DIR *dir_stream = NULL;
709 char fullpath[LTTNG_PATH_MAX];
710
711 ret = get_full_path(handle, path, fullpath, sizeof(fullpath));
712 if (ret) {
713 errno = ENOMEM;
714 goto end;
715 }
716
717 dir_stream = opendir(fullpath);
718end:
719 return dir_stream;
720}
721
722static
723int lttng_directory_handle_rmdir(
724 const struct lttng_directory_handle *handle, const char *name)
725{
726 int ret;
727 char fullpath[LTTNG_PATH_MAX];
728
729 ret = get_full_path(handle, name, fullpath, sizeof(fullpath));
730 if (ret) {
731 errno = ENOMEM;
732 goto end;
733 }
734
735 ret = rmdir(fullpath);
736end:
737 return ret;
738}
739
740static
741int _run_as_rmdir(const struct lttng_directory_handle *handle,
742 const char *name, uid_t uid, gid_t gid)
743{
744 int ret;
745 char fullpath[LTTNG_PATH_MAX];
746
747 ret = get_full_path(handle, name, fullpath, sizeof(fullpath));
748 if (ret) {
749 errno = ENOMEM;
750 goto end;
751 }
752
753 ret = run_as_rmdir(fullpath, uid, gid);
754end:
755 return ret;
756}
757
758static
759int _run_as_rmdir_recursive(
760 const struct lttng_directory_handle *handle, const char *name,
761 uid_t uid, gid_t gid)
762{
763 int ret;
764 char fullpath[LTTNG_PATH_MAX];
765
766 ret = get_full_path(handle, name, fullpath, sizeof(fullpath));
767 if (ret) {
768 errno = ENOMEM;
769 goto end;
770 }
771
772 ret = run_as_rmdir_recursive(fullpath, uid, gid);
773end:
774 return ret;
775}
776
18710679
JG
777#endif /* COMPAT_DIRFD */
778
93bed9fe
JG
779/* Common implementation. */
780
18710679
JG
781/*
782 * On some filesystems (e.g. nfs), mkdir will validate access rights before
783 * checking for the existence of the path element. This means that on a setup
784 * where "/home/" is a mounted NFS share, and running as an unpriviledged user,
785 * recursively creating a path of the form "/home/my_user/trace/" will fail with
786 * EACCES on mkdir("/home", ...).
787 *
788 * Checking the path for existence allows us to work around this behaviour.
789 */
790static
791int create_directory_check_exists(const struct lttng_directory_handle *handle,
792 const char *path, mode_t mode)
793{
794 int ret = 0;
795 struct stat st;
796
797 ret = lttng_directory_handle_stat(handle, path, &st);
798 if (ret == 0) {
799 if (S_ISDIR(st.st_mode)) {
800 /* Directory exists, skip. */
801 goto end;
802 } else {
803 /* Exists, but is not a directory. */
804 errno = ENOTDIR;
805 ret = -1;
806 goto end;
807 }
93bed9fe
JG
808 } else if (errno != ENOENT) {
809 goto end;
18710679
JG
810 }
811
812 /*
813 * Let mkdir handle other errors as the caller expects mkdir
814 * semantics.
815 */
816 ret = lttng_directory_handle_mkdir(handle, path, mode);
817end:
818 return ret;
819}
820
46307ffe
JG
821LTTNG_HIDDEN
822struct lttng_directory_handle
823lttng_directory_handle_move(struct lttng_directory_handle *original)
824{
825 const struct lttng_directory_handle tmp = *original;
826
827 lttng_directory_handle_invalidate(original);
828 return tmp;
829}
830
18710679
JG
831static
832int create_directory_recursive(const struct lttng_directory_handle *handle,
833 const char *path, mode_t mode)
834{
835 char *p, tmp[LTTNG_PATH_MAX];
836 size_t len;
837 int ret;
838
839 assert(path);
840
841 ret = lttng_strncpy(tmp, path, sizeof(tmp));
842 if (ret) {
843 ERR("Failed to create directory: provided path's length (%zu bytes) exceeds the maximal allowed length (%zu bytes)",
844 strlen(path) + 1, sizeof(tmp));
845 goto error;
846 }
847
848 len = strlen(path);
849 if (tmp[len - 1] == '/') {
850 tmp[len - 1] = 0;
851 }
852
853 for (p = tmp + 1; *p; p++) {
854 if (*p == '/') {
855 *p = 0;
856 if (tmp[strlen(tmp) - 1] == '.' &&
857 tmp[strlen(tmp) - 2] == '.' &&
858 tmp[strlen(tmp) - 3] == '/') {
859 ERR("Using '/../' is not permitted in the trace path (%s)",
860 tmp);
861 ret = -1;
862 goto error;
863 }
864 ret = create_directory_check_exists(handle, tmp, mode);
865 if (ret < 0) {
866 if (errno != EACCES) {
867 PERROR("Failed to create directory \"%s\"",
868 path);
869 ret = -errno;
870 goto error;
871 }
872 }
873 *p = '/';
874 }
875 }
876
877 ret = create_directory_check_exists(handle, tmp, mode);
878 if (ret < 0) {
879 PERROR("mkdirat recursive last element");
880 ret = -errno;
881 }
882error:
883 return ret;
884}
885
886LTTNG_HIDDEN
887int lttng_directory_handle_create_subdirectory_as_user(
888 const struct lttng_directory_handle *handle,
889 const char *subdirectory,
69e3a560 890 mode_t mode, const struct lttng_credentials *creds)
18710679
JG
891{
892 int ret;
893
894 if (!creds) {
895 /* Run as current user. */
896 ret = create_directory_check_exists(handle,
897 subdirectory, mode);
898 } else {
899 ret = _run_as_mkdir(handle, subdirectory,
900 mode, creds->uid, creds->gid);
901 }
902
903 return ret;
904}
905
906LTTNG_HIDDEN
907int lttng_directory_handle_create_subdirectory_recursive_as_user(
908 const struct lttng_directory_handle *handle,
909 const char *subdirectory_path,
69e3a560 910 mode_t mode, const struct lttng_credentials *creds)
18710679
JG
911{
912 int ret;
913
914 if (!creds) {
915 /* Run as current user. */
916 ret = create_directory_recursive(handle,
917 subdirectory_path, mode);
918 } else {
919 ret = _run_as_mkdir_recursive(handle, subdirectory_path,
920 mode, creds->uid, creds->gid);
921 }
922
923 return ret;
924}
925
926LTTNG_HIDDEN
927int lttng_directory_handle_create_subdirectory(
928 const struct lttng_directory_handle *handle,
929 const char *subdirectory,
930 mode_t mode)
931{
932 return lttng_directory_handle_create_subdirectory_as_user(
933 handle, subdirectory, mode, NULL);
934}
935
936LTTNG_HIDDEN
937int lttng_directory_handle_create_subdirectory_recursive(
938 const struct lttng_directory_handle *handle,
939 const char *subdirectory_path,
940 mode_t mode)
941{
942 return lttng_directory_handle_create_subdirectory_recursive_as_user(
943 handle, subdirectory_path, mode, NULL);
944}
2912cead
JG
945
946LTTNG_HIDDEN
947int lttng_directory_handle_open_file_as_user(
948 const struct lttng_directory_handle *handle,
949 const char *filename,
950 int flags, mode_t mode,
951 const struct lttng_credentials *creds)
952{
953 int ret;
954
955 if (!creds) {
956 /* Run as current user. */
957 ret = lttng_directory_handle_open(handle, filename, flags,
958 mode);
959 } else {
960 ret = _run_as_open(handle, filename, flags, mode,
961 creds->uid, creds->gid);
962 }
963 return ret;
964}
965
966LTTNG_HIDDEN
967int lttng_directory_handle_open_file(
968 const struct lttng_directory_handle *handle,
969 const char *filename,
970 int flags, mode_t mode)
971{
972 return lttng_directory_handle_open_file_as_user(handle, filename, flags,
973 mode, NULL);
974}
975
976LTTNG_HIDDEN
977int lttng_directory_handle_unlink_file_as_user(
978 const struct lttng_directory_handle *handle,
979 const char *filename,
980 const struct lttng_credentials *creds)
981{
982 int ret;
983
984 if (!creds) {
985 /* Run as current user. */
986 ret = lttng_directory_handle_unlink(handle, filename);
987 } else {
988 ret = _run_as_unlink(handle, filename, creds->uid, creds->gid);
989 }
990 return ret;
991}
992
993LTTNG_HIDDEN
994int lttng_directory_handle_unlink_file(
995 const struct lttng_directory_handle *handle,
996 const char *filename)
997{
998 return lttng_directory_handle_unlink_file_as_user(handle,
999 filename, NULL);
1000}
93bed9fe
JG
1001
1002LTTNG_HIDDEN
1003int lttng_directory_handle_rename(
1004 const struct lttng_directory_handle *old_handle,
1005 const char *old_name,
1006 const struct lttng_directory_handle *new_handle,
1007 const char *new_name)
1008{
1009 return lttng_directory_handle_rename_as_user(old_handle, old_name,
1010 new_handle, new_name, NULL);
1011}
1012
1013LTTNG_HIDDEN
1014int lttng_directory_handle_rename_as_user(
1015 const struct lttng_directory_handle *old_handle,
1016 const char *old_name,
1017 const struct lttng_directory_handle *new_handle,
1018 const char *new_name,
1019 const struct lttng_credentials *creds)
1020{
1021 int ret;
1022
1023 if (!creds) {
1024 /* Run as current user. */
1025 ret = _lttng_directory_handle_rename(old_handle,
1026 old_name, new_handle, new_name);
1027 } else {
1028 ret = _run_as_rename(old_handle, old_name, new_handle,
1029 new_name, creds->uid, creds->gid);
1030 }
1031 return ret;
1032}
1033
1034LTTNG_HIDDEN
1035int lttng_directory_handle_remove_subdirectory(
1036 const struct lttng_directory_handle *handle,
1037 const char *name)
1038{
1039 return lttng_directory_handle_remove_subdirectory_as_user(handle, name,
1040 NULL);
1041}
1042
1043LTTNG_HIDDEN
1044int lttng_directory_handle_remove_subdirectory_as_user(
1045 const struct lttng_directory_handle *handle,
1046 const char *name,
1047 const struct lttng_credentials *creds)
1048{
1049 int ret;
1050
1051 if (!creds) {
1052 /* Run as current user. */
1053 ret = lttng_directory_handle_rmdir(handle, name);
1054 } else {
1055 ret = _run_as_rmdir(handle, name, creds->uid, creds->gid);
1056 }
1057 return ret;
1058}
1059
1060struct rmdir_frame {
1061 DIR *dir;
1062 /* Size including '\0'. */
1063 size_t path_size;
1064};
1065
1066static
1067void rmdir_frame_fini(void *data)
1068{
1069 struct rmdir_frame *frame = data;
1070
1071 closedir(frame->dir);
1072}
1073
1074static
1075int remove_directory_recursive(const struct lttng_directory_handle *handle,
1076 const char *path)
1077{
1078 int ret;
1079 struct lttng_dynamic_array frames;
1080 size_t current_frame_idx = 0;
1081 struct rmdir_frame initial_frame = {
1082 .dir = lttng_directory_handle_opendir(handle, path),
1083 .path_size = strlen(path) + 1,
1084 };
1085 struct lttng_dynamic_buffer current_path;
1086 const char separator = '/';
1087
1088 lttng_dynamic_buffer_init(&current_path);
1089 lttng_dynamic_array_init(&frames, sizeof(struct rmdir_frame),
1090 rmdir_frame_fini);
1091
1092 ret = lttng_dynamic_array_add_element(&frames, &initial_frame);
1093 if (ret) {
1094 ERR("Failed to push context frame during recursive directory removal");
1095 rmdir_frame_fini(&initial_frame);
1096 goto end;
1097 }
1098
1099 ret = lttng_dynamic_buffer_append(&current_path, path,
1100 initial_frame.path_size);
1101 if (ret) {
1102 ERR("Failed to set initial path during recursive directory removal");
1103 ret = -1;
1104 goto end;
1105 }
1106
1107 while (lttng_dynamic_array_get_count(&frames) > 0) {
1108 struct dirent *entry;
1109 struct rmdir_frame *current_frame =
1110 lttng_dynamic_array_get_element(&frames,
1111 current_frame_idx);
1112
1113 if (!current_frame->dir) {
1114 PERROR("Failed to open directory stream during recursive directory removal");
1115 ret = -1;
1116 goto end;
1117 }
1118 ret = lttng_dynamic_buffer_set_size(&current_path,
1119 current_frame->path_size);
1120 assert(!ret);
1121 current_path.data[current_path.size - 1] = '\0';
1122
1123 while ((entry = readdir(current_frame->dir))) {
1124 struct stat st;
1125 struct rmdir_frame new_frame;
1126
1127 if (!strcmp(entry->d_name, ".")
1128 || !strcmp(entry->d_name, "..")) {
1129 continue;
1130 }
1131
1132 /* Set current_path to the entry's path. */
1133 ret = lttng_dynamic_buffer_set_size(&current_path,
1134 current_path.size - 1);
1135 assert(!ret);
1136 ret = lttng_dynamic_buffer_append(&current_path,
1137 &separator, sizeof(separator));
1138 if (ret) {
1139 goto end;
1140 }
1141 ret = lttng_dynamic_buffer_append(&current_path,
1142 entry->d_name,
1143 strlen(entry->d_name) + 1);
1144 if (ret) {
1145 goto end;
1146 }
1147
1148 if (lttng_directory_handle_stat(handle,
1149 current_path.data, &st)) {
1150 PERROR("Failed to stat \"%s\"",
1151 current_path.data);
1152 ret = -1;
1153 goto end;
1154 }
1155
1156 if (!S_ISDIR(st.st_mode)) {
1157 /* Not empty, abort. */
1158 DBG("Directory \"%s\" is not empty; refusing to remove directory",
1159 current_path.data);
1160 ret = -1;
1161 goto end;
1162 }
1163
1164 new_frame.path_size = current_path.size;
1165 new_frame.dir = lttng_directory_handle_opendir(handle,
1166 current_path.data);
1167 ret = lttng_dynamic_array_add_element(&frames,
1168 &new_frame);
1169 if (ret) {
1170 ERR("Failed to push context frame during recursive directory removal");
1171 rmdir_frame_fini(&new_frame);
1172 goto end;
1173 }
1174 current_frame_idx++;
1175 break;
1176 }
1177 if (!entry) {
1178 ret = lttng_directory_handle_rmdir(handle,
1179 current_path.data);
1180 if (ret) {
1181 PERROR("Failed to remove \"%s\" during recursive directory removal",
1182 current_path.data);
1183 goto end;
1184 }
1185 ret = lttng_dynamic_array_remove_element(&frames,
1186 current_frame_idx);
1187 if (ret) {
1188 ERR("Failed to pop context frame during recursive directory removal");
1189 goto end;
1190 }
1191 current_frame_idx--;
1192 }
1193 }
1194end:
1195 lttng_dynamic_array_reset(&frames);
1196 lttng_dynamic_buffer_reset(&current_path);
1197 return ret;
1198}
1199
1200LTTNG_HIDDEN
1201int lttng_directory_handle_remove_subdirectory_recursive(
1202 const struct lttng_directory_handle *handle,
1203 const char *name)
1204{
1205 return lttng_directory_handle_remove_subdirectory_recursive_as_user(
1206 handle, name, NULL);
1207}
1208
1209LTTNG_HIDDEN
1210int lttng_directory_handle_remove_subdirectory_recursive_as_user(
1211 const struct lttng_directory_handle *handle,
1212 const char *name,
1213 const struct lttng_credentials *creds)
1214{
1215 int ret;
1216
1217 if (!creds) {
1218 /* Run as current user. */
1219 ret = remove_directory_recursive(handle, name);
1220 } else {
1221 ret = _run_as_rmdir_recursive(handle, name, creds->uid,
1222 creds->gid);
1223 }
1224 return ret;
1225}
This page took 0.071314 seconds and 4 git commands to generate.