Beispiel #1
0
void
sysctl_register_oid(struct sysctl_oid *oidp)
{
	sysctl_lock(LK_EXCLUSIVE);
	sysctl_register_oid_int(oidp);
	sysctl_unlock();
}
Beispiel #2
0
int
netbsd32___sysctl(struct lwp *l, const struct netbsd32___sysctl_args *uap, register_t *retval)
{
	/* {
		syscallarg(netbsd32_intp) name;
		syscallarg(u_int) namelen;
		syscallarg(netbsd32_voidp) old;
		syscallarg(netbsd32_size_tp) oldlenp;
		syscallarg(netbsd32_voidp) new;
		syscallarg(netbsd32_size_t) newlen;
	} */
	const struct sysctlnode *pnode;
	netbsd32_size_t netbsd32_oldlen;
	size_t oldlen, *oldlenp, savelen;
	int name[CTL_MAXNAME], error, nerror, *namep;
	void *newp, *oldp;

	/*
	 * get and convert 32 bit size_t to native size_t
	 */
	namep = SCARG_P32(uap, name);
	oldp = SCARG_P32(uap, oldv);
	newp = SCARG_P32(uap, newv);
	oldlenp = SCARG_P32(uap, oldlenp);
	oldlen = 0;
	if (oldlenp != NULL) {
		error = copyin(oldlenp, &netbsd32_oldlen,
			       sizeof(netbsd32_oldlen));
		if (error)
			return (error);
		oldlen = netbsd32_oldlen;
	}
	savelen = oldlen;

	/*
	 * retrieve name and see if we need to dispatch this query to
	 * the shadow tree.  if we find it in the shadow tree,
	 * dispatch to there, otherwise NULL means use the built-in
	 * default main tree.
	 */
	if (SCARG(uap, namelen) > CTL_MAXNAME || SCARG(uap, namelen) < 1)
		return (EINVAL);
	error = copyin(namep, &name[0], SCARG(uap, namelen) * sizeof(int));
        if (error)
                return (error);

	ktrmib(name, SCARG(uap, namelen));

	sysctl_lock(newp != NULL);
	pnode = &netbsd32_sysctl_root;
	error = sysctl_locate(l, &name[0], SCARG(uap, namelen), &pnode, NULL);
	pnode = (error == 0) ? &netbsd32_sysctl_root : NULL;
	error = sysctl_dispatch(&name[0], SCARG(uap, namelen),
				oldp, &oldlen,
				newp, SCARG(uap, newlen),
				&name[0], l, pnode);
	sysctl_unlock();

	/*
	 * reset caller's oldlen, even if we got an error
	 */
	if (oldlenp) {
		netbsd32_oldlen = oldlen;
                nerror = copyout(&netbsd32_oldlen, oldlenp,
				 sizeof(netbsd32_oldlen));
                if (error == 0)
                        error = nerror;
	}

	/*
	 * if the only problem is that we weren't given enough space,
	 * that's an ENOMEM error
	 */
	if (error == 0 && oldp != NULL && savelen < oldlen)
		error = ENOMEM;

	return (error);
}
Beispiel #3
0
/*
 * linux sysctl system call
 */
int
linux_sys___sysctl(struct lwp *l, const struct linux_sys___sysctl_args *uap, register_t *retval)
{
	struct linux___sysctl ls;
	int error, nerror, name[CTL_MAXNAME];
	size_t savelen = 0, oldlen = 0;

	/*
	 * get linux args structure
	 */
	if ((error = copyin(SCARG(uap, lsp), &ls, sizeof(ls))))
		return error;

	/*
	 * get oldlen
	 */
	oldlen = 0;
	if (ls.oldlenp != NULL) {
		error = copyin(ls.oldlenp, &oldlen, sizeof(oldlen));
		if (error)
			return (error);
	}
	savelen = oldlen;

	/*
	 * top-level sysctl names may or may not be non-terminal, but
	 * we don't care
	 */
	if (ls.nlen > CTL_MAXNAME || ls.nlen < 1)
		return (ENOTDIR);
	error = copyin(ls.name, &name, ls.nlen * sizeof(int));
	if (error)
		return (error);

	ktrmib(name, ls.nlen);

	/*
	 * dispatch request into linux sysctl tree
	 */
	sysctl_lock(ls.newval != NULL);
	error = sysctl_dispatch(&name[0], ls.nlen,
				ls.oldval, &oldlen,
				ls.newval, ls.newlen,
				&name[0], l, &linux_sysctl_root);
	sysctl_unlock();

	/*
	 * reset caller's oldlen, even if we got an error
	 */
	if (ls.oldlenp) {
		nerror = copyout(&oldlen, ls.oldlenp, sizeof(oldlen));
		if (error == 0)
			error = nerror;
	}

	/*
	 * if the only problem is that we weren't given enough space,
	 * that's an ENOMEM error
	 */
	if (error == 0 && ls.oldval != NULL && savelen < oldlen)
		error = ENOMEM;

	return (error);
}
Beispiel #4
0
/*
 * Linux compatible /proc/version. Only active when the -o linux
 * mountflag is used.
 */
int
procfs_doversion(struct lwp *curl, struct proc *p,
    struct pfsnode *pfs, struct uio *uio)
{
	char *bf;
	char lostype[20], losrelease[20], lversion[80];
	const char *postype, *posrelease, *pversion;
	const char *emulname = curlwp->l_proc->p_emul->e_name;
	int len;
	int error = 0;
	int nm[4];
	size_t buflen;

	CTASSERT(EMUL_LINUX_KERN_OSTYPE == EMUL_LINUX32_KERN_OSTYPE);
	CTASSERT(EMUL_LINUX_KERN_OSRELEASE == EMUL_LINUX32_KERN_OSRELEASE);
	CTASSERT(EMUL_LINUX_KERN_VERSION == EMUL_LINUX32_KERN_VERSION);

	bf = malloc(LBFSZ, M_TEMP, M_WAITOK);

	sysctl_lock(false);

	if (strncmp(emulname, "linux", 5) == 0) {
		/*
		 * Lookup the emulation ostype, osrelease, and version.
		 * Since compat_linux and compat_linux32 can be built as
		 * modules, we use sysctl to obtain the values instead of
		 * using the symbols directly.
		 */

		if (strcmp(emulname, "linux32") == 0) {
			nm[0] = CTL_EMUL;
			nm[1] = EMUL_LINUX32;
			nm[2] = EMUL_LINUX32_KERN;
		} else {
			nm[0] = CTL_EMUL;
			nm[1] = EMUL_LINUX;
			nm[2] = EMUL_LINUX_KERN;
		}

		nm[3] = EMUL_LINUX_KERN_OSTYPE;
		buflen = sizeof(lostype);
		error = sysctl_dispatch(nm, __arraycount(nm),
		    lostype, &buflen,
		    NULL, 0, NULL, NULL, NULL);
		if (error)
			goto out;

		nm[3] = EMUL_LINUX_KERN_OSRELEASE;
		buflen = sizeof(losrelease);
		error = sysctl_dispatch(nm, __arraycount(nm),
		    losrelease, &buflen,
		    NULL, 0, NULL, NULL, NULL);
		if (error)
			goto out;

		nm[3] = EMUL_LINUX_KERN_VERSION;
		buflen = sizeof(lversion);
		error = sysctl_dispatch(nm, __arraycount(nm),
		    lversion, &buflen,
		    NULL, 0, NULL, NULL, NULL);
		if (error)
			goto out;

		postype = lostype;
		posrelease = losrelease;
		pversion = lversion;
	} else {
		postype = ostype;
		posrelease = osrelease;
		strlcpy(lversion, version, sizeof(lversion));
		if (strchr(lversion, '\n'))
			*strchr(lversion, '\n') = '\0';
		pversion = lversion;
	}

	len = snprintf(bf, LBFSZ,
		"%s version %s (%s@localhost) (gcc version %s) %s\n",
		postype, posrelease, emulname,
#ifdef __VERSION__
		__VERSION__,
#else
		"unknown",
#endif
		pversion);

	if (len == 0)
		goto out;

	error = uiomove_frombuf(bf, len, uio);
out:
	free(bf, M_TEMP);
	sysctl_unlock();
	return error;
}
Beispiel #5
0
int
linux32_sys___sysctl(struct lwp *l, const struct linux32_sys___sysctl_args *uap, register_t *retval)
{
	/* {
		syscallarg(linux32___sysctlp_t) lsp;
	} */
	struct linux32_sysctl ls32;
	int name[CTL_MAXNAME];
	size_t savelen;
	netbsd32_size_t oldlen32;
	size_t oldlen;
	int error;

	/*
	 * Read sysctl arguments 
	 */
	if ((error = copyin(SCARG_P32(uap, lsp), &ls32, sizeof(ls32))) != 0)
		return error;

	/*
	 * Read oldlen
	 */
	if (NETBSD32PTR64(ls32.oldlenp) != NULL) {
		if ((error = copyin(NETBSD32PTR64(ls32.oldlenp), 
		    &oldlen32, sizeof(oldlen32))) != 0)
			return error;
	} else {
		oldlen32 = 0;
	}

	savelen = (size_t)oldlen32;

	/* 
	 * Sanity check nlen
	 */
	if ((ls32.nlen > CTL_MAXNAME) || (ls32.nlen < 1))
		return ENOTDIR;

	/*
	 * Read the sysctl name
	 */
	if ((error = copyin(NETBSD32PTR64(ls32.name), &name, 
	   ls32.nlen * sizeof(int))) != 0)
		return error;

	ktrmib(name, ls32.nlen);
	/*
	 * First try linux32 tree, then linux tree
	 */
	oldlen = (size_t)oldlen32;
	sysctl_lock(NETBSD32PTR64(ls32.newval) != NULL);
	error = sysctl_dispatch(name, ls32.nlen,
				NETBSD32PTR64(ls32.oldval), &oldlen,
				NETBSD32PTR64(ls32.newval), ls32.newlen,
				name, l, &linux32_sysctl_root);
	oldlen32 = (netbsd32_size_t)oldlen;
	sysctl_unlock();

	/*
	 * Check for oldlen overflow (not likely, but who knows...)
	 */
	if (oldlen != oldlen32) {
#ifdef DEBUG_LINUX
		printf("%s: oldlen32 = %d, oldlen = %ld\n", 
		    __func__, oldlen32, oldlen);
#endif
		return EINVAL;
	}

	/*
	 * set caller's oldlen, even if we got an error
	 */
	if (NETBSD32PTR64(ls32.oldlenp)) {
		int nerror;

		nerror = copyout(&oldlen32, 
		    NETBSD32PTR64(ls32.oldlenp), sizeof(oldlen32));

		if (error == 0)
			error = nerror;
	}

	/*
	 * oldlen was too short
	 */
	if ((error == 0) && 
	    (NETBSD32PTR64(ls32.oldval) != NULL) &&
	    (savelen < oldlen32))
		error = ENOMEM;

	return error;
}
/* Register a new filesystem type in the global table */
static int
vfs_register(struct vfsconf *vfc)
{
	struct sysctl_oid *oidp;
	struct vfsops *vfsops;
	static int once;

	if (!once) {
		vattr_null(&va_null);
		once = 1;
	}
	
	if (vfc->vfc_version != VFS_VERSION) {
		printf("ERROR: filesystem %s, unsupported ABI version %x\n",
		    vfc->vfc_name, vfc->vfc_version);
		return (EINVAL);
	}
	if (vfs_byname(vfc->vfc_name) != NULL)
		return EEXIST;

	vfc->vfc_typenum = maxvfsconf++;
	TAILQ_INSERT_TAIL(&vfsconf, vfc, vfc_list);

	/*
	 * If this filesystem has a sysctl node under vfs
	 * (i.e. vfs.xxfs), then change the oid number of that node to 
	 * match the filesystem's type number.  This allows user code
	 * which uses the type number to read sysctl variables defined
	 * by the filesystem to continue working. Since the oids are
	 * in a sorted list, we need to make sure the order is
	 * preserved by re-registering the oid after modifying its
	 * number.
	 */
	sysctl_lock();
	SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link)
		if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) {
			sysctl_unregister_oid(oidp);
			oidp->oid_number = vfc->vfc_typenum;
			sysctl_register_oid(oidp);
			break;
		}
	sysctl_unlock();

	/*
	 * Initialise unused ``struct vfsops'' fields, to use
	 * the vfs_std*() functions.  Note, we need the mount
	 * and unmount operations, at the least.  The check
	 * for vfsops available is just a debugging aid.
	 */
	KASSERT(vfc->vfc_vfsops != NULL,
	    ("Filesystem %s has no vfsops", vfc->vfc_name));
	/*
	 * Check the mount and unmount operations.
	 */
	vfsops = vfc->vfc_vfsops;
	KASSERT(vfsops->vfs_mount != NULL,
	    ("Filesystem %s has no mount op", vfc->vfc_name));
	KASSERT(vfsops->vfs_unmount != NULL,
	    ("Filesystem %s has no unmount op", vfc->vfc_name));

	if (vfsops->vfs_root == NULL)
		/* return file system's root vnode */
		vfsops->vfs_root =	vfs_stdroot;
	if (vfsops->vfs_quotactl == NULL)
		/* quota control */
		vfsops->vfs_quotactl =	vfs_stdquotactl;
	if (vfsops->vfs_statfs == NULL)
		/* return file system's status */
		vfsops->vfs_statfs =	vfs_stdstatfs;
	if (vfsops->vfs_sync == NULL)
		/*
		 * flush unwritten data (nosync)
		 * file systems can use vfs_stdsync
		 * explicitly by setting it in the
		 * vfsop vector.
		 */
		vfsops->vfs_sync =	vfs_stdnosync;
	if (vfsops->vfs_vget == NULL)
		/* convert an inode number to a vnode */
		vfsops->vfs_vget =	vfs_stdvget;
	if (vfsops->vfs_fhtovp == NULL)
		/* turn an NFS file handle into a vnode */
		vfsops->vfs_fhtovp =	vfs_stdfhtovp;
	if (vfsops->vfs_checkexp == NULL)
		/* check if file system is exported */
		vfsops->vfs_checkexp =	vfs_stdcheckexp;
	if (vfsops->vfs_init == NULL)
		/* file system specific initialisation */
		vfsops->vfs_init =	vfs_stdinit;
	if (vfsops->vfs_uninit == NULL)
		/* file system specific uninitialisation */
		vfsops->vfs_uninit =	vfs_stduninit;
	if (vfsops->vfs_extattrctl == NULL)
		/* extended attribute control */
		vfsops->vfs_extattrctl = vfs_stdextattrctl;
	if (vfsops->vfs_sysctl == NULL)
		vfsops->vfs_sysctl = vfs_stdsysctl;
	
	/*
	 * Call init function for this VFS...
	 */
	(*(vfc->vfc_vfsops->vfs_init))(vfc);

	return 0;
}