From e308faf24f68e262d92d294a01ddca7a17e76762 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 20 Jul 1997 14:56:40 +0000 Subject: Sync with Linux 2.1.46. --- fs/proc/root.c | 149 ++++++++++++++++++++++----------------------------------- 1 file changed, 56 insertions(+), 93 deletions(-) (limited to 'fs/proc/root.c') diff --git a/fs/proc/root.c b/fs/proc/root.c index f42557d2c..2b456ca57 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -24,7 +24,7 @@ #define FIRST_PROCESS_ENTRY 256 static int proc_root_readdir(struct inode *, struct file *, void *, filldir_t); -static int proc_root_lookup(struct inode *,const char *,int,struct inode **); +static int proc_root_lookup(struct inode *,struct dentry *); static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0}; @@ -64,6 +64,7 @@ struct inode_operations proc_dir_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ + NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -104,6 +105,7 @@ static struct inode_operations proc_root_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ + NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -149,14 +151,14 @@ struct proc_dir_entry proc_sys_root = { #if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE) static int (*proc_openprom_defreaddir_ptr)(struct inode *, struct file *, void *, filldir_t); -static int (*proc_openprom_deflookup_ptr)(struct inode *, const char *, int, struct inode **); +static int (*proc_openprom_deflookup_ptr)(struct inode *, struct qstr *, struct inode **); void (*proc_openprom_use)(struct inode *, int) = 0; static struct openpromfs_dev *proc_openprom_devices = NULL; static ino_t proc_openpromdev_ino = PROC_OPENPROMD_FIRST; struct inode_operations * proc_openprom_register(int (*readdir)(struct inode *, struct file *, void *, filldir_t), - int (*lookup)(struct inode *, const char *, int, struct inode **), + int (*lookup)(struct inode *, struct qstr *, struct inode **), void (*use)(struct inode *, int), struct openpromfs_dev ***devices) { @@ -218,15 +220,13 @@ proc_openprom_defreaddir(struct inode * inode, struct file * filp, } static int -proc_openprom_deflookup(struct inode * dir,const char * name, int len, - struct inode ** result) +proc_openprom_deflookup(struct inode * dir, struct qstr *str, struct inode ** result) { request_module("openpromfs"); if (proc_openprom_inode_operations.lookup != proc_openprom_deflookup) return proc_openprom_inode_operations.lookup - (dir, name, len, result); - iput(dir); + (dir, str, result); return -ENOENT; } #endif @@ -264,6 +264,7 @@ struct inode_operations proc_openprom_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ + NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -350,7 +351,6 @@ static int proc_self_readlink(struct inode * inode, char * buffer, int buflen) int len; char tmp[30]; - iput(inode); len = sprintf(tmp, "%d", current->pid); if (buflen < len) len = buflen; @@ -358,6 +358,15 @@ static int proc_self_readlink(struct inode * inode, char * buffer, int buflen) return len; } +static struct dentry * proc_self_follow_link(struct inode *inode, struct dentry *base) +{ + int len; + char tmp[30]; + + len = sprintf(tmp, "%d", current->pid); + return lookup_dentry(tmp, base, 1); +} + static struct inode_operations proc_self_inode_operations = { NULL, /* no file-ops */ NULL, /* create */ @@ -370,6 +379,7 @@ static struct inode_operations proc_self_inode_operations = { NULL, /* mknod */ NULL, /* rename */ proc_self_readlink, /* readlink */ + proc_self_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -611,93 +621,49 @@ void proc_root_init(void) proc_tty_init(); } - -int proc_match(int len,const char * name,struct proc_dir_entry * de) -{ - if (!de || !de->low_ino) - return 0; - /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ - if (!len && (de->name[0]=='.') && (de->name[1]=='\0')) - return 1; - if (de->namelen != len) - return 0; - return !memcmp(name, de->name, len); -} - -int proc_lookup(struct inode * dir,const char * name, int len, - struct inode ** result) +/* + * Don't create negative dentries here, return -ENOENT by hand + * instead. + */ +int proc_lookup(struct inode * dir, struct dentry *dentry) { + struct inode *inode; struct proc_dir_entry * de; - int ino; - *result = NULL; - if (!dir || !S_ISDIR(dir->i_mode)) { - iput(dir); + if (!dir || !S_ISDIR(dir->i_mode)) return -ENOTDIR; - } de = (struct proc_dir_entry *) dir->u.generic_ip; - if (!de) { - iput(dir); - return -EINVAL; - } - - /* Either remove this as soon as possible due to security problems, - * or uncomment the root-only usage. - */ - - /* Allow generic inode lookups everywhere. - * No other name in /proc must begin with a '['. - */ - if(/*!current->uid &&*/ name[0] == '[') - return proc_arbitrary_lookup(dir,name,len,result); - - /* Special case "." and "..": they aren't on the directory list */ - *result = dir; - if (!len) - return 0; - if (name[0] == '.') { - if (len == 1) - return 0; - if (name[1] == '.' && len == 2) { - struct inode * inode; - inode = proc_get_inode(dir->i_sb, de->parent->low_ino, de->parent); - iput(dir); - if (!inode) - return -EINVAL; - *result = inode; - return 0; + inode = NULL; + if (de) { + for (de = de->subdir; de ; de = de->next) { + if (!de || !de->low_ino) + continue; + if (de->namelen != dentry->d_name.len) + continue; + if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { + int ino = de->low_ino | (dir->i_ino & ~(0xffff)); + inode = proc_get_inode(dir->i_sb, ino, de); + if (!inode) + return -EINVAL; + break; + } } } - - *result = NULL; - for (de = de->subdir; de ; de = de->next) { - if (proc_match(len, name, de)) - break; - } - if (!de) { - iput(dir); + if (!inode) return -ENOENT; - } - ino = de->low_ino | (dir->i_ino & ~(0xffff)); - - if (!(*result = proc_get_inode(dir->i_sb, ino, de))) { - iput(dir); - return -EINVAL; - } - iput(dir); + d_add(dentry, inode); return 0; } -static int proc_root_lookup(struct inode * dir,const char * name, int len, - struct inode ** result) +static int proc_root_lookup(struct inode * dir, struct dentry * dentry) { unsigned int pid, c; - int ino, retval; struct task_struct *p; - - atomic_inc(&dir->i_count); + const char *name; + struct inode *inode; + int len; if (dir->i_ino == PROC_ROOT_INO) { /* check for safety... */ dir->i_nlink = proc_root.nlink; @@ -710,13 +676,12 @@ static int proc_root_lookup(struct inode * dir,const char * name, int len, read_unlock(&tasklist_lock); } - retval = proc_lookup(dir, name, len, result); - if (retval != -ENOENT) { - iput(dir); - return retval; - } + if (!proc_lookup(dir, dentry)) + return 0; pid = 0; + name = dentry->d_name.name; + len = dentry->d_name.len; while (len-- > 0) { c = *name - '0'; name++; @@ -732,16 +697,14 @@ static int proc_root_lookup(struct inode * dir,const char * name, int len, } } p = find_task_by_pid(pid); - if (!pid || !p) { - iput(dir); - return -ENOENT; - } - ino = (pid << 16) + PROC_PID_INO; - if (!(*result = proc_get_inode(dir->i_sb, ino, &proc_pid))) { - iput(dir); - return -EINVAL; + inode = NULL; + if (pid && p) { + unsigned long ino = (pid << 16) + PROC_PID_INO; + inode = proc_get_inode(dir->i_sb, ino, &proc_pid); + if (!inode) + return -EINVAL; } - iput(dir); + d_add(dentry, inode); return 0; } -- cgit v1.2.3