58217f5900
WOO HOO!
198 lines
4 KiB
C
198 lines
4 KiB
C
/*
|
|
* linux/fs/proc/fd.c
|
|
*
|
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
|
*
|
|
* proc fd directory handling functions
|
|
*/
|
|
|
|
#include <asm/segment.h>
|
|
|
|
#include <linux/errno.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/stat.h>
|
|
|
|
static int proc_readfd(struct inode *, struct file *, struct dirent *, int);
|
|
static int proc_lookupfd(struct inode *,const char *,int,struct inode **);
|
|
|
|
static struct file_operations proc_fd_operations = {
|
|
NULL, /* lseek - default */
|
|
NULL, /* read - bad */
|
|
NULL, /* write - bad */
|
|
proc_readfd, /* 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_fd_inode_operations = {
|
|
&proc_fd_operations, /* default base directory file-ops */
|
|
NULL, /* create */
|
|
proc_lookupfd, /* lookup */
|
|
NULL, /* link */
|
|
NULL, /* unlink */
|
|
NULL, /* symlink */
|
|
NULL, /* mkdir */
|
|
NULL, /* rmdir */
|
|
NULL, /* mknod */
|
|
NULL, /* rename */
|
|
NULL, /* readlink */
|
|
NULL, /* follow_link */
|
|
NULL, /* bmap */
|
|
NULL, /* truncate */
|
|
NULL /* permission */
|
|
};
|
|
|
|
static int proc_lookupfd(struct inode * dir,const char * name, int len,
|
|
struct inode ** result)
|
|
{
|
|
unsigned int ino, pid, fd, c;
|
|
struct task_struct * p;
|
|
struct super_block * sb;
|
|
int i;
|
|
|
|
*result = NULL;
|
|
ino = dir->i_ino;
|
|
pid = ino >> 16;
|
|
ino &= 0x0000ffff;
|
|
ino -= 7;
|
|
if (!dir)
|
|
return -ENOENT;
|
|
sb = dir->i_sb;
|
|
if (!pid || ino > 1 || !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 = iget(sb,(pid << 16)+2))) {
|
|
iput(dir);
|
|
return -ENOENT;
|
|
}
|
|
iput(dir);
|
|
return 0;
|
|
}
|
|
iput(dir);
|
|
fd = 0;
|
|
while (len-- > 0) {
|
|
c = *name - '0';
|
|
name++;
|
|
if (c > 9) {
|
|
fd = 0xfffff;
|
|
break;
|
|
}
|
|
fd *= 10;
|
|
fd += c;
|
|
if (fd & 0xffff0000) {
|
|
fd = 0xfffff;
|
|
break;
|
|
}
|
|
}
|
|
for (i = 0 ; i < NR_TASKS ; i++)
|
|
if ((p = task[i]) && p->pid == pid)
|
|
break;
|
|
if (!pid || i >= NR_TASKS)
|
|
return -ENOENT;
|
|
if (!ino) {
|
|
if (fd >= NR_OPEN || !p->filp[fd] || !p->filp[fd]->f_inode)
|
|
return -ENOENT;
|
|
ino = (pid << 16) + 0x100 + fd;
|
|
} else {
|
|
int j = 0;
|
|
struct vm_area_struct * mpnt;
|
|
for (mpnt = p->mmap; mpnt; mpnt = mpnt->vm_next)
|
|
if (mpnt->vm_inode)
|
|
j++;
|
|
if (fd >= j)
|
|
return -ENOENT;
|
|
ino = (pid << 16) + 0x200 + fd;
|
|
}
|
|
if (!(*result = iget(sb,ino)))
|
|
return -ENOENT;
|
|
return 0;
|
|
}
|
|
|
|
static int proc_readfd(struct inode * inode, struct file * filp,
|
|
struct dirent * dirent, int count)
|
|
{
|
|
struct task_struct * p;
|
|
unsigned int fd, pid, ino;
|
|
int i,j;
|
|
|
|
if (!inode || !S_ISDIR(inode->i_mode))
|
|
return -EBADF;
|
|
ino = inode->i_ino;
|
|
pid = ino >> 16;
|
|
ino &= 0x0000ffff;
|
|
ino -= 7;
|
|
if (ino > 1)
|
|
return 0;
|
|
while (1) {
|
|
fd = filp->f_pos;
|
|
filp->f_pos++;
|
|
if (fd < 2) {
|
|
i = j = fd+1;
|
|
if (!fd)
|
|
fd = inode->i_ino;
|
|
else
|
|
fd = (inode->i_ino & 0xffff0000) | 2;
|
|
put_fs_long(fd, &dirent->d_ino);
|
|
put_fs_word(i, &dirent->d_reclen);
|
|
put_fs_byte(0, i+dirent->d_name);
|
|
while (i--)
|
|
put_fs_byte('.', i+dirent->d_name);
|
|
return j;
|
|
}
|
|
fd -= 2;
|
|
for (i = 1 ; i < NR_TASKS ; i++)
|
|
if ((p = task[i]) && p->pid == pid)
|
|
break;
|
|
if (i >= NR_TASKS)
|
|
return 0;
|
|
if (!ino) {
|
|
if (fd >= NR_OPEN)
|
|
break;
|
|
if (!p->filp[fd] || !p->filp[fd]->f_inode)
|
|
continue;
|
|
} else {
|
|
int j = 0;
|
|
struct vm_area_struct * mpnt;
|
|
for (mpnt = p->mmap ; mpnt ; mpnt = mpnt->vm_next)
|
|
if (mpnt->vm_inode)
|
|
j++;
|
|
if (fd >= j)
|
|
break;
|
|
}
|
|
j = 10;
|
|
i = 1;
|
|
while (fd >= j) {
|
|
j *= 10;
|
|
i++;
|
|
}
|
|
j = i;
|
|
if (!ino)
|
|
ino = (pid << 16) + 0x100 + fd;
|
|
else
|
|
ino = (pid << 16) + 0x200 + fd;
|
|
put_fs_long(ino, &dirent->d_ino);
|
|
put_fs_word(i, &dirent->d_reclen);
|
|
put_fs_byte(0, i+dirent->d_name);
|
|
while (i--) {
|
|
put_fs_byte('0'+(fd % 10), i+dirent->d_name);
|
|
fd /= 10;
|
|
}
|
|
return j;
|
|
}
|
|
return 0;
|
|
}
|