summaryrefslogtreecommitdiffstats
path: root/fs/nametrans.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nametrans.c')
-rw-r--r--fs/nametrans.c310
1 files changed, 310 insertions, 0 deletions
diff --git a/fs/nametrans.c b/fs/nametrans.c
new file mode 100644
index 000000000..15c98ed70
--- /dev/null
+++ b/fs/nametrans.c
@@ -0,0 +1,310 @@
+/*
+ * $Id: nametrans.c,v 1.2 1997/06/04 23:45:44 davem Exp $
+ *
+ * linux/fs/nametrans.c - context-dependend filename suffixes.
+ * Copyright (C) 1997, Thomas Schoebel-Theuer,
+ * <schoebel@informatik.uni-stuttgart.de>.
+ *
+ * translates names of the form "filename#host=myhost#" to "filename"
+ * as if both names were hardlinked to the same file.
+ * benefit: diskless clients can mount the / filesystem of the
+ * server if /etc/fstab (and other config files) are organized using
+ * context suffixes.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/utsname.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/uaccess.h>
+#include <linux/nametrans.h>
+
+char nametrans_txt[MAX_DEFAULT_TRANSLEN] = "";
+static struct translations * global_trans = NULL;
+static int default_trans = 1;
+static const char version[] = "revision: 2.3 <schoebel@informatik.uni-stuttgart.de>";
+int translations_dirty = 1;
+static char * transl_names[] = {
+#ifdef CONFIG_TR_NODENAME
+ "host=", system_utsname.nodename,
+#endif
+#ifdef CONFIG_TR_KERNNAME
+ "kname=", CONFIG_KERNNAME,
+#endif
+#ifdef CONFIG_TR_KERNTYPE
+ "ktype=", CONFIG_KERNTYPE,
+#endif
+#ifdef CONFIG_TR_MACHINE
+ "machine=", system_utsname.machine,
+#endif
+#ifdef CONFIG_TR_SYSNAME
+ "system=", system_utsname.sysname,
+#endif
+ 0, 0
+};
+
+/* Convert and do syntax checking. */
+static void convert(char * txt, struct translations * res)
+{
+ char * tmp = txt;
+ char * space = (char*)res + sizeof(struct translations);
+
+ res->count = 0;
+ while(*tmp) {
+ struct qstr * name = &res->name[res->count];
+ struct qstr * c_name = &res->c_name[res->count];
+ int len;
+ char * p = tmp;
+
+ if(*p++ != '#')
+ goto next;
+ while(*p && *p != '=' && *p != ':')
+ p++;
+ if(*p != '=')
+ goto next;
+ p++;
+ len = (unsigned long)p - (unsigned long)tmp;
+ c_name->name = space;
+ memcpy(space, tmp, len);
+ memcpy(space + len, "CREATE#", 8);
+ c_name->len = len + 7;
+ if(c_name->len >= MAX_TRANS_SUFFIX)
+ goto next;
+ while(*p && *p != '#' && *p != ':')
+ p++;
+ if(*p != '#')
+ goto next;
+ p++;
+ if(*p != ':' && *p)
+ goto next;
+ space += len + 8;
+ name->len = len = (unsigned long)p - (unsigned long)tmp;
+ if(len >= MAX_TRANS_SUFFIX)
+ goto next;
+ name->name = space;
+ memcpy(space, tmp, len);
+ space[len] = '\0';
+ space += len + 1;
+ res->count++;
+ if(res->count >= MAX_TRANSLATIONS ||
+ (unsigned long)space - (unsigned long)res >= PAGE_SIZE-2*MAX_TRANS_SUFFIX)
+ return;
+ next:
+ while(*p && *p++ != ':') ;
+ tmp = p;
+ }
+}
+
+static inline void trans_to_string(struct translations * trans, char * buf, int maxlen)
+{
+ int i;
+
+ for(i = 0; i < trans->count; i++) {
+ int len = trans->name[i].len;
+ if(len < maxlen) {
+ memcpy(buf, trans->name[i].name, len);
+ buf += len;
+ maxlen -= len;
+ *buf++ = ':';
+ maxlen--;
+ }
+ }
+ buf--;
+ *buf = '\0';
+}
+
+static inline void default_nametrans(char * buf)
+{
+ char * res = buf;
+ char ** entry;
+ char * ptr;
+
+ for (entry = transl_names; *entry; entry++) {
+ *res++ = '#';
+ for(ptr = *entry; *ptr; ptr++)
+ *res++ = *ptr;
+ entry++;
+ for(ptr = *entry; *ptr; ptr++)
+ *res++ = *ptr;
+ *res++ = '#';
+ *res++ = ':';
+ }
+ res--;
+ *res = '\0';
+}
+
+void nametrans_setup(char * line)
+{
+ if(line) {
+ default_trans = (!line[0]);
+ if(!global_trans) {
+ /* This can happen at boot time, and there is no chance
+ * to allocate memory at this early stage.
+ */
+ strncpy(nametrans_txt, line, MAX_DEFAULT_TRANSLEN);
+ } else {
+ if(default_trans) {
+ default_nametrans(nametrans_txt);
+ line = nametrans_txt;
+ }
+ convert(line, global_trans);
+
+ /* Show what really was recognized after parsing... */
+ trans_to_string(global_trans, nametrans_txt, MAX_DEFAULT_TRANSLEN);
+ }
+ }
+}
+
+/* If the _first_ environment variable is "NAMETRANS", return
+ * a pointer to the list of appendices.
+ * You can set the first environment variable using
+ * 'env - NAMETRANS=... "`env`" command ...'
+ */
+char* env_transl(void)
+{
+ char* env;
+ int i;
+
+ if(current && current->mm && (env = (char*)current->mm->env_start)
+ && get_ds() != get_fs()
+ && current->mm->env_end>=current->mm->env_start+10
+ && !verify_area(VERIFY_READ,env,10)) {
+ for(i=0; i<10; i++) {
+ char c;
+
+ get_user(c, env++);
+ if(c != "NAMETRANS="[i])
+ return 0;
+ }
+ return env;
+ }
+ return 0;
+}
+
+/* If name has the correct suffix "#keyword=correct_context#",
+ * return position of the suffix, else 0.
+ */
+char *testname(int restricted, char* name)
+{
+ char * ptr = name;
+ char * cut;
+ char * env;
+ struct translations * trans;
+ int i, len;
+ char c, tmp;
+
+ env = env_transl();
+#ifdef CONFIG_TRANS_RESTRICT
+ if(!env && restricted)
+ goto done;
+#else
+ (void)restricted; /* inhibit parameter usage warning */
+#endif
+ if(get_user(c, ptr))
+ goto done;
+ while(c && c != '#') {
+ ptr++;
+ __get_user(c, ptr);
+ }
+ if(!c)
+ goto done;
+ cut = ptr++;
+ if(get_user(c, ptr))
+ goto done;
+ while (c && c != '#') {
+ ptr++;
+ get_user(c, ptr);
+ }
+ if(!c)
+ goto done;
+ get_user(tmp, ptr);
+ if(tmp)
+ goto done;
+ trans = get_translations(env);
+ len = (unsigned long)ptr - (unsigned long)cut;
+ for(i = 0; i < trans->count; i++)
+ if(trans->name[i].len == len) {
+ const char * p1 = cut;
+ const char * p2 = trans->name[i].name;
+ get_user(c, p1);
+ while(c && c == *p2++) {
+ p1++;
+ get_user(c, p1);
+ }
+ if(!c)
+ return cut;
+ }
+done:
+ return NULL;
+}
+
+static inline void check_dirty(void)
+{
+ if(translations_dirty && default_trans) {
+ nametrans_setup("");
+ translations_dirty = 0;
+ }
+}
+
+struct translations * get_translations(char * env)
+{
+ struct translations * res;
+
+ if(env) {
+ char * env_txt = (char*)__get_free_page(GFP_KERNEL);
+
+ strncpy_from_user(env_txt, env, PAGE_SIZE);
+ res = (struct translations *)__get_free_page(GFP_KERNEL);
+ convert(env_txt, res);
+ free_page((unsigned long)env_txt);
+ } else {
+ check_dirty();
+ res = global_trans;
+ }
+ return res;
+}
+
+int nametrans_dostring(ctl_table * table, int write, struct file * filp,
+ void * buffer, size_t * lenp)
+{
+ int res;
+ check_dirty();
+ res = proc_dostring(table, write, filp, buffer, lenp);
+ if(!res && write)
+ nametrans_setup(nametrans_txt);
+
+ return res;
+}
+
+int nametrans_string(ctl_table * table, int * name, int nlen,
+ void * oldval, size_t * oldlenp,
+ void * newval, size_t newlen, void ** context)
+{
+ int res;
+ check_dirty();
+ res = sysctl_string(table, name, nlen, oldval, oldlenp, newval, newlen, context);
+ if(!res && newval && newlen)
+ nametrans_setup(nametrans_txt);
+
+ return res;
+}
+
+void init_nametrans(void)
+{
+ if(!global_trans)
+ global_trans = (struct translations*)__get_free_page(GFP_KERNEL);
+ if(!global_trans) {
+ printk("NAMETRANS: No free memory\n");
+ return;
+ }
+ nametrans_setup(nametrans_txt);
+
+ /* Notify user for the default/supplied translations.
+ * Extremely useful for finding translation problems.
+ */
+ printk("Nametrans %s\nNametrans %s: %s\n", version,
+ default_trans ? "default translations" : "external parameter",
+ nametrans_txt);
+}