realpath(3) originally required a non-NULL 2nd argument. POSIX
extended it to allow NULL, but some old BSD versions still have the
as-first-introduced-in-4.4BSD implementation that does not accept the
2nd argument being NULL.
Define bup_realpath, which collapses to just system realpath for most
systems, and on systems known to have historic realpath, use a buffer,
and strdup the results, to match the POSIX-with-NULL semantics.
Currently the alternate is used on all OpenBSD, pending contribution
of an appropriate preprocessor conditional. It also remains to
determine versions and write a conditional for Solaris.
---
lib/cmd/bup.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 47 insertions(+), 3 deletions(-)
diff --git a/lib/cmd/bup.c b/lib/cmd/bup.c
index 9cd1f38..ded7c5b 100644
--- a/lib/cmd/bup.c
+++ b/lib/cmd/bup.c
@@ -96,6 +96,50 @@ setup_bup_main_module(void) {
die(2, "unable to register bup_main module\n");
}
+/*
+ * The code below depends on realpath(3). The historical
+ * implementation in 4.4BSD required the second argument to be
+ * non-NULL, and POSIX added the option of NULL with the semantics of
+ * malloc'ing a big-enough buffer. We define a helper function with
+ * the NULL semantics to accomodate historical implementations.
+ *
+ * gnulib has a list of systems that are known to reject NULL as the
+ * 2nd argument:
+ *
https://www.gnu.org/software/gnulib/manual/html_node/realpath.html
+ */
+/* FreeBSD < 7: bup's FreeBSD code does not use realpath(3) */
+#if defined(__NetBSD__) && !__NetBSD_Prereq__(7,0,0)
+#define OLD_REALPATH
+#endif
+#if defined(__OpenBSD__)
+/*
+ * This should only apply to versions < 5, but from reading
+ * src/param.h it is not clear how to write a preprocessor test.
+ */
+#define OLD_REALPATH
+#endif
+/* \todo Solaris 10; later versions unclear */
+
+char *
+bup_realpath(const char *pathname)
+{
+#ifndef OLD_REALPATH
+ return realpath(pathname, NULL);
+#else
+ char *ret;
+ char resolvedname[PATH_MAX];
+
+ ret = realpath(pathname, resolvedname);
+
+ if (ret != NULL)
+ {
+ assert(ret == resolvedname);
+ ret = strdup(ret);
+ }
+ return ret;
+#endif
+}
+
#if defined(__APPLE__) && defined(__MACH__)
static char *exe_parent_dir(const char * const argv_0) {
@@ -110,7 +154,7 @@ static char *exe_parent_dir(const char * const argv_0) {
}
if(rc != 0) die(2, "unable to find executable path\n");
char *path = mpath ? mpath : spath;
- char *abs_exe = realpath(path, NULL);
+ char *abs_exe = bup_realpath(path);
if (!abs_exe)
die(2, "cannot resolve path (%s): %s\n", strerror(errno), path);
char * const abs_parent = strdup(dirname(abs_exe));
@@ -215,7 +259,7 @@ static char *find_exe_parent(const char * const argv_0)
argv_0);
char *path_exe = find_in_path(argv_0, env_path);
if (path_exe) {
- char * abs_exe = realpath(path_exe, NULL);
+ char * abs_exe = bup_realpath(path_exe);
if (!abs_exe)
die(2, "cannot resolve path (%s): %s\n",
strerror(errno), path_exe);
@@ -226,7 +270,7 @@ static char *find_exe_parent(const char * const argv_0)
if (!candidate)
return NULL;
- char * const abs_exe = realpath(candidate, NULL);
+ char * const abs_exe = bup_realpath(candidate);
if (!abs_exe)
die(2, "cannot resolve path (%s): %s\n", strerror(errno), candidate);
free(candidate);
--
2.36.1