[patch 01/02] vfs: variant symlinks

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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]
  Powered by Linux