Messages in this thread Patch in this message | | | Date | Thu, 18 Dec 1997 13:38:20 -0500 | From | Tall cool one <> | Subject | Re: Conditional SymLinks |
| |
Hello,
I have labored to produce another "proof of concept" patch. This time environment variables are symlinks in the /proc filesystem. This looks nicer, but is unfortunately actually less usefull than my previous proof of concept. Much less actually. I didn't know what the hell I was talking about in my last message on the subject. Can I claim temporary stupidity? =)
Anyway this 4-5 hour waste of time is yours to peruse. It makes a new directory in the /proc/<pid> directories called "env", where all the environment variables are symlinks to the data, so you get nice links like:
> tree /proc/12/env/ /proc/12/env |-- AUTOBOOT -> YES |-- BOOT_IMAGE -> Linux |-- CONSOLE -> /dev/console |-- HOME -> / |-- HOSTTYPE -> i386 |-- INIT_VERSION -> sysvinit-2.69 |-- OSTYPE -> Linux |-- PATH -> /sbin:/usr/sbin:/bin:/usr/bin |-- PREVLEVEL -> N |-- RUNLEVEL -> S |-- SHELL -> /bin/tcsh |-- SHLVL -> 1 |-- TERM -> linux `-- _ -> /sbin/update
Nice, but pretty useless. A /cond filesystem wouldn't work very well, unless a special case were made for sym-links entering /cond, where /cond essentually expands links much the same way my previous patch did.
You can at least do:
/tmp -> /proc/self/env/HOME/tmp
and expect it to work reasonably well, except in the cases where HOME isn't defined, points to /, etc...
I guess the only real way to do it would be the way my first proof of concept worked, but cleaned up and expanded upon I suppose. It also means that conditional sym-links haven't got a chance of getting in the kernel.
Oh, one final note. The /proc/<pid>/* directory uses 8 bits when it only really needs 4, those extra 4 bits would let you display up to 4096 file descriptors in the /proc/<pid>/fd directory instead of 256. If there is a case for 48 or 64 bit inodes, /proc is it. That and inodeless filesystems.
- Steve
.------------------------------------------------. # * # # # # # # | Steve Baker | Barely Working | # ## # # # # # | ice@mama.indstate.edu | System Administrator | # # # # # # # # | Red-Hat Rulz! | Will work for hardware | # # # ## # # # # `-- SYS-ADMIN FOR HIRE, HAVE UNIX, WILL TRAVEL --' #### # # # ## # #
diff -u -N --recursive linux-2.0.32/fs/proc/Makefile linux/fs/proc/Makefile --- linux-2.0.32/fs/proc/Makefile Thu Jan 18 00:06:17 1996 +++ linux/fs/proc/Makefile Tue Dec 16 13:31:55 1997 @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := proc.o -O_OBJS := inode.o root.o base.o mem.o link.o fd.o array.o kmsg.o net.o scsi.o +O_OBJS := inode.o root.o base.o mem.o link.o fd.o array.o kmsg.o net.o scsi.o env.o OX_OBJS := procfs_syms.o M_OBJS := $(O_TARGET) diff -u -N --recursive linux-2.0.32/fs/proc/array.c linux/fs/proc/array.c --- linux-2.0.32/fs/proc/array.c Sun Aug 3 15:59:07 1997 +++ linux/fs/proc/array.c Wed Dec 17 14:26:48 1997 @@ -332,7 +332,7 @@ return NULL; } -static unsigned long get_phys_addr(struct task_struct * p, unsigned long ptr) +unsigned long get_phys_addr(struct task_struct * p, unsigned long ptr) { pgd_t *page_dir; pmd_t *page_middle; @@ -362,7 +362,7 @@ return pte_page(pte) + (ptr & ~PAGE_MASK); } -static int get_array(struct task_struct ** p, unsigned long start, unsigned long end, char * buffer) +int get_array(struct task_struct ** p, unsigned long start, unsigned long end, char * buffer) { unsigned long addr; int size = 0, result = 0; diff -u -N --recursive linux-2.0.32/fs/proc/base.c linux/fs/proc/base.c --- linux-2.0.32/fs/proc/base.c Wed Feb 21 04:26:09 1996 +++ linux/fs/proc/base.c Tue Dec 16 13:26:37 1997 @@ -125,6 +125,12 @@ NULL, proc_pid_fill_inode, }); proc_register(&proc_pid, &(struct proc_dir_entry) { + PROC_PID_ENV, 3, "env", + S_IFDIR | S_IRUSR | S_IXUSR, 1, 0, 0, + 0, &proc_env_inode_operations, + NULL, proc_pid_fill_inode, + }); + proc_register(&proc_pid, &(struct proc_dir_entry) { PROC_PID_CMDLINE, 7, "cmdline", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_array_inode_operations, diff -u -N --recursive linux-2.0.32/fs/proc/env.c linux/fs/proc/env.c --- linux-2.0.32/fs/proc/env.c Wed Dec 31 18:00:00 1969 +++ linux/fs/proc/env.c Thu Dec 18 13:06:09 1997 @@ -0,0 +1,361 @@ +/* + * linux/fs/proc/env.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * proc env directory handling functions + */ + +#include <asm/segment.h> + +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/proc_fs.h> +#include <linux/stat.h> +#include <linux/sched.h> +#include <linux/malloc.h> + + +static int proc_readenv(struct inode *, struct file *, void *, filldir_t); +static int proc_lookupenv(struct inode *,const char *,int,struct inode **); +static int proc_env_followlink(struct inode *, struct inode *, int, int, + struct inode **); +static int proc_env_readlink(struct inode *, char *, int); + +unsigned long get_phys_addr(struct task_struct *, unsigned long); +int get_array(struct task_struct **, unsigned long, unsigned long, char *); + + +static struct file_operations proc_env_operations = { + NULL, /* lseek - default */ + NULL, /* read - bad */ + NULL, /* write - bad */ + proc_readenv, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* can't fsync */ +}; + +/* + * proc directories can do almost nothing.. + */ +struct inode_operations proc_env_inode_operations = { + &proc_env_operations, /* default base directory file-ops */ + NULL, /* create */ + proc_lookupenv, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +static struct file_operations proc_env_link_operations = { + NULL, /* lseek - default */ + NULL, /* read - bad */ + NULL, /* write - bad */ + NULL, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* can't fsync */ +}; + +struct inode_operations proc_env_link_inode_operations = { + &proc_env_link_operations, /* default base directory file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + proc_env_readlink, /* readlink */ + proc_env_followlink, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +static int proc_lookupenv(struct inode * dir, const char * name, int len, + struct inode ** result) +{ + char *env_buf, *env_end, *es, *ee; + unsigned int ino, pid, ep, envlen; + struct task_struct * p; + struct super_block * sb; + int i; + + *result = NULL; + ino = dir->i_ino; + pid = ino >> 16; + ino &= 0x0000ffff; + if (!dir) + return -ENOENT; + sb = dir->i_sb; + if (!pid || ino != PROC_PID_ENV || !S_ISDIR(dir->i_mode)) { + iput(dir); + return -ENOENT; + } + if (!len || (name[0] == '.' && (len == 1 || + (name[1] == '.' && len == 2)))) { + if (len < 2) { + *result = dir; + return 0; + } + if (!(*result = proc_get_inode(sb, (pid << 16)+PROC_PID_INO, &proc_pid))) { + iput(dir); + return -ENOENT; + } + iput(dir); + return 0; + } + iput(dir); + + for (i = 0 ; i < NR_TASKS ; i++) + if ((p = task[i]) && p->pid == pid) + break; + if (!pid || i >= NR_TASKS) + return -ENOENT; + + ep = 0; + env_buf = vmalloc((p->mm->env_end - p->mm->env_start) +1); + if (!env_buf) return -ENOENT; + envlen = get_array(&p,p->mm->env_start,p->mm->env_end,env_buf); + if (!envlen) { + vfree(env_buf); + return -ENOENT; + } + env_end = env_buf+envlen; + + for(ep=0, es=env_buf; es < env_end; ep++,es++) { + for(ee=es+1; ee < env_end && *ee != '=' && *ee; ee++); + + if (!*ee || ee >= env_end) { + vfree(env_buf); + return -ENOENT; + } + if (!strncmp(name,es,ee-es)) break; + + for(es=ee+1;es < env_end && *es; es++); + } + vfree(env_buf); + + ino = (pid << 16) + (PROC_PID_ENV_DIR << 8) + ep; + + if (!(*result = proc_get_inode(sb, ino, NULL))) + return -ENOENT; + return 0; +} + +static int proc_readenv(struct inode * inode, struct file * filp, + void * dirent, filldir_t filldir) +{ + char *env_buf, *env_end, *es, *ee; + int task_nr; + struct task_struct * p; + unsigned int envlen, ep, pid, ino, i; + + if (!inode || !S_ISDIR(inode->i_mode)) + return -EBADF; + ino = inode->i_ino; + pid = ino >> 16; + ino &= 0x0000ffff; + if (ino != PROC_PID_ENV) + return 0; + + for (ep = filp->f_pos; ep < 2; ep++, filp->f_pos++) { + unsigned long ino = inode->i_ino; + if (ep) + ino = (ino & 0xffff0000) | PROC_PID_INO; + if (filldir(dirent, "..", ep+1, ep, ino) < 0) + return 0; + } + + task_nr = 1; + for (;;) { + if ((p = task[task_nr]) && p->pid == pid) + break; + if (++task_nr >= NR_TASKS) + return 0; + } + + env_buf = vmalloc((p->mm->env_end - p->mm->env_start) +1); + if (!env_buf) return 0; + envlen = get_array(&p,p->mm->env_start,p->mm->env_end,env_buf); + if (!envlen) { + vfree(env_buf); + return 0; + } + env_end = env_buf+envlen; + + for (es=env_buf, ep -= 2, i=0; es < env_end && i < ep; i++, es++) { + while(es < env_end && es) es++; + } + if (es >= env_end) return 0; + + for (; es < env_end; ep++, filp->f_pos++, es++) { + for(ee=es+1; ee < env_end && *ee != '=' && *ee; ee++); + + if (!*ee || ee >= env_end) break; + + ino = (pid << 16) + (PROC_PID_ENV_DIR << 8) + ep; + if (filldir(dirent, es, ee-es, ep+2, ino) < 0) + break; + + /* filldir() might have slept, so we must re-validate "p" */ + if (p != task[task_nr] || p->pid != pid) + break; + + for(es=ee+1; es < env_end && *es; es++); + } + if (env_buf) vfree(env_buf); + return 0; +} + +static int proc_env_followlink(struct inode * dir, struct inode * inode, + int flag, int mode, struct inode ** res_inode) +{ + int error, task_nr; + unsigned int ino, pid, envlen; + char * link, *env_buf, *env_end, *es, *ee; + struct task_struct * p; + + *res_inode = NULL; + if (!dir) { + dir = current->fs->root; + dir->i_count++; + } + if (!inode) { + iput (dir); + return -ENOENT; + } + + ino = inode->i_ino; + pid = ino >> 16; + ino &= 0x0000ffff; + if (ino>>8 != PROC_PID_ENV_DIR) return -ENOENT; + ino &= 0x000000ff; + + if (current->link_count > 5) { + iput (dir); + iput (inode); + return -ELOOP; + } + + task_nr = 1; + for (;;) { + if ((p = task[task_nr]) && p->pid == pid) + break; + if (++task_nr >= NR_TASKS) + return -ENOENT; + } + + env_buf = vmalloc((p->mm->env_end - p->mm->env_start) +1); + if (!env_buf) return -ENOENT; + envlen = get_array(&p,p->mm->env_start,p->mm->env_end,env_buf); + if (!envlen) { + vfree(env_buf); + return -ENOENT; + } + env_end = env_buf+envlen; + + for(es=env_buf;es < env_end && ino; ino--, es++) { + while(es < env_end && *es) es++; + } + + while(es < env_end && *es != '=' && *es) es++; + + if (es >= env_end || !*es) { + vfree(env_buf); + return -ENOENT; + } + + for(ee=++es; ee<env_end && *ee; ee++); + + link = vmalloc((ee-es)+2); + strncpy(link,es,(ee-es)); + link[ee-es] = 0; + + current->link_count++; + error = open_namei (link, flag, mode, res_inode, dir); + current->link_count--; + iput (inode); + vfree(link); + vfree(env_buf); + return error; +} + +static int proc_env_readlink(struct inode * inode, char * buffer, int buflen) +{ + int len, task_nr; + unsigned int ino, pid, envlen; + char *env_buf, *env_end, *es, *ee; + struct task_struct * p; + + iput(inode); + + ino = inode->i_ino; + pid = ino >> 16; + ino &= 0x0000ffff; + if (ino>>8 != PROC_PID_ENV_DIR) return -EINVAL; + ino &= 0x000000ff; + + task_nr = 1; + for (;;) { + if ((p = task[task_nr]) && p->pid == pid) + break; + if (++task_nr >= NR_TASKS) + return -ENOENT; + } + + env_buf = vmalloc((p->mm->env_end - p->mm->env_start) +1); + if (!env_buf) return -ENOENT; + envlen = get_array(&p,p->mm->env_start,p->mm->env_end,env_buf); + if (!envlen) { + vfree(env_buf); + return -EINVAL; + } + env_end = env_buf+envlen; + + for(es=env_buf;(es < env_end) && ino; ino--, es++) + while(es < env_end && *es) es++; + + while(es < env_end && *es != '=' && *es) es++; + + if (es >= env_end || !*es) { + vfree(env_buf); + return -ENOENT; + } + + for(ee=++es; ee<env_end && *ee; ee++); + + len = (ee-es)+1; + if (buflen > len) buflen = len; + + for(;buflen && es < ee;buflen--,es++) + put_user(*es,buffer++); + + if (buflen) put_user(0,buffer); + + vfree(env_buf); + return len; +} diff -u -N --recursive linux-2.0.32/fs/proc/inode.c linux/fs/proc/inode.c --- linux-2.0.32/fs/proc/inode.c Sat Nov 1 15:31:17 1997 +++ linux/fs/proc/inode.c Thu Dec 18 11:07:38 1997 @@ -221,6 +221,11 @@ inode->i_mode = S_IFREG | S_IRUSR; inode->i_op = &proc_array_inode_operations; return; + case PROC_PID_ENV: + inode->i_mode = S_IFDIR | S_IRUSR | S_IXUSR; + inode->i_op = &proc_env_inode_operations; + inode->i_nlink = 2; + return; case PROC_PID_CMDLINE: case PROC_PID_STATUS: case PROC_PID_STAT: @@ -245,6 +250,13 @@ inode->i_mode |= S_IRUSR | S_IXUSR; if (p->files->fd[ino]->f_mode & 2) inode->i_mode |= S_IWUSR | S_IXUSR; + return; + case PROC_PID_ENV_DIR: + ino &= 0xff; + if (ino > 254) return; + inode->i_op = &proc_env_link_inode_operations; + inode->i_size = 1024; + inode->i_mode = S_IFLNK | S_IRUSR | S_IXUSR; return; } return; diff -u -N --recursive linux-2.0.32/include/linux/proc_fs.h linux/include/linux/proc_fs.h --- linux-2.0.32/include/linux/proc_fs.h Thu Nov 13 19:12:35 1997 +++ linux/include/linux/proc_fs.h Wed Dec 17 16:14:48 1997 @@ -58,11 +58,13 @@ PROC_PID_CMDLINE, PROC_PID_STAT, PROC_PID_STATM, - PROC_PID_MAPS + PROC_PID_MAPS, + PROC_PID_ENV }; enum pid_subdirectory_inos { - PROC_PID_FD_DIR = 1 + PROC_PID_FD_DIR = 1, + PROC_PID_ENV_DIR }; enum net_directory_inos { @@ -283,5 +285,6 @@ extern struct inode_operations proc_kmsg_inode_operations; extern struct inode_operations proc_link_inode_operations; extern struct inode_operations proc_fd_inode_operations; - +extern struct inode_operations proc_env_inode_operations; +extern struct inode_operations proc_env_link_inode_operations; #endif
| |