@@ -105,7 +105,7 @@ AC_CHECK_DECLS([sys_siglist], [], [], [[#include <signal.h>]])
AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec, struct stat.st_mtimensec],
[], [], [[#include <sys/stat.h>]])
AC_CHECK_MEMBERS([struct ifreq.ifr_flagshigh], [], [], [[#include <net/if.h>]])
-AC_CHECK_FUNCS([mlockall strnlen getloadavg statvfs getmntent_r])
+AC_CHECK_FUNCS([mlockall strnlen getloadavg statvfs getmntent_r realpath])
AC_CHECK_HEADERS([mntent.h sys/statvfs.h linux/types.h linux/if_ether.h stdatomic.h])
AC_CHECK_HEADERS([net/if_mib.h], [], [], [[#include <sys/types.h>
#include <net/if.h>]])
@@ -2098,6 +2098,58 @@ is_stdout_a_tty(void)
return (isatty(STDOUT_FILENO) && t && strcmp(t, "dumb") != 0);
}
+/* Derives, from the pathname pointed to by path, an absolute pathname that
+ * names the same file, whose resolution does not involve '.', '..' or
+ * symbolic links. If path is null or does not exist, returns NULL.
+ */
+char *
+ovs_realpath(const char *path)
+{
+ if (!path) {
+ return NULL;
+ }
+ char *realpath_res = NULL;
+
+#ifdef HAVE_REALPATH
+ realpath_res = realpath(path, NULL);
+ if (realpath_res == NULL) {
+ goto error;
+ }
+ struct stat s;
+ int err = stat(realpath_res, &s);
+ if (err) {
+ goto error;
+ }
+ return realpath_res;
+#elif defined(_WIN32)
+ realpath_res = xstrdup(path);
+ DWORD ret = GetFullPathName(path, strlen(realpath_res), realpath_res,
+ NULL);
+ if (ret == 0) {
+ goto error;
+ } else if (ret > strlen(realpath_res)) {
+ DWORD new_ret;
+ char *new_path = (char *)xrealloc(realpath_res, ret);
+ if (new_path == NULL) {
+ goto error;
+ }
+ realpath_res = new_path;
+ new_ret = GetFullPathName(path, strlen(realpath_res), realpath_res,
+ NULL);
+ if (new_ret == 0 || new_ret != ret ) {
+ goto error;
+ }
+ }
+ return realpath_res;
+#else
+#error Need realpath() on this platform
+#endif
+
+error:
+ free(realpath_res);
+ return NULL;
+}
+
#ifdef _WIN32
char *
@@ -220,6 +220,7 @@ char *dir_name(const char *file_name);
char *base_name(const char *file_name);
#endif
char *abs_file_name(const char *dir, const char *file_name);
+char *ovs_realpath(const char *path);
char *follow_symlinks(const char *filename);
@@ -234,3 +234,8 @@ AT_CLEANUP
AT_SETUP([test rcu])
AT_CHECK([ovstest test-rcu-quiesce], [0], [])
AT_CLEANUP
+
+AT_SETUP([test ovs_realpath])
+AT_CHECK([ovstest test-util realpath \
+/tmp/../tmp/../usr/bin/.//../share:/usr/share /tmpNOEXISTS:], [0], [])
+AT_CLEANUP
@@ -1128,6 +1128,28 @@ test_snprintf(struct ovs_cmdl_context *ctx OVS_UNUSED)
ovs_assert(snprintf(NULL, 0, "abcde") == 5);
}
+static void
+test_ovs_realpath(struct ovs_cmdl_context *ctx)
+{
+ int i;
+ for (i = 1; i < ctx->argc; i++) {
+ char *str_toks = NULL;
+ char *path = strtok_r(ctx->argv[i], ":", &str_toks);
+ ovs_assert(path != NULL);
+
+ char *check = strtok_r(NULL, ":", &str_toks);
+ char *rpath = ovs_realpath(path);
+
+ if (check) {
+ ovs_assert(rpath != NULL);
+ ovs_assert(!strcmp(check, rpath));
+ free(rpath);
+ } else {
+ ovs_assert(rpath == NULL);
+ }
+ }
+}
+
#ifndef _WIN32
static void
test_file_name(struct ovs_cmdl_context *ctx)
@@ -1164,6 +1186,7 @@ static const struct ovs_cmdl_command commands[] = {
{"assert", NULL, 0, 0, test_assert},
{"ovs_scan", NULL, 0, 0, test_ovs_scan},
{"snprintf", NULL, 0, 0, test_snprintf},
+ {"realpath", NULL, 1, INT_MAX, test_ovs_realpath},
#ifndef _WIN32
{"file_name", NULL, 1, INT_MAX, test_file_name},
#endif
This commit adds a new function (ovs_realpath) to perform the role of realpath on various operating systems. The purpose is to ensure that a given path to file exists, and to return a completely resolved path (sans '.' and '..'). Signed-off-by: Aaron Conole <aconole@redhat.com> --- v11: * Added configure.ac | 2 +- lib/util.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/util.h | 1 + tests/library.at | 5 +++++ tests/test-util.c | 23 +++++++++++++++++++++++ 5 files changed, 82 insertions(+), 1 deletion(-)