X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fcommon%2Futils.c;h=901ddb036771d77ff7ab1c2f723c98db7f895bbb;hp=2417a7d255ffb1445e12ec9e24ba2b5a29900e1d;hb=32bd4678460f5a6d724ca5f4470314bbe63c0429;hpb=d7c23421dddd4dcfbdfd329299816fa7d020eeb8 diff --git a/src/common/utils.c b/src/common/utils.c index 2417a7d25..901ddb036 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -107,7 +108,7 @@ char *utils_partial_realpath(const char *path, char *resolved_path, size_t size) } /* Try to resolve this part */ - try_path = realpath((char *)cut_path, try_path_buf); + try_path = realpath((char *) cut_path, try_path_buf); if (try_path == NULL) { free(try_path_buf); /* @@ -188,6 +189,10 @@ char *utils_partial_realpath(const char *path, char *resolved_path, size_t size) error: free(resolved_path); free(cut_path); + free(try_path); + if (try_path_prev != try_path) { + free(try_path_prev); + } return NULL; } @@ -551,6 +556,44 @@ error: return fd; } +/* + * On some filesystems (e.g. nfs), mkdir will validate access rights before + * checking for the existence of the path element. This means that on a setup + * where "/home/" is a mounted NFS share, and running as an unpriviledged user, + * recursively creating a path of the form "/home/my_user/trace/" will fail with + * EACCES on mkdir("/home", ...). + * + * Performing a stat(...) on the path to check for existence allows us to + * work around this behaviour. + */ +static +int mkdir_check_exists(const char *path, mode_t mode) +{ + int ret = 0; + struct stat st; + + ret = stat(path, &st); + if (ret == 0) { + if (S_ISDIR(st.st_mode)) { + /* Directory exists, skip. */ + goto end; + } else { + /* Exists, but is not a directory. */ + errno = ENOTDIR; + ret = -1; + goto end; + } + } + + /* + * Let mkdir handle other errors as the caller expects mkdir + * semantics. + */ + ret = mkdir(path, mode); +end: + return ret; +} + /* * Create directory using the given path and mode. * @@ -562,7 +605,7 @@ int utils_mkdir(const char *path, mode_t mode, int uid, int gid) int ret; if (uid < 0 || gid < 0) { - ret = mkdir(path, mode); + ret = mkdir_check_exists(path, mode); } else { ret = run_as_mkdir(path, mode, uid, gid); } @@ -617,9 +660,9 @@ int _utils_mkdir_recursive_unsafe(const char *path, mode_t mode) ret = -1; goto error; } - ret = mkdir(tmp, mode); + ret = mkdir_check_exists(tmp, mode); if (ret < 0) { - if (errno != EEXIST) { + if (errno != EACCES) { PERROR("mkdir recursive"); ret = -errno; goto error; @@ -629,14 +672,10 @@ int _utils_mkdir_recursive_unsafe(const char *path, mode_t mode) } } - ret = mkdir(tmp, mode); + ret = mkdir_check_exists(tmp, mode); if (ret < 0) { - if (errno != EEXIST) { - PERROR("mkdir recursive last element"); - ret = -errno; - } else { - ret = 0; - } + PERROR("mkdir recursive last element"); + ret = -errno; } error: @@ -808,7 +847,6 @@ int utils_rotate_stream_file(char *path_name, char *file_name, uint64_t size, { int ret; - assert(new_count); assert(stream_fd); ret = close(out_fd); @@ -831,18 +869,22 @@ int utils_rotate_stream_file(char *path_name, char *file_name, uint64_t size, * Unlinking the old file rather than overwriting it * achieves this. */ - *new_count = (*new_count + 1) % count; - ret = utils_unlink_stream_file(path_name, file_name, - size, *new_count, uid, gid, 0); + if (new_count) { + *new_count = (*new_count + 1) % count; + } + ret = utils_unlink_stream_file(path_name, file_name, size, + new_count ? *new_count : 0, uid, gid, 0); if (ret < 0 && errno != ENOENT) { goto error; } } else { - (*new_count)++; + if (new_count) { + (*new_count)++; + } } - ret = utils_create_stream_file(path_name, file_name, size, *new_count, - uid, gid, 0); + ret = utils_create_stream_file(path_name, file_name, size, + new_count ? *new_count : 0, uid, gid, 0); if (ret < 0) { goto error; } @@ -1231,14 +1273,15 @@ int utils_recursive_rmdir(const char *path) path_len = strlen(path); while ((entry = readdir(dir))) { - if (!strcmp(entry->d_name, ".") - || !strcmp(entry->d_name, "..")) - continue; - struct stat st; size_t name_len; char filename[PATH_MAX]; + if (!strcmp(entry->d_name, ".") + || !strcmp(entry->d_name, "..")) { + continue; + } + name_len = strlen(entry->d_name); if (path_len + name_len + 2 > sizeof(filename)) { ERR("Failed to remove file: path name too long (%s/%s)", @@ -1286,3 +1329,56 @@ end: } return ret; } + +LTTNG_HIDDEN +int utils_truncate_stream_file(int fd, off_t length) +{ + int ret; + + ret = ftruncate(fd, length); + if (ret < 0) { + PERROR("ftruncate"); + goto end; + } + ret = lseek(fd, length, SEEK_SET); + if (ret < 0) { + PERROR("lseek"); + goto end; + } +end: + return ret; +} + +static const char *get_man_bin_path(void) +{ + char *env_man_path = lttng_secure_getenv(DEFAULT_MAN_BIN_PATH_ENV); + + if (env_man_path) { + return env_man_path; + } + + return DEFAULT_MAN_BIN_PATH; +} + +LTTNG_HIDDEN +int utils_show_man_page(int section, const char *page_name) +{ + char section_string[8]; + const char *man_bin_path = get_man_bin_path(); + int ret; + + /* Section integer -> section string */ + ret = sprintf(section_string, "%d", section); + assert(ret > 0 && ret < 8); + + /* + * Execute man pager. + * + * We provide --manpath to man here because LTTng-tools can + * be installed outside /usr, in which case its man pages are + * not located in the default /usr/share/man directory. + */ + ret = execlp(man_bin_path, "man", "--manpath", MANPATH, + section_string, page_name, NULL); + return ret; +}