Import 2.1.55pre1
[davej-history.git] / fs / proc / fd.c
blob4baa299fc7abd2882e2feb578f60de84c2c5f1f9
1 /*
2 * linux/fs/proc/fd.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
6 * proc fd directory handling functions
7 */
9 #include <asm/uaccess.h>
11 #include <linux/errno.h>
12 #include <linux/sched.h>
13 #include <linux/proc_fs.h>
14 #include <linux/stat.h>
16 static int proc_readfd(struct file *, void *, filldir_t);
17 static int proc_lookupfd(struct inode *, struct dentry *);
19 static struct file_operations proc_fd_operations = {
20 NULL, /* lseek - default */
21 NULL, /* read - bad */
22 NULL, /* write - bad */
23 proc_readfd, /* readdir */
24 NULL, /* poll - default */
25 NULL, /* ioctl - default */
26 NULL, /* mmap */
27 NULL, /* no special open code */
28 NULL, /* no special release code */
29 NULL /* can't fsync */
33 * proc directories can do almost nothing..
35 struct inode_operations proc_fd_inode_operations = {
36 &proc_fd_operations, /* default base directory file-ops */
37 NULL, /* create */
38 proc_lookupfd, /* lookup */
39 NULL, /* link */
40 NULL, /* unlink */
41 NULL, /* symlink */
42 NULL, /* mkdir */
43 NULL, /* rmdir */
44 NULL, /* mknod */
45 NULL, /* rename */
46 NULL, /* readlink */
47 NULL, /* follow_link */
48 NULL, /* readpage */
49 NULL, /* writepage */
50 NULL, /* bmap */
51 NULL, /* truncate */
52 NULL /* permission */
56 * NOTE! Normally we'd indicate that a file does not
57 * exist by creating a negative dentry and returning
58 * a successful return code. However, for this case
59 * we do not want to create negative dentries, because
60 * the state of the world can change behind our backs.
62 * Thus just return -ENOENT instead.
64 static int proc_lookupfd(struct inode * dir, struct dentry * dentry)
66 unsigned int ino, pid, fd, c;
67 struct task_struct * p;
68 struct super_block * sb;
69 struct inode *inode;
70 const char *name;
71 int len;
73 ino = dir->i_ino;
74 pid = ino >> 16;
75 ino &= 0x0000ffff;
76 if (!dir)
77 return -ENOENT;
78 sb = dir->i_sb;
79 if (!pid || ino != PROC_PID_FD || !S_ISDIR(dir->i_mode))
80 return -ENOENT;
82 fd = 0;
83 len = dentry->d_name.len;
84 name = dentry->d_name.name;
85 while (len-- > 0) {
86 c = *name - '0';
87 name++;
88 if (c > 9) {
89 fd = 0xfffff;
90 break;
92 fd *= 10;
93 fd += c;
94 if (fd & 0xffff0000) {
95 fd = 0xfffff;
96 break;
99 p = find_task_by_pid(pid);
100 if (!pid || !p)
101 return -ENOENT;
104 * File handle is invalid if it is out of range, if the process
105 * has no files (Zombie) if the file is closed, or if its inode
106 * is NULL
109 if (fd >= NR_OPEN ||
110 !p->files ||
111 !p->files->fd[fd] ||
112 !p->files->fd[fd]->f_dentry)
113 return -ENOENT;
115 ino = (pid << 16) + (PROC_PID_FD_DIR << 8) + fd;
117 inode = proc_get_inode(sb, ino, NULL);
118 if (!inode)
119 return -ENOENT;
121 d_add(dentry, inode);
122 return 0;
125 #define NUMBUF 10
127 static int proc_readfd(struct file * filp,
128 void * dirent, filldir_t filldir)
130 char buf[NUMBUF];
131 struct task_struct * p, **tarrayp;
132 unsigned int fd, pid, ino;
133 unsigned long i,j;
134 struct inode *inode = filp->f_dentry->d_inode;
136 if (!inode || !S_ISDIR(inode->i_mode))
137 return -EBADF;
138 ino = inode->i_ino;
139 pid = ino >> 16;
140 ino &= 0x0000ffff;
141 if (ino != PROC_PID_FD)
142 return 0;
144 for (fd = filp->f_pos; fd < 2; fd++, filp->f_pos++) {
145 unsigned long ino = inode->i_ino;
146 if (fd)
147 ino = (ino & 0xffff0000) | PROC_PID_INO;
148 if (filldir(dirent, "..", fd+1, fd, ino) < 0)
149 return 0;
152 p = find_task_by_pid(pid);
153 if(!p)
154 return 0;
155 tarrayp = p->tarray_ptr;
157 for (fd -= 2 ; fd < NR_OPEN; fd++, filp->f_pos++) {
158 if (!p->files)
159 break;
160 if (!p->files->fd[fd] || !p->files->fd[fd]->f_dentry)
161 continue;
163 j = NUMBUF;
164 i = fd;
165 do {
166 j--;
167 buf[j] = '0' + (i % 10);
168 i /= 10;
169 } while (i);
171 ino = (pid << 16) + (PROC_PID_FD_DIR << 8) + fd;
172 if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino) < 0)
173 break;
175 /* filldir() might have slept, so we must re-validate "p" */
176 if (p != *tarrayp || p->pid != pid)
177 break;
179 return 0;