#include <unistd.h>
#include <inttypes.h>
#include <regex.h>
+#include <grp.h>
#include <common/common.h>
#include <common/runas.h>
#include "utils.h"
#include "defaults.h"
+/*
+ * Resolve the './' and '../' strings in the middle of a path using
+ * our very own way to do it, so that it works even if the directory
+ * does not exist
+ */
+LTTNG_HIDDEN
+char *utils_resolve_relative(const char *path)
+{
+ char *next, *previous, *slash, *start_path, *absolute_path = NULL;
+
+ /* Safety net */
+ if (path == NULL) {
+ goto error;
+ }
+
+ /* Allocate memory for the absolute path */
+ absolute_path = zmalloc(PATH_MAX);
+ if (absolute_path == NULL) {
+ PERROR("zmalloc expand path");
+ goto error;
+ }
+
+ /* Copy the path in the absolute path */
+ strncpy(absolute_path, path, PATH_MAX);
+
+ /* As long as we find '/./' in the path string */
+ while ((next = strstr(absolute_path, "/./"))) {
+
+ /* We prepare the start_path not containing it */
+ start_path = strndup(absolute_path, next - absolute_path);
+
+ /* And we concatenate it with the part after this string */
+ snprintf(absolute_path, PATH_MAX, "%s%s", start_path, next + 2);
+
+ free(start_path);
+ }
+
+ /* As long as we find '/../' in the path string */
+ while ((next = strstr(absolute_path, "/../"))) {
+ /* If the path starts with '/../', there's a problem */
+ if (next == absolute_path) {
+ ERR("%s: Path cannot be resolved", path);
+ goto error;
+ }
+
+ /* We find the last level of directory */
+ previous = absolute_path;
+ while ((slash = strpbrk(previous + 1, "/")) && slash != next) {
+ previous = slash;
+ }
+
+ /* Then we prepare the start_path not containing it */
+ start_path = strndup(absolute_path, previous - absolute_path);
+
+ /* And we concatenate it with the part after the '/../' */
+ snprintf(absolute_path, PATH_MAX, "%s%s", start_path, next + 3);
+
+ free(start_path);
+ }
+
+ return absolute_path;
+
+error:
+ free(absolute_path);
+ return NULL;
+}
+
+
/*
* Return the realpath(3) of the path even if the last directory token does not
* exist. For example, with /tmp/test1/test2, if test2/ does not exist but the
LTTNG_HIDDEN
char *utils_expand_path(const char *path)
{
- const char *end_path = path;
+ const char *end_path = NULL;
char *next, *cut_path = NULL, *expanded_path = NULL;
/* Safety net */
goto error;
}
- /* Find last token delimited by '/' */
- while ((next = strpbrk(end_path + 1, "/"))) {
- end_path = next;
- }
-
- /* Cut last token from original path */
- cut_path = strndup(path, end_path - path);
-
+ /* Allocate memory for the expanded path */
expanded_path = zmalloc(PATH_MAX);
if (expanded_path == NULL) {
PERROR("zmalloc expand path");
goto error;
}
- expanded_path = realpath((char *)cut_path, expanded_path);
- if (expanded_path == NULL) {
- switch (errno) {
- case ENOENT:
- ERR("%s: No such file or directory", cut_path);
- break;
- default:
- PERROR("realpath utils expand path");
- break;
+ /* If given path is already absolute */
+ if (*path == '/') {
+ strncpy(expanded_path, path, PATH_MAX);
+ /* Else, we have some work to do */
+ } else {
+ /* Pointer to the last char of the path */
+ const char *last_char = path + strlen(path) - 1;
+
+ end_path = path;
+
+ /* Split part that will be resolved by realpath (relative path from
+ * current directory using ./ or ../ only) and part that could not
+ * (directory names)
+ */
+ while ((next = strpbrk(end_path, "/")) && (next != last_char)) {
+ end_path = next + 1;
+ if (strncmp(end_path, "./", 2) != 0 &&
+ strncmp(end_path, "../", 3) != 0) {
+ break;
+ }
+ }
+
+ /* If this is the end of the string, and we still can resolve it */
+ if (strncmp(end_path, "..\0", 3) == 0 ||
+ strncmp(end_path, ".\0", 2) == 0) {
+ end_path += strlen(end_path);
+ }
+
+ /* If the end part is the whole path, we are in the current dir */
+ if (end_path == path) {
+ cut_path = strdup(".");
+ /* Else, cut the resolvable part from original path */
+ } else {
+ cut_path = strndup(path, end_path - path);
+ }
+
+ /* Resolve the canonical path of the first part of the path */
+ expanded_path = realpath((char *)cut_path, expanded_path);
+ if (expanded_path == NULL) {
+ switch (errno) {
+ case ENOENT:
+ ERR("%s: No such file or directory", cut_path);
+ break;
+ default:
+ PERROR("realpath utils expand path");
+ break;
+ }
+ goto error;
+ }
+
+ /* Add end part to expanded path if not empty */
+ if (*end_path != 0) {
+ strncat(expanded_path, "/", PATH_MAX - strlen(expanded_path) - 1);
+ strncat(expanded_path, end_path,
+ PATH_MAX - strlen(expanded_path) - 1);
}
- goto error;
}
- /* Add end part to expanded path */
- strncat(expanded_path, end_path, PATH_MAX - strlen(expanded_path) - 1);
+ /* Resolve the internal './' and '../' strings */
+ next = utils_resolve_relative(expanded_path);
+ if (next == NULL) {
+ goto error;
+ }
+ free(expanded_path);
free(cut_path);
- return expanded_path;
+ return next;
error:
free(expanded_path);
return ret;
}
+
+/*
+ * Return the group ID matching name, else 0 if it cannot be found.
+ */
+LTTNG_HIDDEN
+gid_t utils_get_group_id(const char *name)
+{
+ struct group *grp;
+
+ grp = getgrnam(name);
+ if (!grp) {
+ static volatile int warn_once;
+
+ if (!warn_once) {
+ WARN("No tracing group detected");
+ warn_once = 1;
+ }
+ return 0;
+ }
+ return grp->gr_gid;
+}