X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fcommon%2Futils.c;h=6e772671451aec4e90e9943dd4c78eddd087c083;hp=ca4eb44481c7d3e7fc90500c91112f50aaacef09;hb=a98e236e95719aa9c777a8cb1569a66daf0d576f;hpb=7a946bebe4a23b07f257906b90c88fed383835aa diff --git a/src/common/utils.c b/src/common/utils.c index ca4eb4448..6e7726714 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -17,7 +17,6 @@ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#define _GNU_SOURCE #define _LGPL_SOURCE #include #include @@ -31,12 +30,14 @@ #include #include #include -#include +#include #include #include #include #include +#include +#include #include "utils.h" #include "defaults.h" @@ -82,6 +83,8 @@ char *utils_partial_realpath(const char *path, char *resolved_path, size_t size) /* Resolve the canonical path of the first part of the path */ while (try_path != NULL && next != end) { + char *try_path_buf = NULL; + /* * If there is not any '/' left, we want to try with * the full path @@ -98,9 +101,16 @@ char *utils_partial_realpath(const char *path, char *resolved_path, size_t size) goto error; } + try_path_buf = zmalloc(LTTNG_PATH_MAX); + if (!try_path_buf) { + PERROR("zmalloc"); + goto error; + } + /* Try to resolve this part */ - try_path = realpath((char *)cut_path, NULL); + try_path = realpath((char *) cut_path, try_path_buf); if (try_path == NULL) { + free(try_path_buf); /* * There was an error, we just want to be assured it * is linked to an unexistent directory, if it's another @@ -117,6 +127,7 @@ char *utils_partial_realpath(const char *path, char *resolved_path, size_t size) } } else { /* Save the place we are before trying the next step */ + try_path_buf = NULL; free(try_path_prev); try_path_prev = try_path; prev = next; @@ -480,7 +491,7 @@ int utils_create_pid_file(pid_t pid, const char *filepath) goto error; } - ret = fprintf(fp, "%d\n", pid); + ret = fprintf(fp, "%d\n", (int) pid); if (ret < 0) { PERROR("fprintf pid file"); goto error; @@ -489,7 +500,7 @@ int utils_create_pid_file(pid_t pid, const char *filepath) if (fclose(fp)) { PERROR("fclose"); } - DBG("Pid %d written in file %s", pid, filepath); + DBG("Pid %d written in file %s", (int) pid, filepath); ret = 0; error: return ret; @@ -504,11 +515,13 @@ int utils_create_lock_file(const char *filepath) { int ret; int fd; + struct flock lock; assert(filepath); - fd = open(filepath, O_CREAT, - O_WRONLY | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + memset(&lock, 0, sizeof(lock)); + fd = open(filepath, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | + S_IRGRP | S_IWGRP); if (fd < 0) { PERROR("open lock file %s", filepath); ret = -1; @@ -520,8 +533,12 @@ int utils_create_lock_file(const char *filepath) * already a process using the same lock file running * and we should exit. */ - ret = flock(fd, LOCK_EX | LOCK_NB); - if (ret) { + lock.l_whence = SEEK_SET; + lock.l_type = F_WRLCK; + + ret = fcntl(fd, F_SETLK, &lock); + if (ret == -1) { + PERROR("fcntl lock file"); ERR("Could not get lock file %s, another instance is running.", filepath); if (close(fd)) { @@ -535,6 +552,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. * @@ -546,7 +601,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); } @@ -601,9 +656,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; @@ -613,14 +668,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: @@ -1207,22 +1258,23 @@ int utils_recursive_rmdir(const char *path) PERROR("Cannot open '%s' path", path); return -1; } - dir_fd = dirfd(dir); + dir_fd = lttng_dirfd(dir); if (dir_fd < 0) { - PERROR("dirfd"); + PERROR("lttng_dirfd"); return -1; } 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)",