From 23f80c74c38dfd726ac1b50176989b3aa14e3a81 Mon Sep 17 00:00:00 2001 From: Steve Guminski Date: Mon, 13 Feb 2017 15:24:08 -0500 Subject: [PATCH] LU-8993 utils: Use absolute pathname for debug_daemon log file The lctl debug_daemon command is changed to always provide an absolute pathname to the kernel. The kernel code will return EINVAL if the pathname does not begin with '/', leading to the confusing error "Invalid argument". This patch allows the user to provide a relative pathname to the command without generating this error. The absolute_path function has been moved to string.c and renamed to cfs_abs_path, so that it may be used by all utilities. Signed-off-by: Steve Guminski Change-Id: I35af242bfcfcb9a56135aeabe0423e28e9634bab Reviewed-on: https://review.whamcloud.com/25485 Tested-by: Jenkins Reviewed-by: John L. Hammond Reviewed-by: James Simmons Tested-by: Maloo Reviewed-by: Oleg Drokin --- libcfs/include/libcfs/util/string.h | 1 + libcfs/libcfs/util/string.c | 82 +++++++++++++++++++++++++++++++++++ lnet/utils/debug.c | 14 +++++- lustre/utils/libmount_utils_ldiskfs.c | 60 +++---------------------- 4 files changed, 101 insertions(+), 56 deletions(-) diff --git a/libcfs/include/libcfs/util/string.h b/libcfs/include/libcfs/util/string.h index 4dc7abf..bf83fb8 100644 --- a/libcfs/include/libcfs/util/string.h +++ b/libcfs/include/libcfs/util/string.h @@ -91,5 +91,6 @@ void cfs_expr_list_free(struct cfs_expr_list *expr_list); void cfs_expr_list_free_list(struct list_head *list); int cfs_ip_addr_parse(char *str, int len, struct list_head *list); int cfs_ip_addr_match(__u32 addr, struct list_head *list); +int cfs_abs_path(const char *request_path, char **resolved_path); #endif diff --git a/libcfs/libcfs/util/string.c b/libcfs/libcfs/util/string.c index 9078500..223281d 100644 --- a/libcfs/libcfs/util/string.c +++ b/libcfs/libcfs/util/string.c @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include /* @@ -480,3 +482,83 @@ cfs_expr_list_free_list(struct list_head *list) cfs_expr_list_free(el); } } + +/** + * cfs_abs_path() - Get the absolute path of a relative path + * @request_path: The relative path to be resolved + * @resolved_path: Set to the resolved absolute path + * + * Returns the canonicalized absolute pathname. This function is a wrapper to + * realpath, but will work even if the target file does not exist. All + * directories in the path must exist. + * + * Return: On success, 0 is returned and resolved_path points to an allocated + * string containing the absolute pathname. On error, errno is set + * appropriately, -errno is returned, and resolved_path points to NULL. + */ +int cfs_abs_path(const char *request_path, char **resolved_path) +{ + char buf[PATH_MAX + 1] = ""; + char *path; + char *ptr; + int len; + int rc = 0; + const char *fmt; + + path = malloc(sizeof(buf)); + if (path == NULL) + return -ENOMEM; + + if (request_path[0] != '/') { + if (getcwd(path, sizeof(buf) - 1) == NULL) { + rc = -errno; + goto out; + } + len = snprintf(buf, sizeof(buf), "%s/%s", path, request_path); + if (len >= sizeof(buf)) { + rc = -ENAMETOOLONG; + goto out; + } + } else { + /* skip duplicate leading '/' */ + len = snprintf(buf, sizeof(buf), "%s", + request_path + strspn(request_path, "/") - 1); + if (len >= sizeof(buf)) { + rc = -ENAMETOOLONG; + goto out; + } + } + + /* if filename not in root directory, call realpath for parent path */ + ptr = strrchr(buf, '/'); + if (ptr != buf) { + *ptr = '\0'; + if (path != realpath(buf, path)) { + rc = -errno; + goto out; + } + /* add the filename back */ + len = strlen(path); + fmt = (path[len - 1] == '/') ? "%s" : "/%s"; + len = snprintf(path + len, sizeof(buf) - len, fmt, ptr + 1); + if (len >= sizeof(buf) - len) { + rc = -ENAMETOOLONG; + goto out; + } + } else { + len = snprintf(path, sizeof(buf), "%s", buf); + if (len >= sizeof(buf)) { + rc = -ENAMETOOLONG; + goto out; + } + } + +out: + if (rc == 0) { + *resolved_path = path; + } else { + *resolved_path = NULL; + free(path); + } + return rc; +} diff --git a/lnet/utils/debug.c b/lnet/utils/debug.c index 8a9f0c2..a0ef7de 100644 --- a/lnet/utils/debug.c +++ b/lnet/utils/debug.c @@ -58,6 +58,7 @@ #include #include #include +#include static char rawbuf[8192]; static char *buf = rawbuf; @@ -646,6 +647,7 @@ int jt_dbg_debug_daemon(int argc, char **argv) { int rc; int fd; + char *resolved_path = NULL; if (argc <= 1) { fprintf(stderr, debug_daemon_usage, argv[0]); @@ -689,7 +691,15 @@ int jt_dbg_debug_daemon(int argc, char **argv) } } - rc = dbg_write_cmd(fd, argv[2], strlen(argv[2])); + rc = cfs_abs_path(argv[2], &resolved_path); + if (rc != 0) { + fprintf(stderr, + "%s debug_daemon: cannot resolve path '%s': %s\n", + program_invocation_short_name, argv[2], + strerror(-rc)); + goto out; + } + rc = dbg_write_cmd(fd, resolved_path, strlen(resolved_path)); if (rc != 0) { fprintf(stderr, "start debug_daemon on %s failed: %s\n", argv[2], strerror(errno)); @@ -714,6 +724,8 @@ int jt_dbg_debug_daemon(int argc, char **argv) rc = -1; out: dbg_close_ctlhandle(fd); + if (resolved_path != NULL) + free(resolved_path); return rc; } diff --git a/lustre/utils/libmount_utils_ldiskfs.c b/lustre/utils/libmount_utils_ldiskfs.c index c6ece22..ec7b556 100644 --- a/lustre/utils/libmount_utils_ldiskfs.c +++ b/lustre/utils/libmount_utils_ldiskfs.c @@ -70,6 +70,7 @@ #include #include #include +#include #ifdef HAVE_SELINUX #include @@ -120,57 +121,6 @@ static void append_context_for_mount(char *mntpt, struct mkfs_opts *mop) } #endif -/* return canonicalized absolute pathname, even if the target file does not - * exist, unlike realpath */ -static char *absolute_path(char *devname) -{ - char buf[PATH_MAX + 1] = ""; - char *path; - char *ptr; - int len; - - path = malloc(sizeof(buf)); - if (path == NULL) - return NULL; - - if (devname[0] != '/') { - if (getcwd(buf, sizeof(buf) - 1) == NULL) { - free(path); - return NULL; - } - len = snprintf(path, sizeof(buf), "%s/%s", buf, devname); - if (len >= sizeof(buf)) { - free(path); - return NULL; - } - } else { - len = snprintf(path, sizeof(buf), "%s", devname); - if (len >= sizeof(buf)) { - free(path); - return NULL; - } - } - - /* truncate filename before calling realpath */ - ptr = strrchr(path, '/'); - if (ptr == NULL) { - free(path); - return NULL; - } - *ptr = '\0'; - if (buf != realpath(path, buf)) { - free(path); - return NULL; - } - /* add the filename back */ - len = snprintf(path, PATH_MAX, "%s/%s", buf, ptr+1); - if (len >= PATH_MAX) { - free(path); - return NULL; - } - return path; -} - /* Determine if a device is a block device (as opposed to a file) */ static int is_block(char *devname) { @@ -178,10 +128,10 @@ static int is_block(char *devname) int ret = 0; char *devpath; - devpath = absolute_path(devname); - if (devpath == NULL) { - fprintf(stderr, "%s: failed to resolve path to %s\n", - progname, devname); + ret = cfs_abs_path(devname, &devpath); + if (ret != 0) { + fprintf(stderr, "%s: failed to resolve path '%s': %s\n", + progname, devname, strerror(-ret)); return -1; } -- 1.8.3.1