Magic symlinks redux

Brooks Davis brooks at freebsd.org
Fri Aug 22 15:06:52 UTC 2008


On Fri, Aug 22, 2008 at 04:56:16PM +0200, Luigi Rizzo wrote:
> On Fri, Aug 22, 2008 at 02:05:26PM +0200, Christian Brueffer wrote:
> > On Fri, Aug 22, 2008 at 12:24:41PM +0200, Ivan Voras wrote:
> ...
> > > This patch is huge. As far as I can tell DragonflyBSD has a whole 
> > > framework dedicated to varsyms, spread across a fair part of the kernel 
> > > and with at least one special userland utility. It allows the operator 
> > > to define his own variables that can be used in the substitutions, and I 
> > > don't see that it predefines "special" variables like "uid" and 
> > > "hostname". It's not necessarily a bad solution but I consider it overkill.
> ...
> > Brooks has a varsym port in p4, see //depot/user/brooks/varsym/
> 
> this also seems to be based on Dragonfly's code, quite intrusive.

This code adds one global symbol, one function call in the vfs code,
and two pointers to struct proc.  For that we get a system which is
significantly more flexible than the NetBSD code.

While the simplicity of the NetBSD code is somewhat attractive, the
fact that variables can not be defined renders it useless for my
purposes which are providing partial file system virtulization for
computing job/sessions where I need to key off of externally derived job
IDs or job specific temporary paths.

-- Brooks

> I am playing with a rewrite (attached below) of the original patch,
> which fixes at least one memory leak and addresses some of the
> issues that i mentioned in this thread (abuse of macros, performance,
> behaviour on errors, etc.).
> 
> (i haven't looked up yet the original copyright but i guess it
> is from netbsd...)
> 
> 	cheers
> 	luigi
> 
> Index: src/sys/kern/vfs_lookup.c
> ===================================================================
> --- src/sys/kern/vfs_lookup.c	(revision 181995)
> +++ src/sys/kern/vfs_lookup.c	(working copy)
> @@ -46,6 +46,7 @@
>  #include <sys/kernel.h>
>  #include <sys/lock.h>
>  #include <sys/mutex.h>
> +#include <sys/jail.h>	// XXX symlinks
>  #include <sys/namei.h>
>  #include <sys/vnode.h>
>  #include <sys/mount.h>
> @@ -88,6 +89,123 @@
>  }
>  SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nameiinit, NULL);
>  
> +#ifdef MAGICLINKS
> +static int vfs_magiclinks = 1;
> +#else
> +static int vfs_magiclinks = 1;
> +#endif
> +SYSCTL_INT(_vfs, OID_AUTO, magiclinks, CTLFLAG_RW, &vfs_magiclinks, 0,
> +	"Whether \"magic\" symlinks are expanded");
> +
> +/* looks up a string returns the match len or 0 */
> +static int
> +s_match(const char *key, int keylen, const char *haystack, const char *end)
> +{
> +	if (haystack + keylen >= end || haystack[keylen] != '}')
> +		return 0;
> +	if (strncmp(key, haystack, keylen))
> +		return 0;
> +	return keylen;
> +}
> +#define	MATCH(str) s_match(str, sizeof(str) - 1, src, end)
> +
> +static char *
> +s_subst(char *dst, const char *max, const char *value, int len)
> +{
> +	if (value == dst) {	/* already copied, locate end of string */
> +		while (*dst)
> +			dst++;
> +		return dst;
> +	}
> +	/* check size, copy and replace */
> +	if (dst + len > max) /* overflow */
> +		return NULL;
> +	bcopy(value, dst, len);
> +	dst += len;
> +	return dst;
> +}
> +
> +/*
> + * Substitute replacement text for 'magic' strings in symlinks.
> + * Looks for "@{string}", where <string> is a
> + * recognized 'magic' string.  Replaces the original with the
> + * appropriate replacement text.  (Note that in some cases the
> + * replacement text may have zero length.)
> + * Assume *len is at least 3.
> + */
> +static void
> +symlink_magic(struct thread *td, char *cp, int *len)
> +{
> +	char *src, *dst, *tmp, *end = cp + *len, *max;
> +	int change = 0;
> +
> +	/* quick return if nothing to replace */
> +	for (src = cp; src < end - 1; src++) {
> +		if (src[0] == '@' && src[1] == '{')
> +			break;
> +	}
> +	if (src == end - 1)	/* no replacement */
> +		return;
> +
> +	/* allocate a buffer for the replacement */
> +	dst = tmp = uma_zalloc(namei_zone, M_WAITOK);
> +	if (dst == NULL) {	/* no space for replacement */
> +		printf("zalloc fail in %s\n", __FUNCTION__);
> +		return;
> +	}
> +	max = dst + MAXPATHLEN - 1;
> +	for (src = cp; src < end - 1 && dst < max - 1;) {
> +		int l;
> +		if (src[0] != '@' || src[1] != '{') {
> +			*dst++ = *src++;	/* copy current char */
> +			continue;
> +		}
> +		src += 2;	/* skip @{ */
> +
> +printf("replace magic at %s\n", src);
> +		/*
> +		 * The following checks should be ordered according
> +		 * to frequency of use.
> +		 */
> +		if ( (l = MATCH("machine_arch")) ) {
> +			dst = s_subst(dst, max, MACHINE_ARCH, sizeof(MACHINE_ARCH) - 1);
> +		} else if ( (l= MATCH("machine")) ) {
> +			dst = s_subst(dst, max, MACHINE_ARCH, sizeof(MACHINE_ARCH) - 1);
> +		} else if ( (l= MATCH("hostname")) ) {
> +			getcredhostname(td->td_ucred, dst, max - dst);
> +			dst = s_subst(dst, max, dst, 0);
> +		} else if ( (l= MATCH("osrelease")) ) {
> +			dst = s_subst(dst, max, osrelease, strlen(osrelease));
> +		} else if ( (l= MATCH("kernel_ident")) ) {
> +			dst = s_subst(dst, max, kern_ident, strlen(kern_ident));
> +		} else if ( (l= MATCH("domainname")) ) {
> +			dst = s_subst(dst, max, domainname, strlen(domainname));
> +		} else if ( (l= MATCH("ostype")) ) {
> +			dst = s_subst(dst, max, ostype, strlen(ostype));
> +		}
> +		if (dst == NULL)	/* overflow */
> +			break;
> +		if (l == 0) { /* no match, restore original */
> +			*dst++ = '@';
> +			*dst++ = '{';
> +			continue;
> +		}
> +		/* otherwise skip original name and } */
> +		src += l + 1;
> +		change = 1;
> +	}
> +	if (change && dst) {
> +		if (src < end)	/* copy last char */
> +			*dst++ = *src;
> +		*dst = '\0';
> +		printf("translating into %s\n", tmp);
> +		*len = dst - tmp;
> +		bcopy(tmp, cp, *len);
> +	}
> +	uma_zfree(namei_zone, tmp);
> +}
> +#undef MATCH
> +
>  #ifdef LOOKUP_SHARED
>  static int lookup_shared = 1;
>  #else
> @@ -284,6 +402,8 @@
>  			error = ENOENT;
>  			break;
>  		}
> +		if (vfs_magiclinks && linklen >3) /* at least @{} in the symlink */
> +			symlink_magic(td, cp, &linklen);
>  		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
>  			if (ndp->ni_pathlen > 1)
>  				uma_zfree(namei_zone, cp);
> _______________________________________________
> freebsd-arch at freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-arch
> To unsubscribe, send any mail to "freebsd-arch-unsubscribe at freebsd.org"
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 187 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-arch/attachments/20080822/0f008445/attachment.pgp


More information about the freebsd-arch mailing list