root.c

来自「elinux jffs初始版本 具体了解JFFS的文件系统!」· C语言 代码 · 共 585 行

C
585
字号
/* *  linux/fs/proc/root.c * *  Copyright (C) 1991, 1992 Linus Torvalds * *  proc root directory handling functions */#include <asm/segment.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/proc_fs.h>#include <linux/stat.h>#include <linux/config.h>#include <asm/bitops.h>/* * Offset of the first process in the /proc root directory.. */#define FIRST_PROCESS_ENTRY 256static int proc_root_readdir(struct inode *, struct file *, void *, filldir_t);static int proc_root_lookup(struct inode *,const char *,int,struct inode **);static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0};/* * These are the generic /proc directory operations. They * use the in-memory "struct proc_dir_entry" tree to parse * the /proc directory. * * NOTE! The /proc/scsi directory currently does not correctly * build up the proc_dir_entry tree, and will show up empty. */static struct file_operations proc_dir_operations = {	NULL,			/* lseek - default */	NULL,			/* read - bad */	NULL,			/* write - bad */	proc_readdir,		/* 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_dir_inode_operations = {	&proc_dir_operations,	/* default net directory file-ops */	NULL,			/* create */	proc_lookup,		/* lookup */	NULL,			/* link */	NULL,			/* unlink */	NULL,			/* symlink */	NULL,			/* mkdir */	NULL,			/* rmdir */	NULL,			/* mknod */	NULL,			/* rename */	NULL,			/* readlink */	NULL,			/* follow_link */	NULL,			/* readpage */	NULL,			/* writepage */	NULL,			/* bmap */	NULL,			/* truncate */	NULL			/* permission */};/* * The root /proc directory is special, as it has the * <pid> directories. Thus we don't use the generic * directory handling functions for that.. */static struct file_operations proc_root_operations = {	NULL,			/* lseek - default */	NULL,			/* read - bad */	NULL,			/* write - bad */	proc_root_readdir,	/* readdir */	NULL,			/* select - default */	NULL,			/* ioctl - default */	NULL,			/* mmap */	NULL,			/* no special open code */	NULL,			/* no special release code */	NULL			/* no fsync */};/* * proc root can do almost nothing.. */static struct inode_operations proc_root_inode_operations = {	&proc_root_operations,	/* default base directory file-ops */	NULL,			/* create */	proc_root_lookup,	/* lookup */	NULL,			/* link */	NULL,			/* unlink */	NULL,			/* symlink */	NULL,			/* mkdir */	NULL,			/* rmdir */	NULL,			/* mknod */	NULL,			/* rename */	NULL,			/* readlink */	NULL,			/* follow_link */	NULL,			/* readpage */	NULL,			/* writepage */	NULL,			/* bmap */	NULL,			/* truncate */	NULL			/* permission */};/* * 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, 2, 0, 0,	0, &proc_root_inode_operations,	NULL, NULL,	NULL,	&proc_root, NULL};struct proc_dir_entry proc_net = {	PROC_NET, 3, "net",	S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,	0, &proc_dir_inode_operations,	NULL, NULL,	NULL,	NULL, NULL	};struct proc_dir_entry proc_scsi = {	PROC_SCSI, 4, "scsi",	S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,	0, &proc_dir_inode_operations,	NULL, NULL,	NULL, &proc_root, NULL};struct proc_dir_entry proc_sys_root = {	PROC_SYS, 3, "sys",			/* inode, name */	S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,	/* mode, nlink, uid, gid */	0, &proc_dir_inode_operations,		/* size, ops */	NULL, NULL,				/* get_info, fill_inode */	NULL,					/* next */	NULL, NULL				/* parent, subdir */};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--;			if (ino >= PROC_DYNAMIC_FIRST &&			    ino < PROC_DYNAMIC_FIRST+PROC_NDYNAMIC)				clear_bit(ino-PROC_DYNAMIC_FIRST, 					  (void *) proc_alloc_map);			return 0;		}		p = &dp->next;	}	return -EINVAL;}	static int make_inode_number(void){	int i = find_first_zero_bit((void *) proc_alloc_map, PROC_NDYNAMIC);	if (i<0 || i>=PROC_NDYNAMIC) 		return -1;	set_bit(i, (void *) proc_alloc_map);	return PROC_DYNAMIC_FIRST + i;}int proc_register_dynamic(struct proc_dir_entry * dir,			  struct proc_dir_entry * dp){	int i = make_inode_number();	if (i < 0)		return -EAGAIN;	dp->low_ino = i;	dp->next = dir->subdir;	dp->parent = dir;	dir->subdir = dp;	if (S_ISDIR(dp->mode))		dir->nlink++;	return 0;}/* * /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,			/* readpage */	NULL,			/* writepage */	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_register(&proc_root, &(struct proc_dir_entry) {		PROC_PCI, 3, "pci",		S_IFREG | S_IRUGO, 1, 0, 0,	});#endif	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);	proc_register(&proc_root, &proc_sys_root);#ifdef CONFIG_DEBUG_MALLOC	proc_register(&proc_root, &(struct proc_dir_entry) {		PROC_MALLOC, 6, "malloc",		S_IFREG | S_IRUGO, 1, 0, 0,	});#endif	proc_register(&proc_root, &(struct proc_dir_entry) {		PROC_KCORE, 5, "kcore",		S_IFREG | S_IRUSR, 1, 0, 0,	});#ifdef CONFIG_MODULES	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_KSYMS, 5, "ksyms",		S_IFREG | S_IRUGO, 1, 0, 0,	});#endif	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,	});#ifdef __SMP_PROF__	proc_register(&proc_root, &(struct proc_dir_entry) {		PROC_SMP_PROF, 3,"smp",		S_IFREG | S_IRUGO, 1, 0, 0,	});#endif 	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_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,	});	proc_register(&proc_root, &(struct proc_dir_entry) {		PROC_CMDLINE, 7, "cmdline",		S_IFREG | S_IRUGO, 1, 0, 0,	});#if defined(CONFIG_RTC) || defined(CONFIG_DS1302)	proc_register(&proc_root, &(struct proc_dir_entry) {		PROC_RTC, 3, "rtc",		S_IFREG | S_IRUGO, 1, 0, 0,	});#endif	proc_register(&proc_root, &(struct proc_dir_entry) {		PROC_LOCKS, 5, "locks",		S_IFREG | S_IRUGO, 1, 0, 0,	});	proc_register( &proc_root, &(struct proc_dir_entry)	   { PROC_MTAB, 6, "mounts", S_IFREG | S_IRUGO, 1, 0, 0, } );		   	if (prof_shift) {		proc_register(&proc_root, &(struct proc_dir_entry) {			PROC_PROFILE, 7, "profile",			S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 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);}int proc_lookup(struct inode * dir,const char * name, int len,	struct inode ** result){	struct proc_dir_entry * de;	int ino;	*result = NULL;	if (!dir || !S_ISDIR(dir->i_mode)) {		iput(dir);		return -ENOTDIR;	}	de = (struct proc_dir_entry *) dir->u.generic_ip;	if (!de) {		iput(dir);		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;		}	}	*result = NULL;	for (de = de->subdir; de ; de = de->next) {		if (proc_match(len, name, de))			break;	}	if (!de) {		iput(dir);		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, retval;	dir->i_count++;	retval = proc_lookup(dir, name, len, result);	if (retval != -ENOENT) {		iput(dir);		return retval;	}		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;		}	}	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);	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 10static 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;	nr = filp->f_pos;	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 -= FIRST_PROCESS_ENTRY; nr < NR_TASKS; nr++, filp->f_pos++) {		struct task_struct * p = task[nr];		if (!p || !(pid = p->pid))			continue;		j = NUMBUF;		i = pid;		do {			j--;			buf[j] = '0' + (i % 10);			i /= 10;		} while (i);		if (filldir(dirent, buf+j, NUMBUF-j, filp->f_pos, (pid << 16) + PROC_PID_INO) < 0)			break;	}	return 0;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?