patch-1.3.19 linux/fs/proc/root.c
Next file: linux/fs/proc/scsi.c
Previous file: linux/fs/proc/net.c
Back to the patch index
Back to the overall index
- Lines: 496
- Date:
Tue Aug 15 14:55:47 1995
- Orig file:
v1.3.18/linux/fs/proc/root.c
- Orig date:
Sun Aug 13 14:45:34 1995
diff -u --recursive --new-file v1.3.18/linux/fs/proc/root.c linux/fs/proc/root.c
@@ -14,14 +14,19 @@
#include <linux/stat.h>
#include <linux/config.h>
-static int proc_readroot(struct inode *, struct file *, void *, filldir_t);
-static int proc_lookuproot(struct inode *,const char *,int,struct inode **);
+/*
+ * Offset of the first process in the /proc root directory..
+ */
+#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 struct file_operations proc_root_operations = {
NULL, /* lseek - default */
NULL, /* read - bad */
NULL, /* write - bad */
- proc_readroot, /* readdir */
+ proc_root_readdir, /* readdir */
NULL, /* select - default */
NULL, /* ioctl - default */
NULL, /* mmap */
@@ -33,10 +38,10 @@
/*
* proc directories can do almost nothing..
*/
-struct inode_operations proc_root_inode_operations = {
+static struct inode_operations proc_root_inode_operations = {
&proc_root_operations, /* default base directory file-ops */
NULL, /* create */
- proc_lookuproot, /* lookup */
+ proc_root_lookup, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
@@ -51,125 +56,368 @@
NULL /* permission */
};
-static struct proc_dir_entry root_dir[] = {
- { PROC_ROOT_INO, 1, "." },
- { PROC_ROOT_INO, 2, ".." },
- { PROC_LOADAVG, 7, "loadavg" },
- { PROC_UPTIME, 6, "uptime" },
- { PROC_MEMINFO, 7, "meminfo" },
- { PROC_KMSG, 4, "kmsg" },
- { PROC_VERSION, 7, "version" },
+/*
+ * This is the root "inode" in the /proc tree..
+ */
+struct proc_dir_entry proc_root = {
+ PROC_ROOT_INO, 5, "/proc",
+ S_IFDIR | S_IRUGO | S_IXUGO, 3, 0, 0,
+ 0, &proc_root_inode_operations,
+ NULL, NULL,
+ NULL,
+ &proc_root, NULL
+};
+
+int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
+{
+ dp->next = dir->subdir;
+ dp->parent = dir;
+ dir->subdir = dp;
+ if (S_ISDIR(dp->mode))
+ dir->nlink++;
+ return 0;
+}
+
+int proc_unregister(struct proc_dir_entry * dir, int ino)
+{
+ struct proc_dir_entry **p = &dir->subdir, *dp;
+
+ while ((dp = *p) != NULL) {
+ if (dp->low_ino == ino) {
+ *p = dp->next;
+ dp->next = NULL;
+ if (S_ISDIR(dp->mode))
+ dir->nlink--;
+ return 0;
+ }
+ p = &dp->next;
+ }
+ return -EINVAL;
+}
+
+/*
+ * /proc/self:
+ */
+static int proc_self_followlink(struct inode * dir, struct inode * inode,
+ int flag, int mode, struct inode ** res_inode)
+{
+ iput(dir);
+ *res_inode = proc_get_inode(inode->i_sb, (current->pid << 16) + PROC_PID_INO, &proc_pid);
+ iput(inode);
+ if (!*res_inode)
+ return -ENOENT;
+ return 0;
+}
+
+static int proc_self_readlink(struct inode * inode, char * buffer, int buflen)
+{
+ int len;
+ char tmp[30];
+
+ iput(inode);
+ len = 1 + sprintf(tmp, "%d", current->pid);
+ if (buflen < len)
+ len = buflen;
+ memcpy_tofs(buffer, tmp, len);
+ return len;
+}
+
+static struct inode_operations proc_self_inode_operations = {
+ NULL, /* no file-ops */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ proc_self_readlink, /* readlink */
+ proc_self_followlink, /* follow_link */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL /* permission */
+};
+
+void proc_root_init(void)
+{
+ static int done = 0;
+
+ if (done)
+ return;
+ done = 1;
+ proc_base_init();
+ proc_register(&proc_root, &(struct proc_dir_entry) {
+ PROC_LOADAVG, 7, "loadavg",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ });
+ proc_register(&proc_root, &(struct proc_dir_entry) {
+ PROC_UPTIME, 6, "uptime",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ });
+ proc_register(&proc_root, &(struct proc_dir_entry) {
+ PROC_MEMINFO, 7, "meminfo",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ });
+ proc_register(&proc_root, &(struct proc_dir_entry) {
+ PROC_KMSG, 4, "kmsg",
+ S_IFREG | S_IRUSR, 1, 0, 0,
+ });
+ proc_register(&proc_root, &(struct proc_dir_entry) {
+ PROC_VERSION, 7, "version",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ });
#ifdef CONFIG_PCI
- { PROC_PCI, 3, "pci" },
+ proc_register(&proc_root, &(struct proc_dir_entry) {
+ PROC_PCI, 3, "pci",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ });
#endif
- { PROC_CPUINFO, 7, "cpuinfo" },
- { PROC_SELF, 4, "self" }, /* will change inode # */
- { PROC_NET, 3, "net" },
- { PROC_SCSI, 4, "scsi" },
+ proc_register(&proc_root, &(struct proc_dir_entry) {
+ PROC_CPUINFO, 7, "cpuinfo",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ });
+ proc_register(&proc_root, &(struct proc_dir_entry) {
+ PROC_SELF, 4, "self",
+ S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, 1, 0, 0,
+ 64, &proc_self_inode_operations,
+ });
+ proc_register(&proc_root, &proc_net);
+ proc_register(&proc_root, &proc_scsi);
#ifdef CONFIG_DEBUG_MALLOC
- { PROC_MALLOC, 6, "malloc" },
+ proc_register(&proc_root, &(struct proc_dir_entry) {
+ PROC_MALLOC, 6, "malloc",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ });
#endif
- { PROC_KCORE, 5, "kcore" },
- { PROC_MODULES, 7, "modules" },
- { PROC_STAT, 4, "stat" },
- { PROC_DEVICES, 7, "devices" },
- { PROC_INTERRUPTS, 10,"interrupts" },
- { PROC_FILESYSTEMS, 11,"filesystems" },
- { PROC_KSYMS, 5, "ksyms" },
- { PROC_DMA, 3, "dma" },
- { PROC_IOPORTS, 7, "ioports" },
+ proc_register(&proc_root, &(struct proc_dir_entry) {
+ PROC_KCORE, 5, "kcore",
+ S_IFREG | S_IRUSR, 1, 0, 0,
+ });
+ proc_register(&proc_root, &(struct proc_dir_entry) {
+ PROC_MODULES, 7, "modules",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ });
+ proc_register(&proc_root, &(struct proc_dir_entry) {
+ PROC_STAT, 4, "stat",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ });
+ proc_register(&proc_root, &(struct proc_dir_entry) {
+ PROC_DEVICES, 7, "devices",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ });
+ proc_register(&proc_root, &(struct proc_dir_entry) {
+ PROC_INTERRUPTS, 10,"interrupts",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ });
+ proc_register(&proc_root, &(struct proc_dir_entry) {
+ PROC_FILESYSTEMS, 11,"filesystems",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ });
+ proc_register(&proc_root, &(struct proc_dir_entry) {
+ PROC_KSYMS, 5, "ksyms",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ });
+ proc_register(&proc_root, &(struct proc_dir_entry) {
+ PROC_DMA, 3, "dma",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ });
+ proc_register(&proc_root, &(struct proc_dir_entry) {
+ PROC_IOPORTS, 7, "ioports",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ });
#ifdef CONFIG_PROFILE
- { PROC_PROFILE, 7, "profile" },
+ proc_register(&proc_root, &(struct proc_dir_entry) {
+ PROC_PROFILE, 7, "profile",
+ S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
+ });
#endif
-};
+}
+
-#define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0])))
+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);
+}
-static int proc_lookuproot(struct inode * dir,const char * name, int len,
+int proc_lookup(struct inode * dir,const char * name, int len,
struct inode ** result)
{
- struct proc_dir_entry * de = NULL;
- unsigned int pid, c;
- int i, ino;
+ struct proc_dir_entry * de;
+ int ino;
*result = NULL;
- if (!dir)
- return -ENOENT;
- if (!S_ISDIR(dir->i_mode)) {
+ if (!dir || !S_ISDIR(dir->i_mode)) {
iput(dir);
- return -ENOENT;
- }
- for (i = 0; i < NR_ROOT_DIRENTRY; i++) {
- if (!proc_match(len,name,root_dir+i))
- continue;
- de = root_dir + i;
- break;
+ return -ENOTDIR;
}
- if (de) {
- ino = de->low_ino;
- if (ino == PROC_ROOT_INO) {
- *result = dir;
+
+ de = (struct proc_dir_entry *) dir->u.generic_ip;
+ if (!de)
+ return -EINVAL;
+
+ /* 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;
}
- if (ino == PROC_SELF) /* self modifying inode ... */
- ino = (current->pid << 16) + 2;
- } else {
- pid = 0;
- while (len-- > 0) {
- c = *name - '0';
- name++;
- if (c > 9) {
- pid = 0;
- break;
- }
- pid *= 10;
- pid += c;
- if (pid & 0xffff0000) {
- pid = 0;
- break;
- }
+ }
+
+ *result = NULL;
+ for (de = de->subdir; de ; de = de->next) {
+ if (proc_match(len, name, de))
+ break;
+ }
+ if (!de)
+ 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);
+ return 0;
+}
+
+static int proc_root_lookup(struct inode * dir,const char * name, int len,
+ struct inode ** result)
+{
+ unsigned int pid, c;
+ int i, ino;
+
+ int retval = proc_lookup(dir, name, len, result);
+ if (retval != -ENOENT)
+ return retval;
+
+ pid = 0;
+ while (len-- > 0) {
+ c = *name - '0';
+ name++;
+ if (c > 9) {
+ pid = 0;
+ break;
}
- for (i = 0 ; i < NR_TASKS ; i++)
- if (task[i] && task[i]->pid == pid)
- break;
- if (!pid || i >= NR_TASKS) {
- iput(dir);
- return -ENOENT;
+ pid *= 10;
+ pid += c;
+ if (pid & 0xffff0000) {
+ pid = 0;
+ break;
}
- ino = (pid << 16) + 2;
}
- if (!(*result = iget(dir->i_sb,ino))) {
+ for (i = 0 ; i < NR_TASKS ; i++)
+ if (task[i] && task[i]->pid == pid)
+ break;
+ if (!pid || i >= NR_TASKS) {
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;
+ }
iput(dir);
- (*result)->u.generic_ip = de;
return 0;
}
+/*
+ * This returns non-zero if at EOF, so that the /proc
+ * root directory can use this and check if it should
+ * continue with the <pid> entries..
+ *
+ * Note that the VFS-layer doesn't care about the return
+ * value of the readdir() call, as long as it's non-negative
+ * for success..
+ */
+int proc_readdir(struct inode * inode, struct file * filp,
+ void * dirent, filldir_t filldir)
+{
+ struct proc_dir_entry * de;
+ unsigned int ino;
+ int i;
+
+ if (!inode || !S_ISDIR(inode->i_mode))
+ return -ENOTDIR;
+ ino = inode->i_ino;
+ de = (struct proc_dir_entry *) inode->u.generic_ip;
+ if (!de)
+ return -EINVAL;
+ i = filp->f_pos;
+ switch (i) {
+ case 0:
+ if (filldir(dirent, ".", 1, i, ino) < 0)
+ return 0;
+ i++;
+ filp->f_pos++;
+ /* fall through */
+ case 1:
+ if (filldir(dirent, "..", 2, i, de->parent->low_ino) < 0)
+ return 0;
+ i++;
+ filp->f_pos++;
+ /* fall through */
+ default:
+ ino &= ~0xffff;
+ de = de->subdir;
+ i -= 2;
+ for (;;) {
+ if (!de)
+ return 1;
+ if (!i)
+ break;
+ de = de->next;
+ i--;
+ }
+
+ do {
+ if (filldir(dirent, de->name, de->namelen, filp->f_pos, ino | de->low_ino) < 0)
+ return 0;
+ filp->f_pos++;
+ de = de->next;
+ } while (de);
+ }
+ return 1;
+}
+
#define NUMBUF 10
-static int proc_readroot(struct inode * inode, struct file * filp,
+static int proc_root_readdir(struct inode * inode, struct file * filp,
void * dirent, filldir_t filldir)
{
char buf[NUMBUF];
unsigned int nr,pid;
unsigned long i,j;
- if (!inode || !S_ISDIR(inode->i_mode))
- return -EBADF;
-
nr = filp->f_pos;
- while (nr < NR_ROOT_DIRENTRY) {
- struct proc_dir_entry * de = root_dir + nr;
-
- if (filldir(dirent, de->name, de->namelen, nr, de->low_ino) < 0)
- return 0;
- filp->f_pos++;
- nr++;
+ if (nr < FIRST_PROCESS_ENTRY) {
+ int error = proc_readdir(inode, filp, dirent, filldir);
+ if (error <= 0)
+ return error;
+ filp->f_pos = nr = FIRST_PROCESS_ENTRY;
}
- for (nr -= NR_ROOT_DIRENTRY; nr < NR_TASKS; nr++, filp->f_pos++) {
+ for (nr -= FIRST_PROCESS_ENTRY; nr < NR_TASKS; nr++, filp->f_pos++) {
struct task_struct * p = task[nr];
if (!p || !(pid = p->pid))
@@ -183,7 +431,7 @@
i /= 10;
} while (i);
- if (filldir(dirent, buf+j, NUMBUF-j, nr+NR_ROOT_DIRENTRY, (pid << 16)+2) < 0)
+ if (filldir(dirent, buf+j, NUMBUF-j, filp->f_pos, (pid << 16) + PROC_PID_INO) < 0)
break;
}
return 0;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this