From owner-freebsd-arch@FreeBSD.ORG Fri Aug 22 14:53:42 2008 Return-Path: Delivered-To: freebsd-arch@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 95D8D1065672; Fri, 22 Aug 2008 14:53:42 +0000 (UTC) (envelope-from luigi@onelab2.iet.unipi.it) Received: from onelab2.iet.unipi.it (onelab2.iet.unipi.it [131.114.9.129]) by mx1.freebsd.org (Postfix) with ESMTP id 38CC98FC1E; Fri, 22 Aug 2008 14:53:41 +0000 (UTC) (envelope-from luigi@onelab2.iet.unipi.it) Received: by onelab2.iet.unipi.it (Postfix, from userid 275) id 5072673098; Fri, 22 Aug 2008 16:56:16 +0200 (CEST) Date: Fri, 22 Aug 2008 16:56:16 +0200 From: Luigi Rizzo To: Christian Brueffer Message-ID: <20080822145616.GA61094@onelab2.iet.unipi.it> References: <20080822090448.GB57441@onelab2.iet.unipi.it> <48AE89DC.9080408@yandex.ru> <20080822120525.GA1366@haakonia.hitnet.RWTH-Aachen.DE> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20080822120525.GA1366@haakonia.hitnet.RWTH-Aachen.DE> User-Agent: Mutt/1.4.2.3i Cc: brooks@freebsd.org, Ivan Voras , freebsd-arch@freebsd.org Subject: Re: Magic symlinks redux X-BeenThere: freebsd-arch@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Discussion related to FreeBSD architecture List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 22 Aug 2008 14:53:42 -0000 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 #include #include +#include // XXX symlinks #include #include #include @@ -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 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);