patch to realpath(3) to make it DTRT(IMO) with variant symlinks

Chris Pressey cpressey at catseye.mine.nu
Thu Feb 5 01:15:36 PST 2004


OK, something more substantial: I discovered that realpath(3) (and
consequently realpath(1) too) do not act as one probably would expect
when an element of the path is a variant symlink.

The attached patch is one way to correct realpath's behaviour.  It is
quite probably not the best way, but it seems to work (it's been
modestly tested.)  Other ways to address it might be:

- just don't make realpath resolve variant symlinks

I think that leaves the spirit (if not the letter) of realpath broken.
Existing scripts expect realpath(1) to return a real genuine filename.

- make readlink(2) resolve variant symlinks instead

It's not uncommon for programs to 'abuse' the symlink target, never
intending for it to point to a real file (e.g. malloc, cvsupd, the
webserver 'fnord', ...) and while I'm not aware of any that rely on a
${}-like syntax in the symlink, it seems best to give them exactly what
they're asking for: the contents of the symlink, verbatim, regardless
of what it 'means'.

- make varsymreplace a syscall

Too rich for my blood :)  Could be better for consistency though (e.g.
my patch doesn't check vfs.varsym_enable; it probably should.)

-Chris
Index: realpath.c
===================================================================
RCS file: /home/dcvs/src/lib/libc/stdlib/realpath.c,v
retrieving revision 1.2
diff -u -r1.2 realpath.c
--- realpath.c	17 Jun 2003 04:26:46 -0000	1.2
+++ realpath.c	4 Feb 2004 23:34:17 -0000
@@ -27,17 +27,20 @@
  *
  * @(#)realpath.c	8.1 (Berkeley) 2/16/94
  * $FreeBSD: src/lib/libc/stdlib/realpath.c,v 1.9.2.2 2003/06/02 13:31:16 fjoe Exp $
- * $DragonFly: src/lib/libc/stdlib/realpath.c,v 1.2 2003/06/17 04:26:46 dillon Exp $
+ * $DragonFly: src/lib/libc/stdlib/realpath.c,v 1.1 2003/06/16 04:35:25 dillon Exp $
  */
 
 #include <sys/param.h>
 #include <sys/stat.h>
+#include <sys/varsym.h>
 
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
+void replace_varsyms(char *symlink);
+
 /*
  * char *realpath(const char *path, char resolved[PATH_MAX]);
  *
@@ -159,6 +162,8 @@
 				resolved_len = q - resolved;
 			}
 
+			replace_varsyms(symlink);
+
 			/*
 			 * If there are any path components left, then
 			 * append them to symlink. The result is placed
@@ -191,3 +196,39 @@
 		resolved[resolved_len - 1] = '\0';
 	return (resolved);
 }
+
+void
+replace_varsyms(char *symlink)
+{
+	char buf[PATH_MAX], name[PATH_MAX], value[PATH_MAX];
+	char *i, *j, *t, *u;
+	int error;
+
+	i = symlink;
+	j = buf;
+	while(*i != 0 && (j - buf) < PATH_MAX) {
+		if (*i == '$' && *(i + 1) == '{') {
+			t = i + 2;
+			u = name;
+			while(*t != '}' && *t != 0) {
+				*(u++) = *(t++);
+			}
+			*u = 0;
+			error = varsym_get(VARSYM_ALL_MASK, name, value,
+			    PATH_MAX);
+			if (error >= 0 && error <= (PATH_MAX - (j - buf)) &&
+			    *t != 0) {
+				strcpy(j, value);
+				j += (error - 1);
+				i = t + 1;
+			} else {
+				*(j++) = *(i++);
+			}
+		} else {
+			*(j++) = *(i++);
+		}
+	}
+	*j = 0;
+
+	strcpy(symlink, buf);
+}




More information about the Submit mailing list