From owner-freebsd-arch@FreeBSD.ORG Wed Mar 18 23:40:04 2009 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 14DDC106566B; Wed, 18 Mar 2009 23:40:04 +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 8748A8FC12; Wed, 18 Mar 2009 23:40:02 +0000 (UTC) (envelope-from luigi@onelab2.iet.unipi.it) Received: by onelab2.iet.unipi.it (Postfix, from userid 275) id A805C730A1; Thu, 19 Mar 2009 00:44:47 +0100 (CET) Date: Thu, 19 Mar 2009 00:44:47 +0100 From: Luigi Rizzo To: Ivan Voras Message-ID: <20090318234447.GA21963@onelab2.iet.unipi.it> References: <49C17BB3.1010702@freebsd.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="fdj2RfSjLxBAspz7" Content-Disposition: inline In-Reply-To: <49C17BB3.1010702@freebsd.org> User-Agent: Mutt/1.4.2.3i Cc: 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: Wed, 18 Mar 2009 23:40:04 -0000 --fdj2RfSjLxBAspz7 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Wed, Mar 18, 2009 at 11:54:43PM +0100, Ivan Voras wrote: > Hi, > > I started doing something that would be nicely solved by magic symlinks > so I remembered this thread. It started some 6+ months ago here: > > http://lists.freebsd.org/pipermail/freebsd-arch/2008-August/008473.html > > Is there any new development? at the time i did some quick tests on probably the same code as you reference below, and it is really trivial (attached). I do remember a discussion of a more complete implementation but was many times more complex and more intrusive and I am afraid that such a thing will never happen. BTW today i hit a problem where some form of magic symlinks would be useful. Say you are preparing a disk image in a subtree of your filesystem, and your image contains symlinks with absolute paths: to do things right, you should navigate the subtree in a chroot'ed environment, but chroot() requires root privs. If we had some form of magic symlinks that support a per-process remapping, one could e.g. set a variable that is prepended to the target of absolute symlinks, and achieve the same effect of a chroot without the need for root privs... cheers luigi > Ivan Voras wrote: > > I was reading about new things in NetBSD, and one thing caught my > > attention: per-user /tmp. See > > http://www.feyrer.de/NetBSD/bx/blosxom.cgi/nb_20080714_0251.html for > > example. > > > > Google says that a discussion about magic symlinks happens every now and > > then in FreeBSD but nothing really gets done. I found this > > implementation which looks like it's for 7.0: > > > > http://butcher.heavennet.ru/patches/kernel/magiclinks/ > > > > As far as I understand the VFS (which isn't much...) this looks like an > > trivial patch, and it's compatible with NetBSD. Since I'm interested in > > this (specifically for the per-user /tmp and maybe similar gadgetry), > > I'd like to nurse this patch into the tree, if there are no objections > > (of course, I'll bug anyone I can find who knows VFS to review it :) ). > > --fdj2RfSjLxBAspz7 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="20090211-symlinks.diff" Index: sys/kern/vfs_lookup.c =================================================================== --- sys/kern/vfs_lookup.c (revision 189113) +++ sys/kern/vfs_lookup.c (working copy) @@ -45,6 +45,7 @@ #include #include #include +#include // XXX symlinks #include #include #include @@ -87,6 +88,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 + static int lookup_shared = 0; SYSCTL_INT(_vfs, OID_AUTO, lookup_shared, CTLFLAG_RW, &lookup_shared, 0, "Enables/Disables shared locks for path name translation"); @@ -280,6 +398,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); --fdj2RfSjLxBAspz7--