X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fcommon%2Futils.c;h=db2ed8e7d11dee928a6f96be4167a94669f015c6;hp=7f91dcb8151ea6ae6083668e78df123f73521758;hb=d77dded285b058e4242c8a3d2233f80e725ceefc;hpb=208ff148af91eb5ee6b2d88ada757c27be24d443 diff --git a/src/common/utils.c b/src/common/utils.c index 7f91dcb81..db2ed8e7d 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -32,9 +32,11 @@ #include #include #include +#include #include #include +#include #include "utils.h" #include "defaults.h" @@ -530,12 +532,42 @@ error: } /* - * Recursively create directory using the given path and mode. + * Create directory using the given path and mode. * * On success, return 0 else a negative error code. */ LTTNG_HIDDEN -int utils_mkdir_recursive(const char *path, mode_t mode) +int utils_mkdir(const char *path, mode_t mode, int uid, int gid) +{ + int ret; + + if (uid < 0 || gid < 0) { + ret = mkdir(path, mode); + } else { + ret = run_as_mkdir(path, mode, uid, gid); + } + if (ret < 0) { + if (errno != EEXIST) { + PERROR("mkdir %s, uid %d, gid %d", path ? path : "NULL", + uid, gid); + } else { + ret = 0; + } + } + + return ret; +} + +/* + * Internal version of mkdir_recursive. Runs as the current user. + * Don't call directly; use utils_mkdir_recursive(). + * + * This function is ominously marked as "unsafe" since it should only + * be called by a caller that has transitioned to the uid and gid under which + * the directory creation should occur. + */ +LTTNG_HIDDEN +int _utils_mkdir_recursive_unsafe(const char *path, mode_t mode) { char *p, tmp[PATH_MAX]; size_t len; @@ -580,7 +612,7 @@ int utils_mkdir_recursive(const char *path, mode_t mode) ret = mkdir(tmp, mode); if (ret < 0) { if (errno != EEXIST) { - PERROR("mkdir recursive last piece"); + PERROR("mkdir recursive last element"); ret = -errno; } else { ret = 0; @@ -591,8 +623,34 @@ error: return ret; } +/* + * Recursively create directory using the given path and mode, under the + * provided uid and gid. + * + * On success, return 0 else a negative error code. + */ +LTTNG_HIDDEN +int utils_mkdir_recursive(const char *path, mode_t mode, int uid, int gid) +{ + int ret; + + if (uid < 0 || gid < 0) { + /* Run as current user. */ + ret = _utils_mkdir_recursive_unsafe(path, mode); + } else { + ret = run_as_mkdir_recursive(path, mode, uid, gid); + } + if (ret < 0) { + PERROR("mkdir %s, uid %d, gid %d", path ? path : "NULL", + uid, gid); + } + + return ret; +} + /* * Create the stream tracefile on disk. + * path is the output parameter. It needs to be PATH_MAX len. * * Return 0 on success or else a negative value. */ @@ -885,11 +943,11 @@ char *utils_get_home_dir(void) char *val = NULL; struct passwd *pwd; - val = getenv(DEFAULT_LTTNG_HOME_ENV_VAR); + val = lttng_secure_getenv(DEFAULT_LTTNG_HOME_ENV_VAR); if (val != NULL) { goto end; } - val = getenv(DEFAULT_LTTNG_FALLBACK_HOME_ENV_VAR); + val = lttng_secure_getenv(DEFAULT_LTTNG_FALLBACK_HOME_ENV_VAR); if (val != NULL) { goto end; } @@ -954,7 +1012,7 @@ end: LTTNG_HIDDEN char *utils_get_kmod_probes_list(void) { - return getenv(DEFAULT_LTTNG_KMOD_PROBES); + return lttng_secure_getenv(DEFAULT_LTTNG_KMOD_PROBES); } /* @@ -964,7 +1022,7 @@ char *utils_get_kmod_probes_list(void) LTTNG_HIDDEN char *utils_get_extra_kmod_probes_list(void) { - return getenv(DEFAULT_LTTNG_EXTRA_KMOD_PROBES); + return lttng_secure_getenv(DEFAULT_LTTNG_EXTRA_KMOD_PROBES); } /* @@ -1048,12 +1106,77 @@ char *utils_generate_optstring(const struct option *long_options, break; } - optstring[str_pos++] = (char)long_options[i].val; - if (long_options[i].has_arg) { - optstring[str_pos++] = ':'; + if (long_options[i].val != '\0') { + optstring[str_pos++] = (char) long_options[i].val; + if (long_options[i].has_arg) { + optstring[str_pos++] = ':'; + } } } end: return optstring; } + +/* + * Try to remove a hierarchy of empty directories, recursively. Don't unlink + * any file. Try to rmdir any empty directory within the hierarchy. + */ +LTTNG_HIDDEN +int utils_recursive_rmdir(const char *path) +{ + DIR *dir; + int dir_fd, ret = 0, closeret, is_empty = 1; + struct dirent *entry; + + /* Open directory */ + dir = opendir(path); + if (!dir) { + PERROR("Cannot open '%s' path", path); + return -1; + } + dir_fd = dirfd(dir); + if (dir_fd < 0) { + PERROR("dirfd"); + return -1; + } + + while ((entry = readdir(dir))) { + if (!strcmp(entry->d_name, ".") + || !strcmp(entry->d_name, "..")) + continue; + switch (entry->d_type) { + case DT_DIR: + { + char subpath[PATH_MAX]; + + strncpy(subpath, path, PATH_MAX); + subpath[PATH_MAX - 1] = '\0'; + strncat(subpath, "/", + PATH_MAX - strlen(subpath) - 1); + strncat(subpath, entry->d_name, + PATH_MAX - strlen(subpath) - 1); + if (utils_recursive_rmdir(subpath)) { + is_empty = 0; + } + break; + } + case DT_REG: + is_empty = 0; + break; + default: + ret = -EINVAL; + goto end; + } + } +end: + closeret = closedir(dir); + if (closeret) { + PERROR("closedir"); + } + if (is_empty) { + DBG3("Attempting rmdir %s", path); + ret = rmdir(path); + } + return ret; +}