Variant symlinks add the ability to embed variables in to the contents of symbolic links so their targets can change based on outside sources (user environment, uts, filesystems, etc.)
Signed-off-by: Ken Schmidt <[email protected]>
---
diff -urN linux-2.6.22.5.orig/include/linux/variant.h linux-2.6.22.5/include/linux/variant.h
--- linux-2.6.22.5.orig/include/linux/variant.h 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.22.5/include/linux/variant.h 2007-08-28 09:35:40.000000000 -0700
@@ -0,0 +1,10 @@
+#ifndef _LINUX_VARIANT_H
+#define _LINUX_VARIANT_H
+
+int variant_func_register(int ( *variant_func)(const char *, int, char *, int), int priority, char *name);
+void variant_func_unregister(int id);
+int do_variant_lookup(const char *path, char **newpath);
+
+extern int variant_links_enabled;
+
+#endif /* _LINUX_VARIANT_H */
diff -urN linux-2.6.22.5.orig/fs/Kconfig linux-2.6.22.5/fs/Kconfig
--- linux-2.6.22.5.orig/fs/Kconfig 2007-08-22 16:23:54.000000000 -0700
+++ linux-2.6.22.5/fs/Kconfig 2007-09-23 09:16:04.000000000 -0700
@@ -524,6 +524,14 @@
If unsure, say Y.
+config VARIANT
+ bool "Variant symlink support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ help
+ If you say Y here, all filesystems will have the ability to
+ dynamically redirect their symbolic link targets based on embedded
+ variables. If unsure, say N
+
config QUOTA
bool "Quota support"
help
diff -urN linux-2.6.22.5.orig/fs/Makefile linux-2.6.22.5/fs/Makefile
--- linux-2.6.22.5.orig/fs/Makefile 2007-08-22 16:23:54.000000000 -0700
+++ linux-2.6.22.5/fs/Makefile 2007-09-23 09:15:25.000000000 -0700
@@ -63,6 +63,8 @@
obj-$(CONFIG_PROFILING) += dcookies.o
obj-$(CONFIG_DLM) += dlm/
+
+obj-$(CONFIG_VARIANT) += variant/
# Do not add any filesystems before this line
obj-$(CONFIG_REISERFS_FS) += reiserfs/
diff -urN linux-2.6.22.5.orig/fs/variant/Makefile linux-2.6.22.5/fs/variant/Makefile
--- linux-2.6.22.5.orig/fs/variant/Makefile 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.22.5/fs/variant/Makefile 2007-09-23 09:17:04.000000000 -0700
@@ -0,0 +1,5 @@
+#
+# Makefile for the variant symlinks
+#
+
+obj-$(CONFIG_VARIANT) += variant.o
diff -urN linux-2.6.22.5.orig/fs/namei.c linux-2.6.22.5/fs/namei.c
--- linux-2.6.22.5.orig/fs/namei.c 2007-08-22 16:23:54.000000000 -0700
+++ linux-2.6.22.5/fs/namei.c 2007-09-23 07:15:52.000000000 -0700
@@ -31,6 +31,7 @@
#include <linux/file.h>
#include <linux/fcntl.h>
#include <linux/namei.h>
+#include <linux/variant.h>
#include <asm/namei.h>
#include <asm/uaccess.h>
@@ -539,10 +540,25 @@
static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link)
{
int res = 0;
+#ifdef CONFIG_VARIANT
+ char *newlink = NULL;
+ int err;
+#endif
char *name;
if (IS_ERR(link))
goto fail;
+#ifdef CONFIG_VARIANT
+ if (variant_links_enabled && strchr(link, '$')) {
+ err = do_variant_lookup(link, &newlink);
+ if (err) {
+ path_release(nd);
+ return err;
+ }
+ link = newlink;
+ }
+#endif
+
if (*link == '/') {
path_release(nd);
if (!walk_init_root(link, nd))
@@ -551,6 +565,11 @@
}
res = link_path_walk(link, nd);
out:
+#ifdef CONFIG_VARIANT
+ if (newlink == link)
+ kfree(newlink);
+#endif
+
if (nd->depth || res || nd->last_type!=LAST_NORM)
return res;
/*
--- linux-2.6.22.5.unpacked/fs/variant/variant.c 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.22.5/fs/variant/variant.c 2007-09-24 04:26:57.000000000 -0700
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) Pacific Northwest National Laboratory., 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * written by Kenneth P Schmidt (kenneth.schmidt <at> pnl.gov) for the
+ * Department of Energy
+ */
+
+#include<linux/kernel.h>
+#include<linux/slab.h>
+#include<linux/string.h>
+#include<linux/limits.h>
+#include<linux/rwsem.h>
+#include<linux/module.h>
+#include<linux/variant.h>
+
+struct variant_func_module {
+ int id;
+
+ char *name; /* name for possible reporting to user space (sysfs) */
+
+ /* priority lists the order for variable lookups. 0 - highest priority*/
+ int priority;
+
+ /*
+ * the callback function for each registered module.
+ * key points to the key in the original path
+ * keylen is the length of the key
+ * dest is the buffer to copy directly into
+ * destlen is the length allowed to write into the dest buffer
+ */
+ int ( *variant_lookup_func)(const char *key, int keylen, char *dest, int destlen);
+
+ struct list_head list;
+};
+
+static DECLARE_RWSEM(variant_module_rwsem);
+static LIST_HEAD(variant_func_list);
+static int variant_func_uniq;
+
+int variant_links_enabled = 1;
+
+int variant_func_register(int ( *variant_func)(const char *, int, char *, int), int priority, char *name)
+{
+ int retval;
+ int inserted = 0;
+ struct variant_func_module *new_module, *cur_module;
+ struct list_head *cur;
+
+ down_write(&variant_module_rwsem);
+ new_module = (struct variant_func_module *)kmalloc(
+ sizeof(struct variant_func_module),
+ GFP_KERNEL);
+ if (new_module) {
+ new_module->variant_lookup_func = variant_func;
+ retval = (new_module->id) = ++variant_func_uniq;
+ new_module->priority = priority;
+ new_module->name = (char *)kmalloc(strlen(name)+1, GFP_KERNEL);
+ strcpy(new_module->name, name);
+ list_for_each(cur, &variant_func_list) {
+ cur_module = list_entry(cur, struct variant_func_module, list);
+ if (cur_module->priority < priority) {
+ list_add_tail(&new_module->list, cur);
+ inserted = 1;
+ }
+ }
+ if (!inserted)
+ list_add_tail(&new_module->list, &variant_func_list);
+ } else {
+ retval = -1;
+ }
+ up_write(&variant_module_rwsem);
+ return retval;
+}
+EXPORT_SYMBOL(variant_func_register);
+
+void variant_func_unregister(int id)
+{
+ struct list_head *cur, *tmp;
+
+ down_write(&variant_module_rwsem);
+ list_for_each_safe(cur, tmp, &variant_func_list) {
+ if (list_entry(cur, struct variant_func_module, list)->id == id) {
+ list_del(cur);
+ kfree(list_entry(cur, struct variant_func_module, list));
+ }
+ }
+ up_write(&variant_module_rwsem);
+}
+EXPORT_SYMBOL(variant_func_unregister);
+
+static int variant_var_lookup(const char *key, int keylen, char *dest, int destlen)
+{
+ struct list_head *cur;
+ int modsize = 0;
+ struct variant_func_module *cur_module;
+
+ if (keylen == 0)
+ return 0;
+
+ down_read(&variant_module_rwsem);
+ list_for_each(cur, &variant_func_list) {
+ /*
+ * call each modules' lookup function
+ * until one of them returns something
+ */
+ cur_module = list_entry(cur, struct variant_func_module, list);
+ modsize = (*(cur_module)->variant_lookup_func)(key, keylen, dest, destlen);
+ if (modsize != 0)
+ break;
+ }
+ up_read(&variant_module_rwsem);
+ return modsize;
+}
+
+/*make sure to free the returned string*/
+int do_variant_lookup(const char *path, char **newpath)
+{
+ const char *beg, *end, *cur;
+ char *tmppath;
+ int varsize;
+
+ *newpath = (char *)kmalloc(PATH_MAX, GFP_KERNEL);
+ if (*newpath == NULL) {
+ return -ENOMEM;
+ }
+
+ cur = beg = path;
+ tmppath = *newpath;
+ while ((cur = strchr(cur, '$'))) {
+ if ((cur[1] == '{') && (end = strchr(cur+2, '}'))) {
+
+ /*
+ * Copy everything before the variable into our new
+ * buffer, making sure we didn't already overrun it
+ */
+ varsize = cur - beg;
+ if (varsize + (tmppath - *newpath) > PATH_MAX) {
+ kfree(*newpath);
+ return -ENAMETOOLONG;
+ }
+ strncpy(tmppath, beg, varsize);
+ tmppath += varsize;
+
+ varsize = variant_var_lookup(cur + 2, end - cur - 2, tmppath, PATH_MAX - (tmppath - *newpath));
+ /*
+ * if zero was returned, then there was no variable
+ * replacement. Leave the variable in the path
+ */
+ if (varsize == 0) {
+ varsize = end - cur + 1;
+ if (varsize + (tmppath - *newpath) > PATH_MAX) {
+ kfree(*newpath);
+ return -ENAMETOOLONG;
+ }
+ strncpy(tmppath, cur, varsize);
+ }
+ tmppath += varsize;
+
+ cur = beg = end;
+ beg++;
+ }
+ cur++;
+ }
+ /* copy in the rest of the path */
+ strncpy(tmppath, beg, PATH_MAX - (tmppath - *newpath));
+ (*newpath)[PATH_MAX - 1] = '\0';
+ return 0;
+}
+
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]