⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sysctl.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 3 页
字号:
 * procname - the name of the sysctl file under /proc/sys. Set to %NULL to not *            enter a sysctl file * * data - a pointer to data for use by proc_handler * * maxlen - the maximum size in bytes of the data * * mode - the file permissions for the /proc/sys file, and for sysctl(2) * * child - a pointer to the child sysctl table if this entry is a directory, or *         %NULL. * * proc_handler - the text handler routine (described below) * * strategy - the strategy routine (described below) * * de - for internal use by the sysctl routines * * extra1, extra2 - extra pointers usable by the proc handler routines * * Leaf nodes in the sysctl tree will be represented by a single file * under /proc; non-leaf nodes will be represented by directories. * * sysctl(2) can automatically manage read and write requests through * the sysctl table.  The data and maxlen fields of the ctl_table * struct enable minimal validation of the values being written to be * performed, and the mode field allows minimal authentication. * * More sophisticated management can be enabled by the provision of a * strategy routine with the table entry.  This will be called before * any automatic read or write of the data is performed. * * The strategy routine may return * * < 0 - Error occurred (error is passed to user process) * * 0   - OK - proceed with automatic read or write. * * > 0 - OK - read or write has been done by the strategy routine, so *       return immediately. * * There must be a proc_handler routine for any terminal nodes * mirrored under /proc/sys (non-terminals are handled by a built-in * directory handler).  Several default handlers are available to * cover common cases - * * proc_dostring(), proc_dointvec(), proc_dointvec_jiffies(), * proc_dointvec_minmax(), proc_doulongvec_ms_jiffies_minmax(), * proc_doulongvec_minmax() * * It is the handler's job to read the input buffer from user memory * and process it. The handler should return 0 on success. * * This routine returns %NULL on a failure to register, and a pointer * to the table header on success. */struct ctl_table_header *register_sysctl_table(ctl_table * table, 					       int insert_at_head){	struct ctl_table_header *tmp;	tmp = kmalloc(sizeof(struct ctl_table_header), GFP_KERNEL);	if (!tmp)		return NULL;	tmp->ctl_table = table;	INIT_LIST_HEAD(&tmp->ctl_entry);	if (insert_at_head)		list_add(&tmp->ctl_entry, &root_table_header.ctl_entry);	else		list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);#ifdef CONFIG_PROC_FS	register_proc_table(table, proc_sys_root);#endif	return tmp;}/** * unregister_sysctl_table - unregister a sysctl table heirarchy * @header: the header returned from register_sysctl_table * * Unregisters the sysctl table and all children. proc entries may not * actually be removed until they are no longer used by anyone. */void unregister_sysctl_table(struct ctl_table_header * header){	list_del(&header->ctl_entry);#ifdef CONFIG_PROC_FS	unregister_proc_table(header->ctl_table, proc_sys_root);#endif	kfree(header);}/* * /proc/sys support */#ifdef CONFIG_PROC_FS/* Scan the sysctl entries in table and add them all into /proc */static void register_proc_table(ctl_table * table, struct proc_dir_entry *root){	struct proc_dir_entry *de;	int len;	mode_t mode;		for (; table->ctl_name; table++) {		/* Can't do anything without a proc name. */		if (!table->procname)			continue;		/* Maybe we can't do anything with it... */		if (!table->proc_handler && !table->child) {			printk(KERN_WARNING "SYSCTL: Can't register %s\n",				table->procname);			continue;		}		len = strlen(table->procname);		mode = table->mode;		de = NULL;		if (table->proc_handler)			mode |= S_IFREG;		else {			mode |= S_IFDIR;			for (de = root->subdir; de; de = de->next) {				if (proc_match(len, table->procname, de))					break;			}			/* If the subdir exists already, de is non-NULL */		}		if (!de) {			de = create_proc_entry(table->procname, mode, root);			if (!de)				continue;			de->data = (void *) table;			if (table->proc_handler) {				de->proc_fops = &proc_sys_file_operations;				de->proc_iops = &proc_sys_inode_operations;			}		}		table->de = de;		if (de->mode & S_IFDIR)			register_proc_table(table->child, de);	}}/* * Unregister a /proc sysctl table and any subdirectories. */static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root){	struct proc_dir_entry *de;	for (; table->ctl_name; table++) {		if (!(de = table->de))			continue;		if (de->mode & S_IFDIR) {			if (!table->child) {				printk (KERN_ALERT "Help - malformed sysctl tree on free\n");				continue;			}			unregister_proc_table(table->child, de);			/* Don't unregister directories which still have entries.. */			if (de->subdir)				continue;		}		/* Don't unregister proc entries that are still being used.. */		if (atomic_read(&de->count))			continue;		table->de = NULL;		remove_proc_entry(table->procname, root);	}}static ssize_t do_rw_proc(int write, struct file * file, char * buf,			  size_t count, loff_t *ppos){	int op;	struct proc_dir_entry *de;	struct ctl_table *table;	size_t res;	ssize_t error;		de = (struct proc_dir_entry*) file->f_dentry->d_inode->u.generic_ip;	if (!de || !de->data)		return -ENOTDIR;	table = (struct ctl_table *) de->data;	if (!table || !table->proc_handler)		return -ENOTDIR;	op = (write ? 002 : 004);	if (ctl_perm(table, op))		return -EPERM;		res = count;	/*	 * FIXME: we need to pass on ppos to the handler.	 */	error = (*table->proc_handler) (table, write, file, buf, &res);	if (error)		return error;	return res;}static ssize_t proc_readsys(struct file * file, char * buf,			    size_t count, loff_t *ppos){	return do_rw_proc(0, file, buf, count, ppos);}static ssize_t proc_writesys(struct file * file, const char * buf,			     size_t count, loff_t *ppos){	return do_rw_proc(1, file, (char *) buf, count, ppos);}static int proc_sys_permission(struct inode *inode, int op){	return test_perm(inode->i_mode, op);}/** * proc_dostring - read a string sysctl * @table: the sysctl table * @write: %TRUE if this is a write to the sysctl file * @filp: the file structure * @buffer: the user buffer * @lenp: the size of the user buffer * * Reads/writes a string from/to the user buffer. If the kernel * buffer provided is not large enough to hold the string, the * string is truncated. The copied string is %NULL-terminated. * If the string is being read by the user process, it is copied * and a newline '\n' is added. It is truncated if the buffer is * not large enough. * * Returns 0 on success. */int proc_dostring(ctl_table *table, int write, struct file *filp,		  void *buffer, size_t *lenp){	size_t len;	char *p, c;		if (!table->data || !table->maxlen || !*lenp ||	    (filp->f_pos && !write)) {		*lenp = 0;		return 0;	}		if (write) {		len = 0;		p = buffer;		while (len < *lenp) {			if(get_user(c, p++))				return -EFAULT;			if (c == 0 || c == '\n')				break;			len++;		}		if (len >= table->maxlen)			len = table->maxlen-1;		if(copy_from_user(table->data, buffer, len))			return -EFAULT;		((char *) table->data)[len] = 0;		filp->f_pos += *lenp;	} else {		len = strlen(table->data);		if (len > table->maxlen)			len = table->maxlen;		if (len > *lenp)			len = *lenp;		if (len)			if(copy_to_user(buffer, table->data, len))				return -EFAULT;		if (len < *lenp) {			if(put_user('\n', ((char *) buffer) + len))				return -EFAULT;			len++;		}		*lenp = len;		filp->f_pos += len;	}	return 0;}/* *	Special case of dostring for the UTS structure. This has locks *	to observe. Should this be in kernel/sys.c ???? */ static int proc_doutsstring(ctl_table *table, int write, struct file *filp,		  void *buffer, size_t *lenp){	int r;	if (!write) {		down_read(&uts_sem);		r=proc_dostring(table,0,filp,buffer,lenp);		up_read(&uts_sem);	} else {		down_write(&uts_sem);		r=proc_dostring(table,1,filp,buffer,lenp);		up_write(&uts_sem);	}	return r;}#define OP_SET	0#define OP_AND	1#define OP_OR	2#define OP_MAX	3#define OP_MIN	4static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,		  void *buffer, size_t *lenp, int conv, int op){	int *i, vleft, first=1, neg, val;	size_t left, len;		#define TMPBUFLEN 20	char buf[TMPBUFLEN], *p;		if (!table->data || !table->maxlen || !*lenp ||	    (filp->f_pos && !write)) {		*lenp = 0;		return 0;	}		i = (int *) table->data;	vleft = table->maxlen / sizeof(int);	left = *lenp;		for (; left && vleft--; i++, first=0) {		if (write) {			while (left) {				char c;				if(get_user(c,(char *) buffer))					return -EFAULT;				if (!isspace(c))					break;				left--;				((char *) buffer)++;			}			if (!left)				break;			neg = 0;			len = left;			if (len > TMPBUFLEN-1)				len = TMPBUFLEN-1;			if(copy_from_user(buf, buffer, len))				return -EFAULT;			buf[len] = 0;			p = buf;			if (*p == '-' && left > 1) {				neg = 1;				left--, p++;			}			if (*p < '0' || *p > '9')				break;			val = simple_strtoul(p, &p, 0) * conv;			len = p-buf;			if ((len < left) && *p && !isspace(*p))				break;			if (neg)				val = -val;			buffer += len;			left -= len;			switch(op) {			case OP_SET:	*i = val; break;			case OP_AND:	*i &= val; break;			case OP_OR:	*i |= val; break;			case OP_MAX:	if(*i < val)						*i = val;					break;			case OP_MIN:	if(*i > val)						*i = val;					break;			}		} else {			p = buf;			if (!first)				*p++ = '\t';			sprintf(p, "%d", (*i) / conv);			len = strlen(buf);			if (len > left)				len = left;			if(copy_to_user(buffer, buf, len))				return -EFAULT;			left -= len;			buffer += len;		}	}	if (!write && !first && left) {		if(put_user('\n', (char *) buffer))			return -EFAULT;		left--, buffer++;	}	if (write) {		p = (char *) buffer;		while (left) {			char c;			if(get_user(c, p++))				return -EFAULT;			if (!isspace(c))				break;			left--;		}	}	if (write && first)		return -EINVAL;	*lenp -= left;	filp->f_pos += *lenp;	return 0;}/** * proc_dointvec - read a vector of integers * @table: the sysctl table * @write: %TRUE if this is a write to the sysctl file * @filp: the file structure * @buffer: the user buffer * @lenp: the size of the user buffer * * Reads/writes up to table->maxlen/sizeof(unsigned int) integer * values from/to the user buffer, treated as an ASCII string.  * * Returns 0 on success. */int proc_dointvec(ctl_table *table, int write, struct file *filp,		     void *buffer, size_t *lenp){    return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET);}/* *	init may raise the set. */ int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,			void *buffer, size_t *lenp){	if (!capable(CAP_SYS_MODULE)) {		return -EPERM;	}	return do_proc_dointvec(table,write,filp,buffer,lenp,1,				(current->pid == 1) ? OP_SET : OP_AND);}/** * proc_dointvec_minmax - read a vector of integers with min/max values * @table: the sysctl table * @write: %TRUE if this is a write to the sysctl file * @filp: the file structure * @buffer: the user buffer * @lenp: the size of the user buffer * * Reads/writes up to table->maxlen/sizeof(unsigned int) integer * values from/to the user buffer, treated as an ASCII string. * * This routine will ensure the values are within the range specified by * table->extra1 (min) and table->extra2 (max). * * Returns 0 on success. */int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,		  void *buffer, size_t *lenp){	int *i, *min, *max, vleft, first=1, neg, val;	size_t len, left;	#define TMPBUFLEN 20	char buf[TMPBUFLEN], *p;		if (!table->data || !table->maxlen || !*lenp ||	    (filp->f_pos && !write)) {		*lenp = 0;		return 0;	}		i = (int *) table->data;	min = (int *) table->extra1;	max = (int *) table->extra2;	vleft = table->maxlen / sizeof(int);	left = *lenp;		for (; left && vleft--; i++, first=0) {		if (write) {			while (left) {				char c;				if(get_user(c, (char *) buffer))					return -EFAULT;				if (!isspace(c))					break;

⌨️ 快捷键说明

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