Date: Fri, 22 Aug 2008 16:56:16 +0200 From: Luigi Rizzo <rizzo@iet.unipi.it> To: Christian Brueffer <brueffer@freebsd.org> Cc: brooks@freebsd.org, Ivan Voras <ivoras@freebsd.org>, freebsd-arch@freebsd.org Subject: Re: Magic symlinks redux Message-ID: <20080822145616.GA61094@onelab2.iet.unipi.it> In-Reply-To: <20080822120525.GA1366@haakonia.hitnet.RWTH-Aachen.DE> References: <g8kv7v$sp2$1@ger.gmane.org> <20080822090448.GB57441@onelab2.iet.unipi.it> <48AE89DC.9080408@yandex.ru> <g8m458$d3$1@ger.gmane.org> <20080822120525.GA1366@haakonia.hitnet.RWTH-Aachen.DE>
next in thread | previous in thread | raw e-mail | index | archive | help
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. 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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20080822145616.GA61094>