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

📄 sysctl.c

📁 Kernel code of linux kernel
💻 C
📖 第 1 页 / 共 5 页
字号:
 * some sysctl variables are readonly even to root. */static int test_perm(int mode, int op){	if (!current->euid)		mode >>= 6;	else if (in_egroup_p(0))		mode >>= 3;	if ((op & ~mode & (MAY_READ|MAY_WRITE|MAY_EXEC)) == 0)		return 0;	return -EACCES;}int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op){	int error;	int mode;	error = security_sysctl(table, op & (MAY_READ | MAY_WRITE | MAY_EXEC));	if (error)		return error;	if (root->permissions)		mode = root->permissions(root, current->nsproxy, table);	else		mode = table->mode;	return test_perm(mode, op);}static void sysctl_set_parent(struct ctl_table *parent, struct ctl_table *table){	for (; table->ctl_name || table->procname; table++) {		table->parent = parent;		if (table->child)			sysctl_set_parent(table, table->child);	}}static __init int sysctl_init(void){	sysctl_set_parent(NULL, root_table);#ifdef CONFIG_SYSCTL_SYSCALL_CHECK	{		int err;		err = sysctl_check_table(current->nsproxy, root_table);	}#endif	return 0;}core_initcall(sysctl_init);static struct ctl_table *is_branch_in(struct ctl_table *branch,				      struct ctl_table *table){	struct ctl_table *p;	const char *s = branch->procname;	/* branch should have named subdirectory as its first element */	if (!s || !branch->child)		return NULL;	/* ... and nothing else */	if (branch[1].procname || branch[1].ctl_name)		return NULL;	/* table should contain subdirectory with the same name */	for (p = table; p->procname || p->ctl_name; p++) {		if (!p->child)			continue;		if (p->procname && strcmp(p->procname, s) == 0)			return p;	}	return NULL;}/* see if attaching q to p would be an improvement */static void try_attach(struct ctl_table_header *p, struct ctl_table_header *q){	struct ctl_table *to = p->ctl_table, *by = q->ctl_table;	struct ctl_table *next;	int is_better = 0;	int not_in_parent = !p->attached_by;	while ((next = is_branch_in(by, to)) != NULL) {		if (by == q->attached_by)			is_better = 1;		if (to == p->attached_by)			not_in_parent = 1;		by = by->child;		to = next->child;	}	if (is_better && not_in_parent) {		q->attached_by = by;		q->attached_to = to;		q->parent = p;	}}/** * __register_sysctl_paths - register a sysctl hierarchy * @root: List of sysctl headers to register on * @namespaces: Data to compute which lists of sysctl entries are visible * @path: The path to the directory the sysctl table is in. * @table: the top-level table structure * * Register a sysctl table hierarchy. @table should be a filled in ctl_table * array. A completely 0 filled entry terminates the table. * * The members of the &struct ctl_table structure are used as follows: * * ctl_name - This is the numeric sysctl value used by sysctl(2). The number *            must be unique within that level of sysctl * * 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_userhz_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_paths(	struct ctl_table_root *root,	struct nsproxy *namespaces,	const struct ctl_path *path, struct ctl_table *table){	struct ctl_table_header *header;	struct ctl_table *new, **prevp;	unsigned int n, npath;	struct ctl_table_set *set;	/* Count the path components */	for (npath = 0; path[npath].ctl_name || path[npath].procname; ++npath)		;	/*	 * For each path component, allocate a 2-element ctl_table array.	 * The first array element will be filled with the sysctl entry	 * for this, the second will be the sentinel (ctl_name == 0).	 *	 * We allocate everything in one go so that we don't have to	 * worry about freeing additional memory in unregister_sysctl_table.	 */	header = kzalloc(sizeof(struct ctl_table_header) +			 (2 * npath * sizeof(struct ctl_table)), GFP_KERNEL);	if (!header)		return NULL;	new = (struct ctl_table *) (header + 1);	/* Now connect the dots */	prevp = &header->ctl_table;	for (n = 0; n < npath; ++n, ++path) {		/* Copy the procname */		new->procname = path->procname;		new->ctl_name = path->ctl_name;		new->mode     = 0555;		*prevp = new;		prevp = &new->child;		new += 2;	}	*prevp = table;	header->ctl_table_arg = table;	INIT_LIST_HEAD(&header->ctl_entry);	header->used = 0;	header->unregistering = NULL;	header->root = root;	sysctl_set_parent(NULL, header->ctl_table);	header->count = 1;#ifdef CONFIG_SYSCTL_SYSCALL_CHECK	if (sysctl_check_table(namespaces, header->ctl_table)) {		kfree(header);		return NULL;	}#endif	spin_lock(&sysctl_lock);	header->set = lookup_header_set(root, namespaces);	header->attached_by = header->ctl_table;	header->attached_to = root_table;	header->parent = &root_table_header;	for (set = header->set; set; set = set->parent) {		struct ctl_table_header *p;		list_for_each_entry(p, &set->list, ctl_entry) {			if (p->unregistering)				continue;			try_attach(p, header);		}	}	header->parent->count++;	list_add_tail(&header->ctl_entry, &header->set->list);	spin_unlock(&sysctl_lock);	return header;}/** * register_sysctl_table_path - register a sysctl table hierarchy * @path: The path to the directory the sysctl table is in. * @table: the top-level table structure * * Register a sysctl table hierarchy. @table should be a filled in ctl_table * array. A completely 0 filled entry terminates the table. * * See __register_sysctl_paths for more details. */struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path,						struct ctl_table *table){	return __register_sysctl_paths(&sysctl_table_root, current->nsproxy,					path, table);}/** * register_sysctl_table - register a sysctl table hierarchy * @table: the top-level table structure * * Register a sysctl table hierarchy. @table should be a filled in ctl_table * array. A completely 0 filled entry terminates the table. * * See register_sysctl_paths for more details. */struct ctl_table_header *register_sysctl_table(struct ctl_table *table){	static const struct ctl_path null_path[] = { {} };	return register_sysctl_paths(null_path, table);}/** * unregister_sysctl_table - unregister a sysctl table hierarchy * @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){	might_sleep();	if (header == NULL)		return;	spin_lock(&sysctl_lock);	start_unregistering(header);	if (!--header->parent->count) {		WARN_ON(1);		kfree(header->parent);	}	if (!--header->count)		kfree(header);	spin_unlock(&sysctl_lock);}int sysctl_is_seen(struct ctl_table_header *p){	struct ctl_table_set *set = p->set;	int res;	spin_lock(&sysctl_lock);	if (p->unregistering)		res = 0;	else if (!set->is_seen)		res = 1;	else		res = set->is_seen(set);	spin_unlock(&sysctl_lock);	return res;}void setup_sysctl_set(struct ctl_table_set *p,	struct ctl_table_set *parent,	int (*is_seen)(struct ctl_table_set *)){	INIT_LIST_HEAD(&p->list);	p->parent = parent ? parent : &sysctl_table_root.default_set;	p->is_seen = is_seen;}#else /* !CONFIG_SYSCTL */struct ctl_table_header *register_sysctl_table(struct ctl_table * table){	return NULL;}struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path,						    struct ctl_table *table){	return NULL;}void unregister_sysctl_table(struct ctl_table_header * table){}void setup_sysctl_set(struct ctl_table_set *p,	struct ctl_table_set *parent,	int (*is_seen)(struct ctl_table_set *)){}void sysctl_head_put(struct ctl_table_header *head){}#endif /* CONFIG_SYSCTL *//* * /proc/sys support */#ifdef CONFIG_PROC_SYSCTLstatic int _proc_do_string(void* data, int maxlen, int write,			   struct file *filp, void __user *buffer,			   size_t *lenp, loff_t *ppos){	size_t len;	char __user *p;	char c;	if (!data || !maxlen || !*lenp) {		*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 >= maxlen)			len = maxlen-1;		if(copy_from_user(data, buffer, len))			return -EFAULT;		((char *) data)[len] = 0;		*ppos += *lenp;	} else {		len = strlen(data);		if (len > maxlen)			len = maxlen;		if (*ppos > len) {			*lenp = 0;			return 0;		}		data += *ppos;		len  -= *ppos;		if (len > *lenp)			len = *lenp;		if (len)			if(copy_to_user(buffer, data, len))				return -EFAULT;		if (len < *lenp) {			if(put_user('\n', ((char __user *) buffer) + len))				return -EFAULT;			len++;		}		*lenp = len;		*ppos += len;	}	return 0;}/** * 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 * @ppos: file position * * 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(struct ctl_table *table, int write, struct file *filp,		  void __user *buffer, size_t *lenp, loff_t *ppos){	return _proc_do_string(table->data, table->maxlen, write, filp,			       buffer, lenp, ppos);}static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp,				 int *valp,				 int write, void *data){	if (write) {		*valp = *negp ? -*lvalp : *lvalp;	} else {		int val = *valp;		if (val < 0) {			*negp = -1;			*lvalp = (unsigned long)-val;		} else {			*negp = 0;			*lvalp = (unsigned long)val;		}	}	return 0;}static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,		  int write, struct file *filp, void __user *buffer,		  size_t *lenp, loff_t *ppos,		  int (*conv)(int *negp, unsigned long *lvalp, int *valp,			      int write, void *data),		  void *data){#define TMPBUFLEN 21	int *i, vleft, first=1, neg, val;	unsigned long lval;	size_t left, len;		char buf[TMPBUFLEN], *p;	char __user *s = buffer;		if (!tbl_data || !table->maxlen || !*lenp ||	    (*ppos && !write)) {		*lenp = 0;		return 0;	}		i = (int *) tbl_data;	vleft = table->maxlen / sizeof(*i);	left = *lenp;	if (!conv)		conv = do_proc_dointvec_conv;	for (; left && vleft--; i++, first=0) {		if (write) {			while (left) {				char c;				if (get_user(c, s))					return -EFAULT;				if (!isspace(c))					break;				left--;				s++;			}			if (!left)				break;			neg = 0;			len = left;			if (len > sizeof(buf) - 1)				len = sizeof(buf) - 1;			if (copy_from_user(buf, s, len))				return -EFAULT;			buf[len] = 0;			p = buf;			if (*p == '-' && left > 1) {				neg = 1;				p++;			}			if (*p < '0' || *p > '9')				break;			lval = simple_strtoul(p, &p, 0);			len = p-buf;			if ((len < left) && *p && !isspace(*p))				break;			if (neg)				val = -val;			s += len;			left -= len;			if (conv(&neg, &lval, i, 1, data))				break;		} else {			p = buf;			if (!first)				*p++ = '\t';				if (conv(&neg, &lval, i, 0, data))

⌨️ 快捷键说明

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