[PATCH] lib/cmd/bup.c: Accomodate historical realpath

4 views
Skip to first unread message

Greg Troxel

unread,
Jul 12, 2022, 3:08:52 PM7/12/22
to bup-...@googlegroups.com, Greg Troxel
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

Rob Browning

unread,
Aug 13, 2022, 5:57:35 PM8/13/22
to Greg Troxel, bup-...@googlegroups.com
Greg Troxel <g...@lexort.com> writes:

> Currently the alternate is used on all OpenBSD, pending contribution
> of an appropriate preprocessor conditional.

How about something like this?

#if defined(OpenBSD) && OpenBSD < 201111

via

https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/sys/param.h.diff?r1=1.91&r2=1.92&f=h

from:

https://cvsweb.openbsd.org/src/sys/sys/param.h

Thanks
--
Rob Browning
rlb @defaultvalue.org and @debian.org
GPG as of 2011-07-10 E6A9 DA3C C9FD 1FF8 C676 D2C4 C0F0 39E9 ED1B 597A
GPG as of 2002-11-03 14DD 432F AE39 534D B592 F9A0 25C8 D377 8C7E 73A4

Rob Browning

unread,
Aug 14, 2022, 4:17:13 PM8/14/22
to Greg Troxel, bup-...@googlegroups.com
Greg Troxel <g...@lexort.com> writes:

> 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.

I've added this patch with the OpenBSD version guard here locally -- and
did you intend to add a Signed-off-by?

Greg Troxel

unread,
Aug 15, 2022, 6:52:19 AM8/15/22
to Rob Browning, bup-...@googlegroups.com

Rob Browning <r...@defaultvalue.org> writes:

> Greg Troxel <g...@lexort.com> writes:
>
>> 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.
>
> I've added this patch with the OpenBSD version guard here locally -- and
> did you intend to add a Signed-off-by?

Yes, sorry, I definitely meant Signed-off-by and keep forgetting.

The OpenBSD version guard seems fine. Certainly if anybody on OpenBSD
figures out that it should be different, that's easy to change.


signature.asc

Rob Browning

unread,
Aug 15, 2022, 11:37:35 PM8/15/22
to Greg Troxel, bup-...@googlegroups.com
Greg Troxel <g...@lexort.com> writes:

> Yes, sorry, I definitely meant Signed-off-by and keep forgetting.
>
> The OpenBSD version guard seems fine. Certainly if anybody on OpenBSD
> figures out that it should be different, that's easy to change.

Right, and thanks. I'll include this soon.

Rob Browning

unread,
Aug 20, 2022, 2:15:29 PM8/20/22
to bup-...@googlegroups.com, Greg Troxel
From: Greg Troxel <g...@lexort.com>

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.

This should fix NetBSD and OpenBSD, and realpath isn't used on
FreeBSD. This does not attempt to address Solaris.

Signed-off-by: Greg Troxel <g...@lexort.com>
Reviewed-by: Rob Browning <r...@defaultvalue.org>
[r...@defaultvalue.org: adjust commit message]
[r...@defaultvalue.org: change #define to BUP_HAVE_POSIX_REALPATH]
[r...@defaultvalue.org: add OpenBSD version guard clause]
[r...@defaultvalue.org: nest NetBSD checks so Prereq doesn't crash elsewhere]
[r...@defaultvalue.org: reformat bup_realpath a bit]
Signed-off-by: Rob Browning <r...@defaultvalue.org>
Tested-by: Rob Browning <r...@defaultvalue.org>
---

Pushed.

lib/cmd/bup.c | 46 +++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 43 insertions(+), 3 deletions(-)

diff --git a/lib/cmd/bup.c b/lib/cmd/bup.c
index 9cd1f388..0d002a91 100644
--- a/lib/cmd/bup.c
+++ b/lib/cmd/bup.c
@@ -96,6 +96,46 @@ setup_bup_main_module(void) {
die(2, "unable to register bup_main module\n");
}

+/*
+ * Older realpath implementations (e.g. 4.4BSD) required the second
+ * argument to be non-NULL, and then POSIX added the option of NULL
+ * with the semantics of malloc'ing a big-enough buffer. Define a
+ * helper function with the NULL semantics to accomodate older
+ * platforms.
+ *
+ * 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
+ */
+
+#define BUP_HAVE_POSIX_REALPATH
+
+// FreeBSD < 7: bup's FreeBSD code does not use realpath(3)
+#if defined(__NetBSD__)
+# if !__NetBSD_Prereq__(7,0,0)
+# undef BUP_HAVE_POSIX_REALPATH
+# endif
+// OpenBSD: https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/sys/param.h.diff?r1=1.91&r2=1.92&f=h
+#elif defined(__OpenBSD__) && __OpenBSD__ < 201111
+# undef BUP_HAVE_POSIX_REALPATH
+#endif
+
+char *
+bup_realpath(const char *pathname)
+{
+#ifdef BUP_HAVE_POSIX_REALPATH
+ return realpath(pathname, NULL);
+#else
+ char resolvedname[PATH_MAX];
+ char *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 +150,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 +255,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 +266,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.30.2

Reply all
Reply to author
Forward
0 new messages