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

📄 kern_sysctl.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Transfer function to/from user space. */static intsysctl_old_user(struct sysctl_req *req, const void *p, size_t l){	int error = 0;	size_t i = 0;#ifndef __rtems__	if (req->lock == 1 && req->oldptr)		WITNESS_SLEEP(1, NULL);#endif	if (req->oldptr) {		i = l;		if (req->oldlen <= req->oldidx)			i = 0;		else			if (i > req->oldlen - req->oldidx)				i = req->oldlen - req->oldidx;		if (i > 0)			error = copyout(p, (char *)req->oldptr + req->oldidx,					i);	}	req->oldidx += l;	if (error)		return (error);	if (req->oldptr && i < l)		return (ENOMEM);	return (0);}static intsysctl_new_user(struct sysctl_req *req, void *p, size_t l){	int error;	if (!req->newptr)		return 0;	if (req->newlen - req->newidx < l)		return (EINVAL);	error = copyin((char *)req->newptr + req->newidx, p, l);	req->newidx += l;	return (error);}/* * Wire the user space destination buffer.  If set to a value greater than * zero, the len parameter limits the maximum amount of wired memory. * * XXX - The len parameter is currently ignored due to the lack of * a place to save it in the sysctl_req structure so that the matching * amount of memory can be unwired in the sysctl exit code. */voidsysctl_wire_old_buffer(struct sysctl_req *req, size_t len){	if (req->lock == 1 && req->oldptr && req->oldfunc == sysctl_old_user) {#ifndef __rtems__		vslock(req->oldptr, req->oldlen);#endif		req->lock = 2;	}}intsysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid,    int *nindx, struct sysctl_req *req){	struct sysctl_oid *oid;	int indx;	oid = SLIST_FIRST(&sysctl__children);	indx = 0;	while (oid && indx < CTL_MAXNAME) {		if (oid->oid_number == name[indx]) {			indx++;			if (oid->oid_kind & CTLFLAG_NOLOCK)				req->lock = 0;			if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {				if (oid->oid_handler != NULL ||				    indx == namelen) {					*noid = oid;					if (nindx != NULL)						*nindx = indx;					return (0);				}				oid = SLIST_FIRST(				    (struct sysctl_oid_list *)oid->oid_arg1);			} else if (indx == namelen) {				*noid = oid;				if (nindx != NULL)					*nindx = indx;				return (0);			} else {				return (ENOTDIR);			}		} else {			oid = SLIST_NEXT(oid, oid_link);		}	}	return (ENOENT);}/* * Traverse our tree, and find the right node, execute whatever it points * to, and return the resulting error code. */static intsysctl_root(SYSCTL_HANDLER_ARGS){	struct sysctl_oid *oid;	int error, indx;	error = sysctl_find_oid(arg1, arg2, &oid, &indx, req);	if (error)		return (error);	if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {		/*		 * You can't call a sysctl when it's a node, but has		 * no handler.  Inform the user that it's a node.		 * The indx may or may not be the same as namelen.		 */		if (oid->oid_handler == NULL)			return (EISDIR);	}	/* Is this sysctl writable? */	if (req->newptr && !(oid->oid_kind & CTLFLAG_WR))		return (EPERM);#ifndef __rtems__	KASSERT(req->td != NULL, ("sysctl_root(): req->td == NULL"));	/* Is this sysctl sensitive to securelevels? */	if (req->newptr && (oid->oid_kind & CTLFLAG_SECURE)) {		error = securelevel_gt(req->td->td_ucred, 0);		if (error)			return (error);	}  	/* Is this sysctl writable by only privileged users? */	if (req->newptr && !(oid->oid_kind & CTLFLAG_ANYBODY)) {		int flags;		if (oid->oid_kind & CTLFLAG_PRISON)			flags = PRISON_ROOT;		else			flags = 0;		error = suser_cred(req->td->td_ucred, flags);		if (error)			return (error);	}#endif  	if (!oid->oid_handler)		return EINVAL;	if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE)		error = oid->oid_handler(oid, (int *)arg1 + indx, arg2 - indx,		    req);	else		error = oid->oid_handler(oid, oid->oid_arg1, oid->oid_arg2,		    req);	return (error);}#ifndef _SYS_SYSPROTO_H_struct sysctl_args {	int	*name;	u_int	namelen;	void	*old;	size_t	*oldlenp;	void	*new;	size_t	newlen;};#endif/* * MPSAFE */int__sysctl(struct thread *td, struct sysctl_args *uap){	int error, name[CTL_MAXNAME];	size_t j;	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)		return (EINVAL); 	error = copyin(uap->name, &name, uap->namelen * sizeof(int)); 	if (error)		return (error);	mtx_lock(&Giant);	error = userland_sysctl(td, name, uap->namelen,		uap->old, uap->oldlenp, 0,		uap->new, uap->newlen, &j);	if (error && error != ENOMEM)		goto done2;	if (uap->oldlenp) {		int i = copyout(&j, uap->oldlenp, sizeof(j));		if (i)			error = i;	}done2:	mtx_unlock(&Giant);	return (error);}/* * This is used from various compatibility syscalls too.  That's why name * must be in kernel space. */intuserland_sysctl(struct thread *td, int *name, u_int namelen, void *old,    size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval){	int error = 0;	struct sysctl_req req, req2;	bzero(&req, sizeof req);	req.td = td;	if (oldlenp) {		if (inkernel) {			req.oldlen = *oldlenp;		} else {			error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));			if (error)				return (error);		}	}	if (old) {#ifndef __rtems__		if (!useracc(old, req.oldlen, VM_PROT_WRITE))			return (EFAULT);#endif		req.oldptr= old;	}	if (new != NULL) {#ifndef __rtems__		if (!useracc(new, req.newlen, VM_PROT_READ))			return (EFAULT);#endif		req.newlen = newlen;		req.newptr = new;	}	req.oldfunc = sysctl_old_user;	req.newfunc = sysctl_new_user;	req.lock = 1;	SYSCTL_LOCK();#ifdef MAC	error = mac_check_system_sysctl(td->td_ucred, name, namelen, old,	    oldlenp, inkernel, new, newlen);	if (error) {		SYSCTL_UNLOCK();		return (error);	}#endif	do {	    req2 = req;	    error = sysctl_root(0, name, namelen, &req2);	} while (error == EAGAIN);	req = req2;#ifndef __rtems__	if (req.lock == 2)		vsunlock(req.oldptr, req.oldlen);#endif  	SYSCTL_UNLOCK();	if (error && error != ENOMEM)		return (error);	if (retval) {		if (req.oldptr && req.oldidx > req.oldlen)			*retval = req.oldlen;		else			*retval = req.oldidx;	}	return (error);}#ifdef COMPAT_43#include <sys/socket.h>#include <vm/vm_param.h>#define	KINFO_PROC		(0<<8)#define	KINFO_RT		(1<<8)#define	KINFO_VNODE		(2<<8)#define	KINFO_FILE		(3<<8)#define	KINFO_METER		(4<<8)#define	KINFO_LOADAVG		(5<<8)#define	KINFO_CLOCKRATE		(6<<8)/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */#define	KINFO_BSDI_SYSINFO	(101<<8)/* * XXX this is bloat, but I hope it's better here than on the potentially * limited kernel stack...  -Peter */static struct {	int	bsdi_machine;		/* "i386" on BSD/386 *//*      ^^^ this is an offset to the string, relative to the struct start */	char	*pad0;	long	pad1;	long	pad2;	long	pad3;	u_long	pad4;	u_long	pad5;	u_long	pad6;	int	bsdi_ostype;		/* "BSD/386" on BSD/386 */	int	bsdi_osrelease;		/* "1.1" on BSD/386 */	long	pad7;	long	pad8;	char	*pad9;	long	pad10;	long	pad11;	int	pad12;	long	pad13;	quad_t	pad14;	long	pad15;	struct	timeval pad16;	/* we dont set this, because BSDI's uname used gethostname() instead */	int	bsdi_hostname;		/* hostname on BSD/386 */	/* the actual string data is appended here */} bsdi_si;/* * this data is appended to the end of the bsdi_si structure during copyout. * The "char *" offsets are relative to the base of the bsdi_si struct. * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings * should not exceed the length of the buffer here... (or else!! :-) */static char bsdi_strings[80];	/* It had better be less than this! */#ifndef _SYS_SYSPROTO_H_struct getkerninfo_args {	int	op;	char	*where;	size_t	*size;	int	arg;};#endif/* * MPSAFE */intogetkerninfo(struct thread *td, struct getkerninfo_args *uap){	int error, name[6];	size_t size;	u_int needed = 0;	mtx_lock(&Giant);	switch (uap->op & 0xff00) {	case KINFO_RT:		name[0] = CTL_NET;		name[1] = PF_ROUTE;		name[2] = 0;		name[3] = (uap->op & 0xff0000) >> 16;		name[4] = uap->op & 0xff;		name[5] = uap->arg;		error = userland_sysctl(td, name, 6, uap->where, uap->size,			0, 0, 0, &size);		break;	case KINFO_VNODE:		name[0] = CTL_KERN;		name[1] = KERN_VNODE;		error = userland_sysctl(td, name, 2, uap->where, uap->size,			0, 0, 0, &size);		break;	case KINFO_PROC:		name[0] = CTL_KERN;		name[1] = KERN_PROC;		name[2] = uap->op & 0xff;		name[3] = uap->arg;		error = userland_sysctl(td, name, 4, uap->where, uap->size,			0, 0, 0, &size);		break;	case KINFO_FILE:		name[0] = CTL_KERN;		name[1] = KERN_FILE;		error = userland_sysctl(td, name, 2, uap->where, uap->size,			0, 0, 0, &size);		break;	case KINFO_METER:		name[0] = CTL_VM;		name[1] = VM_METER;		error = userland_sysctl(td, name, 2, uap->where, uap->size,			0, 0, 0, &size);		break;	case KINFO_LOADAVG:		name[0] = CTL_VM;		name[1] = VM_LOADAVG;		error = userland_sysctl(td, name, 2, uap->where, uap->size,			0, 0, 0, &size);		break;	case KINFO_CLOCKRATE:		name[0] = CTL_KERN;		name[1] = KERN_CLOCKRATE;		error = userland_sysctl(td, name, 2, uap->where, uap->size,			0, 0, 0, &size);		break;	case KINFO_BSDI_SYSINFO: {		/*		 * this is pretty crude, but it's just enough for uname()		 * from BSDI's 1.x libc to work.		 *		 * *size gives the size of the buffer before the call, and		 * the amount of data copied after a successful call.		 * If successful, the return value is the amount of data		 * available, which can be larger than *size.		 *		 * BSDI's 2.x product apparently fails with ENOMEM if *size		 * is too small.		 */		u_int left;		char *s;		bzero((char *)&bsdi_si, sizeof(bsdi_si));		bzero(bsdi_strings, sizeof(bsdi_strings));		s = bsdi_strings;		bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);		strcpy(s, ostype);		s += strlen(s) + 1;		bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);		strcpy(s, osrelease);		s += strlen(s) + 1;		bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);		strcpy(s, machine);		s += strlen(s) + 1;		needed = sizeof(bsdi_si) + (s - bsdi_strings);		if ((uap->where == NULL) || (uap->size == NULL)) {			/* process is asking how much buffer to supply.. */			size = needed;			error = 0;			break;		}		if ((error = copyin(uap->size, &size, sizeof(size))) != 0)			break;		/* if too much buffer supplied, trim it down */		if (size > needed)			size = needed;		/* how much of the buffer is remaining */		left = size;		if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)			break;		/* is there any point in continuing? */		if (left > sizeof(bsdi_si)) {			left -= sizeof(bsdi_si);			error = copyout(&bsdi_strings,					uap->where + sizeof(bsdi_si), left);		}		break;	}	default:		error = EOPNOTSUPP;		break;	}	if (error == 0) {		td->td_retval[0] = needed ? needed : size;		if (uap->size) {			error = copyout(&size, uap->size, sizeof(size));		}	}	mtx_unlock(&Giant);	return (error);}#endif /* COMPAT_43 */

⌨️ 快捷键说明

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