1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 1992, 1993
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software donated to Berkeley by
|
|
|
|
* Jan-Simon Pendry.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by the University of
|
|
|
|
* California, Berkeley and its contributors.
|
|
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
1997-02-10 02:22:35 +00:00
|
|
|
* @(#)kernfs_vnops.c 8.15 (Berkeley) 5/21/95
|
1997-10-27 13:33:47 +00:00
|
|
|
* $Id: kernfs_vnops.c,v 1.27 1997/10/26 20:55:18 phk Exp $
|
1994-05-24 10:09:53 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Kernel parameter filesystem (/kern)
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/vmmeter.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/vnode.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/mount.h>
|
|
|
|
#include <sys/namei.h>
|
|
|
|
#include <sys/dirent.h>
|
|
|
|
#include <miscfs/kernfs/kernfs.h>
|
|
|
|
|
|
|
|
#define KSTRING 256 /* Largest I/O available via this filesystem */
|
|
|
|
#define UIO_MX 32
|
|
|
|
|
|
|
|
#define READ_MODE (S_IRUSR|S_IRGRP|S_IROTH)
|
|
|
|
#define WRITE_MODE (S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)
|
|
|
|
#define DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
|
|
|
|
|
1995-10-29 15:33:36 +00:00
|
|
|
static struct kern_target {
|
1997-02-10 02:22:35 +00:00
|
|
|
u_char kt_type;
|
|
|
|
u_char kt_namlen;
|
1994-05-24 10:09:53 +00:00
|
|
|
char *kt_name;
|
|
|
|
void *kt_data;
|
1997-02-10 02:22:35 +00:00
|
|
|
#define KTT_NULL 1
|
|
|
|
#define KTT_TIME 5
|
|
|
|
#define KTT_INT 17
|
|
|
|
#define KTT_STRING 31
|
|
|
|
#define KTT_HOSTNAME 47
|
|
|
|
#define KTT_BOOTFILE 49
|
|
|
|
#define KTT_AVENRUN 53
|
|
|
|
#define KTT_DEVICE 71
|
|
|
|
u_char kt_tag;
|
|
|
|
u_char kt_vtype;
|
|
|
|
mode_t kt_mode;
|
1994-05-24 10:09:53 +00:00
|
|
|
} kern_targets[] = {
|
|
|
|
/* NOTE: The name must be less than UIO_MX-16 chars in length */
|
1997-02-10 02:22:35 +00:00
|
|
|
#define N(s) sizeof(s)-1, s
|
|
|
|
/* name data tag type ro/rw */
|
|
|
|
{ DT_DIR, N("."), 0, KTT_NULL, VDIR, DIR_MODE },
|
|
|
|
{ DT_DIR, N(".."), 0, KTT_NULL, VDIR, DIR_MODE },
|
|
|
|
{ DT_REG, N("boottime"), &boottime.tv_sec, KTT_INT, VREG, READ_MODE },
|
|
|
|
{ DT_REG, N("copyright"), copyright, KTT_STRING, VREG, READ_MODE },
|
|
|
|
{ DT_REG, N("hostname"), 0, KTT_HOSTNAME, VREG, WRITE_MODE },
|
|
|
|
{ DT_REG, N("bootfile"), 0, KTT_BOOTFILE, VREG, READ_MODE },
|
|
|
|
{ DT_REG, N("hz"), &hz, KTT_INT, VREG, READ_MODE },
|
|
|
|
{ DT_REG, N("loadavg"), 0, KTT_AVENRUN, VREG, READ_MODE },
|
|
|
|
{ DT_REG, N("pagesize"), &cnt.v_page_size, KTT_INT, VREG, READ_MODE },
|
|
|
|
{ DT_REG, N("physmem"), &physmem, KTT_INT, VREG, READ_MODE },
|
1994-05-24 10:09:53 +00:00
|
|
|
#if 0
|
1997-02-10 02:22:35 +00:00
|
|
|
{ DT_DIR, N("root"), 0, KTT_NULL, VDIR, DIR_MODE },
|
|
|
|
{ DT_BLK, N("rootdev"), &rootdev, KTT_DEVICE, VBLK, READ_MODE },
|
|
|
|
{ DT_CHR, N("rrootdev"), &rrootdev, KTT_DEVICE, VCHR, READ_MODE },
|
1996-07-03 03:48:46 +00:00
|
|
|
#endif
|
1997-02-10 02:22:35 +00:00
|
|
|
{ DT_REG, N("time"), 0, KTT_TIME, VREG, READ_MODE },
|
|
|
|
{ DT_REG, N("version"), version, KTT_STRING, VREG, READ_MODE },
|
|
|
|
#undef N
|
1994-05-24 10:09:53 +00:00
|
|
|
};
|
|
|
|
static int nkern_targets = sizeof(kern_targets) / sizeof(kern_targets[0]);
|
|
|
|
|
1995-12-03 14:54:48 +00:00
|
|
|
static int kernfs_access __P((struct vop_access_args *ap));
|
|
|
|
static int kernfs_badop __P((void));
|
|
|
|
static int kernfs_enotsupp __P((void));
|
|
|
|
static int kernfs_getattr __P((struct vop_getattr_args *ap));
|
|
|
|
static int kernfs_inactive __P((struct vop_inactive_args *ap));
|
|
|
|
static int kernfs_lookup __P((struct vop_lookup_args *ap));
|
|
|
|
static int kernfs_pathconf __P((struct vop_pathconf_args *ap));
|
|
|
|
static int kernfs_print __P((struct vop_print_args *ap));
|
|
|
|
static int kernfs_read __P((struct vop_read_args *ap));
|
|
|
|
static int kernfs_readdir __P((struct vop_readdir_args *ap));
|
|
|
|
static int kernfs_reclaim __P((struct vop_reclaim_args *ap));
|
|
|
|
static int kernfs_setattr __P((struct vop_setattr_args *ap));
|
|
|
|
static int kernfs_write __P((struct vop_write_args *ap));
|
|
|
|
static int kernfs_xread __P((struct kern_target *kt, char *buf, int len,
|
|
|
|
int *lenp));
|
|
|
|
static int kernfs_xwrite __P((struct kern_target *kt, char *buf, int len));
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
static int
|
|
|
|
kernfs_xread(kt, buf, len, lenp)
|
|
|
|
struct kern_target *kt;
|
|
|
|
char *buf;
|
|
|
|
int len;
|
|
|
|
int *lenp;
|
|
|
|
{
|
1997-02-10 02:22:35 +00:00
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
switch (kt->kt_tag) {
|
|
|
|
case KTT_TIME: {
|
|
|
|
struct timeval tv;
|
|
|
|
microtime(&tv);
|
1994-10-02 17:48:58 +00:00
|
|
|
sprintf(buf, "%ld %ld\n", tv.tv_sec, tv.tv_usec);
|
1994-05-24 10:09:53 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case KTT_INT: {
|
|
|
|
int *ip = kt->kt_data;
|
|
|
|
sprintf(buf, "%d\n", *ip);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case KTT_STRING: {
|
|
|
|
char *cp = kt->kt_data;
|
|
|
|
int xlen = strlen(cp) + 1;
|
|
|
|
|
|
|
|
if (xlen >= len)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
bcopy(cp, buf, xlen);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case KTT_HOSTNAME: {
|
|
|
|
char *cp = hostname;
|
1995-11-14 09:37:22 +00:00
|
|
|
int xlen = strlen(hostname);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
if (xlen >= (len-2))
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
bcopy(cp, buf, xlen);
|
|
|
|
buf[xlen] = '\n';
|
|
|
|
buf[xlen+1] = '\0';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
1994-11-15 20:30:56 +00:00
|
|
|
case KTT_BOOTFILE: {
|
|
|
|
char *cp = kernelname;
|
|
|
|
int xlen = strlen(cp) + 1;
|
|
|
|
|
|
|
|
if (xlen >= (len-2))
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
bcopy(cp, buf, xlen);
|
|
|
|
buf[xlen] = '\n';
|
|
|
|
buf[xlen+1] = '\0';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
case KTT_AVENRUN:
|
|
|
|
sprintf(buf, "%ld %ld %ld %ld\n",
|
1997-02-10 02:22:35 +00:00
|
|
|
averunnable.ldavg[0], averunnable.ldavg[1],
|
|
|
|
averunnable.ldavg[2], averunnable.fscale);
|
1994-05-24 10:09:53 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
1997-02-10 02:22:35 +00:00
|
|
|
return (EIO);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
*lenp = strlen(buf);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
kernfs_xwrite(kt, buf, len)
|
|
|
|
struct kern_target *kt;
|
|
|
|
char *buf;
|
|
|
|
int len;
|
|
|
|
{
|
1997-02-10 02:22:35 +00:00
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
switch (kt->kt_tag) {
|
1997-02-10 02:22:35 +00:00
|
|
|
case KTT_HOSTNAME:
|
1995-11-14 09:37:22 +00:00
|
|
|
/* XXX BOGUS !!! no check for the length */
|
1994-05-24 10:09:53 +00:00
|
|
|
if (buf[len-1] == '\n')
|
|
|
|
--len;
|
|
|
|
bcopy(buf, hostname, len);
|
|
|
|
hostname[len] = '\0';
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
default:
|
|
|
|
return (EIO);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* vp is the current namei directory
|
|
|
|
* ndp is the name to locate in that directory...
|
|
|
|
*/
|
1995-10-29 15:33:36 +00:00
|
|
|
static int
|
1994-05-24 10:09:53 +00:00
|
|
|
kernfs_lookup(ap)
|
|
|
|
struct vop_lookup_args /* {
|
|
|
|
struct vnode * a_dvp;
|
|
|
|
struct vnode ** a_vpp;
|
|
|
|
struct componentname * a_cnp;
|
|
|
|
} */ *ap;
|
|
|
|
{
|
1997-02-10 02:22:35 +00:00
|
|
|
struct componentname *cnp = ap->a_cnp;
|
1994-05-24 10:09:53 +00:00
|
|
|
struct vnode **vpp = ap->a_vpp;
|
|
|
|
struct vnode *dvp = ap->a_dvp;
|
1997-02-10 02:22:35 +00:00
|
|
|
char *pname = cnp->cn_nameptr;
|
|
|
|
struct proc *p = cnp->cn_proc;
|
|
|
|
struct kern_target *kt;
|
1994-05-24 10:09:53 +00:00
|
|
|
struct vnode *fvp;
|
1995-07-31 08:52:02 +00:00
|
|
|
int nameiop = cnp->cn_nameiop;
|
1994-05-24 10:09:53 +00:00
|
|
|
int error, i;
|
|
|
|
|
|
|
|
#ifdef KERNFS_DIAGNOSTIC
|
|
|
|
printf("kernfs_lookup(%x)\n", ap);
|
|
|
|
printf("kernfs_lookup(dp = %x, vpp = %x, cnp = %x)\n", dvp, vpp, ap->a_cnp);
|
|
|
|
printf("kernfs_lookup(%s)\n", pname);
|
|
|
|
#endif
|
1997-02-10 02:22:35 +00:00
|
|
|
|
|
|
|
*vpp = NULLVP;
|
|
|
|
|
|
|
|
if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
|
|
|
|
return (EROFS);
|
|
|
|
|
|
|
|
VOP_UNLOCK(dvp, 0, p);
|
1994-05-24 10:09:53 +00:00
|
|
|
if (cnp->cn_namelen == 1 && *pname == '.') {
|
|
|
|
*vpp = dvp;
|
|
|
|
VREF(dvp);
|
1997-02-10 02:22:35 +00:00
|
|
|
vn_lock(dvp, LK_SHARED | LK_RETRY, p);
|
1994-05-24 10:09:53 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
if (cnp->cn_namelen == 4 && bcmp(pname, "root", 4) == 0) {
|
|
|
|
*vpp = rootdir;
|
|
|
|
VREF(rootdir);
|
1997-02-10 02:22:35 +00:00
|
|
|
vn_lock(rootdir, LK_SHARED | LK_RETRY, p)
|
1994-05-24 10:09:53 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1997-02-10 02:22:35 +00:00
|
|
|
for (kt = kern_targets, i = 0; i < nkern_targets; kt++, i++) {
|
|
|
|
if (cnp->cn_namelen == kt->kt_namlen &&
|
|
|
|
bcmp(kt->kt_name, pname, cnp->cn_namelen) == 0)
|
|
|
|
goto found;
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef KERNFS_DIAGNOSTIC
|
1997-02-10 02:22:35 +00:00
|
|
|
printf("kernfs_lookup: i = %d, failed", i);
|
1994-05-24 10:09:53 +00:00
|
|
|
#endif
|
|
|
|
|
1997-02-10 02:22:35 +00:00
|
|
|
vn_lock(dvp, LK_SHARED | LK_RETRY, p);
|
|
|
|
return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS);
|
1995-07-31 08:52:02 +00:00
|
|
|
|
1997-02-10 02:22:35 +00:00
|
|
|
found:
|
|
|
|
if (kt->kt_tag == KTT_DEVICE) {
|
|
|
|
dev_t *dp = kt->kt_data;
|
|
|
|
loop:
|
|
|
|
if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp)) {
|
|
|
|
vn_lock(dvp, LK_SHARED | LK_RETRY, p);
|
|
|
|
return (ENOENT);
|
1995-07-31 08:52:02 +00:00
|
|
|
}
|
1997-02-10 02:22:35 +00:00
|
|
|
*vpp = fvp;
|
|
|
|
if (vget(fvp, LK_EXCLUSIVE, p))
|
|
|
|
goto loop;
|
|
|
|
return (0);
|
1995-07-31 08:52:02 +00:00
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
#ifdef KERNFS_DIAGNOSTIC
|
|
|
|
printf("kernfs_lookup: allocate new vnode\n");
|
|
|
|
#endif
|
1997-02-10 02:22:35 +00:00
|
|
|
if (error = getnewvnode(VT_KERNFS, dvp->v_mount, kernfs_vnodeop_p,
|
|
|
|
&fvp)) {
|
|
|
|
vn_lock(dvp, LK_SHARED | LK_RETRY, p);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
MALLOC(fvp->v_data, void *, sizeof(struct kernfs_node), M_TEMP,
|
|
|
|
M_WAITOK);
|
|
|
|
VTOKERN(fvp)->kf_kt = kt;
|
|
|
|
fvp->v_type = kt->kt_vtype;
|
|
|
|
vn_lock(fvp, LK_SHARED | LK_RETRY, p);
|
1994-05-24 10:09:53 +00:00
|
|
|
*vpp = fvp;
|
1997-02-10 02:22:35 +00:00
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
#ifdef KERNFS_DIAGNOSTIC
|
|
|
|
printf("kernfs_lookup: newvp = %x\n", fvp);
|
|
|
|
#endif
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
kernfs_access(ap)
|
|
|
|
struct vop_access_args /* {
|
|
|
|
struct vnode *a_vp;
|
|
|
|
int a_mode;
|
|
|
|
struct ucred *a_cred;
|
|
|
|
struct proc *a_p;
|
|
|
|
} */ *ap;
|
|
|
|
{
|
1997-02-10 02:22:35 +00:00
|
|
|
register struct vnode *vp = ap->a_vp;
|
|
|
|
register struct ucred *cred = ap->a_cred;
|
|
|
|
mode_t amode = ap->a_mode;
|
|
|
|
mode_t fmode =
|
|
|
|
(vp->v_flag & VROOT) ? DIR_MODE : VTOKERN(vp)->kf_kt->kt_mode;
|
|
|
|
mode_t mask = 0;
|
|
|
|
register gid_t *gp;
|
|
|
|
int i;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
1997-02-10 02:22:35 +00:00
|
|
|
/* Some files are simply not modifiable. */
|
|
|
|
if ((amode & VWRITE) && (fmode & (S_IWUSR|S_IWGRP|S_IWOTH)) == 0)
|
|
|
|
return (EPERM);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
1997-02-10 02:22:35 +00:00
|
|
|
/* Root can do anything else. */
|
|
|
|
if (cred->cr_uid == 0)
|
1994-05-24 10:09:53 +00:00
|
|
|
return (0);
|
|
|
|
|
1997-02-10 02:22:35 +00:00
|
|
|
/* Check for group 0 (wheel) permissions. */
|
|
|
|
for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
|
|
|
|
if (*gp == 0) {
|
|
|
|
if (amode & VEXEC)
|
|
|
|
mask |= S_IXGRP;
|
|
|
|
if (amode & VREAD)
|
|
|
|
mask |= S_IRGRP;
|
|
|
|
if (amode & VWRITE)
|
|
|
|
mask |= S_IWGRP;
|
|
|
|
return ((fmode & mask) == mask ? 0 : EACCES);
|
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
|
1997-02-10 02:22:35 +00:00
|
|
|
/* Otherwise, check everyone else. */
|
|
|
|
if (amode & VEXEC)
|
|
|
|
mask |= S_IXOTH;
|
|
|
|
if (amode & VREAD)
|
|
|
|
mask |= S_IROTH;
|
|
|
|
if (amode & VWRITE)
|
|
|
|
mask |= S_IWOTH;
|
|
|
|
return ((fmode & mask) == mask ? 0 : EACCES);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
1995-10-29 15:33:36 +00:00
|
|
|
static int
|
1994-05-24 10:09:53 +00:00
|
|
|
kernfs_getattr(ap)
|
|
|
|
struct vop_getattr_args /* {
|
|
|
|
struct vnode *a_vp;
|
|
|
|
struct vattr *a_vap;
|
|
|
|
struct ucred *a_cred;
|
|
|
|
struct proc *a_p;
|
|
|
|
} */ *ap;
|
|
|
|
{
|
|
|
|
struct vnode *vp = ap->a_vp;
|
|
|
|
struct vattr *vap = ap->a_vap;
|
1997-02-10 02:22:35 +00:00
|
|
|
struct timeval tv;
|
1994-05-24 10:09:53 +00:00
|
|
|
int error = 0;
|
|
|
|
char strbuf[KSTRING];
|
|
|
|
|
|
|
|
bzero((caddr_t) vap, sizeof(*vap));
|
|
|
|
vattr_null(vap);
|
|
|
|
vap->va_uid = 0;
|
|
|
|
vap->va_gid = 0;
|
|
|
|
vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
|
1997-02-10 02:22:35 +00:00
|
|
|
vap->va_size = 0;
|
1994-05-24 10:09:53 +00:00
|
|
|
vap->va_blocksize = DEV_BSIZE;
|
1994-08-18 22:36:09 +00:00
|
|
|
{
|
|
|
|
struct timeval tv;
|
|
|
|
microtime(&tv);
|
|
|
|
TIMEVAL_TO_TIMESPEC(&tv, &vap->va_atime);
|
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
vap->va_mtime = vap->va_atime;
|
|
|
|
vap->va_ctime = vap->va_ctime;
|
|
|
|
vap->va_gen = 0;
|
|
|
|
vap->va_flags = 0;
|
|
|
|
vap->va_rdev = 0;
|
|
|
|
vap->va_bytes = 0;
|
|
|
|
|
|
|
|
if (vp->v_flag & VROOT) {
|
|
|
|
#ifdef KERNFS_DIAGNOSTIC
|
|
|
|
printf("kernfs_getattr: stat rootdir\n");
|
|
|
|
#endif
|
|
|
|
vap->va_type = VDIR;
|
|
|
|
vap->va_mode = DIR_MODE;
|
|
|
|
vap->va_nlink = 2;
|
|
|
|
vap->va_fileid = 2;
|
|
|
|
vap->va_size = DEV_BSIZE;
|
|
|
|
} else {
|
|
|
|
struct kern_target *kt = VTOKERN(vp)->kf_kt;
|
|
|
|
int nbytes;
|
|
|
|
#ifdef KERNFS_DIAGNOSTIC
|
|
|
|
printf("kernfs_getattr: stat target %s\n", kt->kt_name);
|
|
|
|
#endif
|
|
|
|
vap->va_type = kt->kt_vtype;
|
1997-02-10 02:22:35 +00:00
|
|
|
vap->va_mode = kt->kt_mode;
|
1994-05-24 10:09:53 +00:00
|
|
|
vap->va_nlink = 1;
|
1997-02-10 02:22:35 +00:00
|
|
|
vap->va_fileid = 1 + (kt - kern_targets) / sizeof(*kt);
|
1994-05-24 10:09:53 +00:00
|
|
|
error = kernfs_xread(kt, strbuf, sizeof(strbuf), &nbytes);
|
|
|
|
vap->va_size = nbytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef KERNFS_DIAGNOSTIC
|
|
|
|
printf("kernfs_getattr: return error %d\n", error);
|
|
|
|
#endif
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
1995-10-29 15:33:36 +00:00
|
|
|
static int
|
1994-05-24 10:09:53 +00:00
|
|
|
kernfs_setattr(ap)
|
|
|
|
struct vop_setattr_args /* {
|
|
|
|
struct vnode *a_vp;
|
|
|
|
struct vattr *a_vap;
|
|
|
|
struct ucred *a_cred;
|
|
|
|
struct proc *a_p;
|
|
|
|
} */ *ap;
|
|
|
|
{
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Silently ignore attribute changes.
|
|
|
|
* This allows for open with truncate to have no
|
|
|
|
* effect until some data is written. I want to
|
|
|
|
* do it this way because all writes are atomic.
|
|
|
|
*/
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
kernfs_read(ap)
|
|
|
|
struct vop_read_args /* {
|
|
|
|
struct vnode *a_vp;
|
|
|
|
struct uio *a_uio;
|
|
|
|
int a_ioflag;
|
|
|
|
struct ucred *a_cred;
|
|
|
|
} */ *ap;
|
|
|
|
{
|
|
|
|
struct vnode *vp = ap->a_vp;
|
|
|
|
struct uio *uio = ap->a_uio;
|
|
|
|
struct kern_target *kt;
|
|
|
|
char strbuf[KSTRING];
|
|
|
|
int off = uio->uio_offset;
|
|
|
|
int error, len;
|
|
|
|
char *cp;
|
|
|
|
|
1997-02-10 02:22:35 +00:00
|
|
|
if (vp->v_type == VDIR)
|
1994-05-24 10:09:53 +00:00
|
|
|
return (EOPNOTSUPP);
|
|
|
|
|
|
|
|
kt = VTOKERN(vp)->kf_kt;
|
|
|
|
|
|
|
|
#ifdef KERNFS_DIAGNOSTIC
|
|
|
|
printf("kern_read %s\n", kt->kt_name);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
len = 0;
|
1997-02-10 02:22:35 +00:00
|
|
|
if (error = kernfs_xread(kt, strbuf, sizeof(strbuf), &len))
|
1994-05-24 10:09:53 +00:00
|
|
|
return (error);
|
1997-02-10 02:22:35 +00:00
|
|
|
if (len <= off)
|
|
|
|
return (0);
|
|
|
|
return (uiomove(&strbuf[off], len - off, uio));
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
kernfs_write(ap)
|
|
|
|
struct vop_write_args /* {
|
|
|
|
struct vnode *a_vp;
|
|
|
|
struct uio *a_uio;
|
|
|
|
int a_ioflag;
|
|
|
|
struct ucred *a_cred;
|
|
|
|
} */ *ap;
|
|
|
|
{
|
|
|
|
struct vnode *vp = ap->a_vp;
|
|
|
|
struct uio *uio = ap->a_uio;
|
|
|
|
struct kern_target *kt;
|
|
|
|
int error, xlen;
|
|
|
|
char strbuf[KSTRING];
|
|
|
|
|
1997-02-10 02:22:35 +00:00
|
|
|
if (vp->v_type == VDIR)
|
|
|
|
return (EOPNOTSUPP);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
kt = VTOKERN(vp)->kf_kt;
|
|
|
|
|
|
|
|
if (uio->uio_offset != 0)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
xlen = min(uio->uio_resid, KSTRING-1);
|
1997-02-10 02:22:35 +00:00
|
|
|
if (error = uiomove(strbuf, xlen, uio))
|
1994-05-24 10:09:53 +00:00
|
|
|
return (error);
|
|
|
|
|
|
|
|
if (uio->uio_resid != 0)
|
|
|
|
return (EIO);
|
|
|
|
|
|
|
|
strbuf[xlen] = '\0';
|
|
|
|
xlen = strlen(strbuf);
|
|
|
|
return (kernfs_xwrite(kt, strbuf, xlen));
|
|
|
|
}
|
|
|
|
|
1995-10-29 15:33:36 +00:00
|
|
|
static int
|
1994-05-24 10:09:53 +00:00
|
|
|
kernfs_readdir(ap)
|
|
|
|
struct vop_readdir_args /* {
|
|
|
|
struct vnode *a_vp;
|
|
|
|
struct uio *a_uio;
|
|
|
|
struct ucred *a_cred;
|
1997-02-10 02:22:35 +00:00
|
|
|
int *a_eofflag;
|
|
|
|
u_long *a_cookies;
|
|
|
|
int a_ncookies;
|
1994-05-24 10:09:53 +00:00
|
|
|
} */ *ap;
|
|
|
|
{
|
1997-02-10 02:22:35 +00:00
|
|
|
int error, i;
|
1994-05-24 10:09:53 +00:00
|
|
|
struct uio *uio = ap->a_uio;
|
1997-02-10 02:22:35 +00:00
|
|
|
struct kern_target *kt;
|
|
|
|
struct dirent d;
|
|
|
|
|
|
|
|
if (ap->a_vp->v_type != VDIR)
|
|
|
|
return (ENOTDIR);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We don't allow exporting kernfs mounts, and currently local
|
|
|
|
* requests do not need cookies.
|
|
|
|
*/
|
|
|
|
if (ap->a_ncookies != NULL)
|
|
|
|
panic("kernfs_readdir: not hungry");
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
i = uio->uio_offset / UIO_MX;
|
|
|
|
error = 0;
|
1997-02-10 02:22:35 +00:00
|
|
|
for (kt = &kern_targets[i];
|
|
|
|
uio->uio_resid >= UIO_MX && i < nkern_targets; kt++, i++) {
|
1994-05-24 10:09:53 +00:00
|
|
|
struct dirent *dp = &d;
|
|
|
|
#ifdef KERNFS_DIAGNOSTIC
|
|
|
|
printf("kernfs_readdir: i = %d\n", i);
|
|
|
|
#endif
|
|
|
|
|
1997-02-10 02:22:35 +00:00
|
|
|
if (kt->kt_tag == KTT_DEVICE) {
|
|
|
|
dev_t *dp = kt->kt_data;
|
|
|
|
struct vnode *fvp;
|
|
|
|
|
|
|
|
if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp))
|
|
|
|
continue;
|
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
|
1997-02-10 02:22:35 +00:00
|
|
|
bzero((caddr_t)dp, UIO_MX);
|
|
|
|
dp->d_namlen = kt->kt_namlen;
|
|
|
|
bcopy(kt->kt_name, dp->d_name, kt->kt_namlen+1);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
#ifdef KERNFS_DIAGNOSTIC
|
|
|
|
printf("kernfs_readdir: name = %s, len = %d\n",
|
|
|
|
dp->d_name, dp->d_namlen);
|
|
|
|
#endif
|
|
|
|
/*
|
|
|
|
* Fill in the remaining fields
|
|
|
|
*/
|
|
|
|
dp->d_reclen = UIO_MX;
|
|
|
|
dp->d_fileno = i + 3;
|
1997-02-10 02:22:35 +00:00
|
|
|
dp->d_type = kt->kt_type;
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* And ship to userland
|
|
|
|
*/
|
1997-02-10 02:22:35 +00:00
|
|
|
if (error = uiomove((caddr_t)dp, UIO_MX, uio))
|
1994-05-24 10:09:53 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
uio->uio_offset = i * UIO_MX;
|
|
|
|
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
1995-10-29 15:33:36 +00:00
|
|
|
static int
|
1994-05-24 10:09:53 +00:00
|
|
|
kernfs_inactive(ap)
|
|
|
|
struct vop_inactive_args /* {
|
|
|
|
struct vnode *a_vp;
|
1997-02-10 02:22:35 +00:00
|
|
|
struct proc *a_p;
|
1994-05-24 10:09:53 +00:00
|
|
|
} */ *ap;
|
|
|
|
{
|
|
|
|
struct vnode *vp = ap->a_vp;
|
|
|
|
|
1997-02-10 02:22:35 +00:00
|
|
|
#ifdef KERNFS_DIAGNOSTIC
|
|
|
|
printf("kernfs_inactive(%x)\n", vp);
|
|
|
|
#endif
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* Clear out the v_type field to avoid
|
|
|
|
* nasty things happening in vgone().
|
|
|
|
*/
|
1997-02-10 02:22:35 +00:00
|
|
|
VOP_UNLOCK(vp, 0, ap->a_p);
|
1994-05-24 10:09:53 +00:00
|
|
|
vp->v_type = VNON;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
1995-10-29 15:33:36 +00:00
|
|
|
static int
|
1994-05-24 10:09:53 +00:00
|
|
|
kernfs_reclaim(ap)
|
|
|
|
struct vop_reclaim_args /* {
|
|
|
|
struct vnode *a_vp;
|
|
|
|
} */ *ap;
|
|
|
|
{
|
|
|
|
struct vnode *vp = ap->a_vp;
|
1997-02-10 02:22:35 +00:00
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
#ifdef KERNFS_DIAGNOSTIC
|
|
|
|
printf("kernfs_reclaim(%x)\n", vp);
|
|
|
|
#endif
|
|
|
|
if (vp->v_data) {
|
|
|
|
FREE(vp->v_data, M_TEMP);
|
|
|
|
vp->v_data = 0;
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
1995-07-31 09:52:21 +00:00
|
|
|
* Print out the contents of a kernfs vnode.
|
1994-05-24 10:09:53 +00:00
|
|
|
*/
|
|
|
|
/* ARGSUSED */
|
1995-10-29 15:33:36 +00:00
|
|
|
static int
|
1994-05-24 10:09:53 +00:00
|
|
|
kernfs_print(ap)
|
|
|
|
struct vop_print_args /* {
|
|
|
|
struct vnode *a_vp;
|
|
|
|
} */ *ap;
|
|
|
|
{
|
|
|
|
|
|
|
|
printf("tag VT_KERNFS, kernfs vnode\n");
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1995-07-31 09:52:21 +00:00
|
|
|
* Kernfs "should never get here" operation
|
1994-05-24 10:09:53 +00:00
|
|
|
*/
|
1995-10-29 15:33:36 +00:00
|
|
|
static int
|
1994-05-24 10:09:53 +00:00
|
|
|
kernfs_badop()
|
|
|
|
{
|
1995-05-25 01:35:24 +00:00
|
|
|
return (EIO);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1997-02-10 02:22:35 +00:00
|
|
|
vop_t **kernfs_vnodeop_p;
|
1995-10-29 15:33:36 +00:00
|
|
|
static struct vnodeopv_entry_desc kernfs_vnodeop_entries[] = {
|
1997-10-26 20:55:39 +00:00
|
|
|
{ &vop_default_desc, (vop_t *) vop_defaultop },
|
1997-10-15 09:22:02 +00:00
|
|
|
{ &vop_access_desc, (vop_t *) kernfs_access },
|
VFS mega cleanup commit (x/N)
1. Add new file "sys/kern/vfs_default.c" where default actions for
VOPs go. Implement proper defaults for ABORTOP, BWRITE, LEASE,
POLL, REVOKE and STRATEGY. Various stuff spread over the entire
tree belongs here.
2. Change VOP_BLKATOFF to a normal function in cd9660.
3. Kill VOP_BLKATOFF, VOP_TRUNCATE, VOP_VFREE, VOP_VALLOC. These
are private interface functions between UFS and the underlying
storage manager layer (FFS/LFS/MFS/EXT2FS). The functions now
live in struct ufsmount instead.
4. Remove a kludge of VOP_ functions in all filesystems, that did
nothing but obscure the simplicity and break the expandability.
If a filesystem doesn't implement VOP_FOO, it shouldn't have an
entry for it in its vnops table. The system will try to DTRT
if it is not implemented. There are still some cruft left, but
the bulk of it is done.
5. Fix another VCALL in vfs_cache.c (thanks Bruce!)
1997-10-16 10:50:27 +00:00
|
|
|
{ &vop_bmap_desc, (vop_t *) kernfs_badop },
|
1997-10-15 09:22:02 +00:00
|
|
|
{ &vop_getattr_desc, (vop_t *) kernfs_getattr },
|
1997-10-15 10:05:29 +00:00
|
|
|
{ &vop_inactive_desc, (vop_t *) kernfs_inactive },
|
1997-10-15 09:22:02 +00:00
|
|
|
{ &vop_lookup_desc, (vop_t *) kernfs_lookup },
|
1997-10-16 20:32:40 +00:00
|
|
|
{ &vop_pathconf_desc, (vop_t *) vop_stdpathconf },
|
1997-10-15 09:22:02 +00:00
|
|
|
{ &vop_print_desc, (vop_t *) kernfs_print },
|
|
|
|
{ &vop_read_desc, (vop_t *) kernfs_read },
|
|
|
|
{ &vop_readdir_desc, (vop_t *) kernfs_readdir },
|
|
|
|
{ &vop_reclaim_desc, (vop_t *) kernfs_reclaim },
|
|
|
|
{ &vop_setattr_desc, (vop_t *) kernfs_setattr },
|
|
|
|
{ &vop_write_desc, (vop_t *) kernfs_write },
|
1995-11-09 08:17:23 +00:00
|
|
|
{ NULL, NULL }
|
1994-05-24 10:09:53 +00:00
|
|
|
};
|
1995-10-29 15:33:36 +00:00
|
|
|
static struct vnodeopv_desc kernfs_vnodeop_opv_desc =
|
1994-05-24 10:09:53 +00:00
|
|
|
{ &kernfs_vnodeop_p, kernfs_vnodeop_entries };
|
1994-09-21 03:47:43 +00:00
|
|
|
|
|
|
|
VNODEOP_SET(kernfs_vnodeop_opv_desc);
|