summaryrefslogtreecommitdiffstats
path: root/fs/proc/root.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/proc/root.c')
-rw-r--r--fs/proc/root.c149
1 files changed, 56 insertions, 93 deletions
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;
}