commit c2f7c5ad8ef0f9c94a2a8382c109c8c6e16c8b18
Author: Peter Seebach <peter.seebach@windriver.com>
Date:   Thu Jun 9 10:53:32 2011 -0500

    Fix realpath(name, NULL) when PSEUDO_DISABLED=1
    
    On some Linux systems, dlsym("realpath", RTLD_NEXT) prefers
    for reasons of its own to give a symbol that is also known
    as old_realpath, which fails and yields EINVAL when called
    with a null pointer as the second argument.  This can be
    avoided, on some systems, by using dlvsym() to request
    the GLIBC_2.3 version of the symbol.
    
    The wrapper logic is enhanced to allow for specifying
    versions, although this currently only works for Linux
    (Darwin has no dlvsym, apparently?).  The test case is
    a trivial program which calls realpath(name, NULL) run
    with PSEUDO_DISABLED=1.

diff --git a/ChangeLog.txt b/ChangeLog.txt
index 7ffb74a..a2bbb61 100644
--- a/ChangeLog.txt
+++ b/ChangeLog.txt
@@ -1,3 +1,8 @@
+2011-06-08:
+	* (seebs) Get the modern realpath from glibc instead of the old
+	  one inexplicably proferred by RTLD_NEXT.  Fixes realpath(path, NULL)
+	  when PSEUDO_DISABLED=1.
+
 2011-06-06:
 	* (seebs) revise system() handler substantially.  It now
 	  pollutes the environment but works.
diff --git a/makewrappers b/makewrappers
index 6dcf889..20bbf2b 100755
--- a/makewrappers
+++ b/makewrappers
@@ -211,6 +211,7 @@ class Function:
         self.flags = '0'
         self.port = port
         self.directory = ''
+	self.version = 'NULL'
         # On Darwin, some functions are SECRETLY converted to foo$INODE64
         # when called.  So we have to look those up for real_*
         self.inode64 = None
diff --git a/ports/unix/wrapfuncs.in b/ports/unix/wrapfuncs.in
index 74bad89..e06e404 100644
--- a/ports/unix/wrapfuncs.in
+++ b/ports/unix/wrapfuncs.in
@@ -18,7 +18,7 @@ int lutimes(const char *path, const struct timeval *tv);
 char *mkdtemp(char *template);
 char *mktemp(char *template);
 long pathconf(const char *path, int name);
-char *realpath(const char *name, char *resolved_name);
+char *realpath(const char *name, char *resolved_name); /* version="GLIBC_2.3" */
 int remove(const char *path); /* flags=AT_SYMLINK_NOFOLLOW */
 DIR *opendir(const char *path);
 char *tempnam(const char *template, const char *pfx);
diff --git a/pseudo_wrappers.c b/pseudo_wrappers.c
index 600a918..07a4429 100644
--- a/pseudo_wrappers.c
+++ b/pseudo_wrappers.c
@@ -90,6 +90,42 @@ pseudo_reinit_libpseudo(void) {
 	_libpseudo_init();
 }
 
+static void
+pseudo_init_one_wrapper(pseudo_function *func) {
+	int (*f)(void) = (int (*)(void)) NULL;
+	char *e;
+	if (*func->real != NULL) {
+		/* already initialized */
+		return;
+	}
+	dlerror();
+
+#if PSEUDO_PORT_LINUX
+	if (func->version)
+		f = dlvsym(RTLD_NEXT, func->name, func->version);
+	/* fall through to the general case, if that failed */
+	if (!f)
+#endif
+	f = dlsym(RTLD_NEXT, func->name);
+	if (f) {
+		*func->real = f;
+	} else {
+		e = dlerror();
+#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
+		char *s = func->name;
+		s += strlen(s) - 2;
+		/* *at() don't have to exist */
+		if (!strcmp(s, "at")) {
+			continue;
+		}
+#else
+		if (e != NULL) {
+			pseudo_diag("No real function for %s: %s\n", func->name, e);
+		}
+#endif
+	}
+}
+
 void
 pseudo_init_wrappers(void) {
 	int i;
@@ -103,29 +139,7 @@ pseudo_init_wrappers(void) {
 	 */
 	if (!done) {
 		for (i = 0; pseudo_functions[i].name; ++i) {
-			if (*pseudo_functions[i].real == NULL) {
-				int (*f)(void);
-				char *e;
-				dlerror();
-				f = dlsym(RTLD_NEXT, pseudo_functions[i].name);
-				if (f) {
-					*pseudo_functions[i].real = f;
-				} else {
-					e = dlerror();
-#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
-					char *s = pseudo_functions[i].name;
-					s += strlen(s) - 2;
-					/* *at() don't have to exist */
-					if (!strcmp(s, "at")) {
-						continue;
-					}
-#else
-					if (e != NULL) {
-						pseudo_diag("No real function for %s: %s\n", pseudo_functions[i].name, e);
-					}
-#endif
-				}
-			}
+			pseudo_init_one_wrapper(&pseudo_functions[i]);
 		}
 		done = 1;
 	}
diff --git a/templates/wrapper_table b/templates/wrapper_table
index 2e79fcd..bb30530 100644
--- a/templates/wrapper_table
+++ b/templates/wrapper_table
@@ -4,17 +4,21 @@
 
 /* This file is generated and should not be modified.  See the makewrappers
  * script if you want to modify this. */
-static struct {
+typedef struct {
 	char *name;		/* the name */
 	int (**real)(void);	/* the underlying syscall */
 	int (*wrapper)(void);	/* the wrapper from guts/name.c */
-} pseudo_functions[] = {
+	char *version;		/* the version, if we know and care */
+} pseudo_function;
+
+static pseudo_function pseudo_functions[] = {
 @body
 	{ /* ${comment}; */
 		"${name}${maybe_inode64}",
 		(int (**)(void)) &real_${name},
-		(int (*)(void)) wrap_${name}
+		(int (*)(void)) wrap_${name},
+		${version}
 	},
 @footer
-	{ NULL, NULL, NULL },
+	{ NULL, NULL, NULL, NULL },
 };
