Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/miscfs/kernfs/kernfs_vnops.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/miscfs/kernfs/kernfs_vnops.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.16 retrieving revision 1.22 diff -u -p -r1.16 -r1.22 --- src/sys/miscfs/kernfs/kernfs_vnops.c 1993/12/22 13:14:10 1.16 +++ src/sys/miscfs/kernfs/kernfs_vnops.c 1994/05/17 06:59:17 1.22 @@ -1,8 +1,9 @@ /* + * Copyright (c) 1992 The Regents of the University of California * Copyright (c) 1990, 1992 Jan-Simon Pendry * All rights reserved. * - * This code is derived from software contributed to Berkeley by + * This code is derived from software donated to Berkeley by * Jan-Simon Pendry. * * Redistribution and use in source and binary forms, with or without @@ -15,8 +16,8 @@ * 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. + * 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. @@ -33,7 +34,10 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: kernfs_vnops.c,v 1.16 1993/12/22 13:14:10 cgd Exp $ + * From: + * Id: kernfs_vnops.c,v 4.1 1994/01/02 14:41:30 jsp Exp + * + * $Id: kernfs_vnops.c,v 1.22 1994/05/17 06:59:17 mycroft Exp $ */ /* @@ -52,34 +56,59 @@ #include #include #include +#include #include /* For readdir() XXX */ -#include +#define KSTRING 256 /* Largest I/O available via this filesystem */ +#define UIO_MX 32 -struct kernfs_target kernfs_targets[] = { +struct kern_target { + char *kt_name; + void *kt_data; +#define KTT_NULL 1 +#define KTT_TIME 5 +#define KTT_INT 17 +#define KTT_STRING 31 +#define KTT_HOSTNAME 47 +#define KTT_AVENRUN 53 + int kt_tag; +#define KTM_RO 0 +#define KTM_RO_MODE \ + ((VREAD) | (VREAD >> 3) | (VREAD >> 6)) +#define KTM_RW 43 +#define KTM_RW_MODE \ + ((VWRITE) | KTM_RO_MODE) +#define KTM_DIR_MODE \ + ((VREAD|VEXEC) | ((VREAD|VEXEC) >> 3) | ((VREAD|VEXEC) >> 6)) + int kt_rw; + enum vtype kt_vtype; +} kern_targets[] = { /* NOTE: The name must be less than UIO_MX-16 chars in length */ -DIR_TARGET(".", 0, KTT_NULL, KTM_DIR_PERMS ) -DIR_TARGET("..", 0, KTT_NULL, KTM_DIR_PERMS ) -REG_TARGET("copyright", copyright, KTT_STRING, KTM_RO_PERMS ) -REG_TARGET("hostname", 0, KTT_HOSTNAME, KTM_RW_PERMS ) -REG_TARGET("hz", &hz, KTT_INT, KTM_RO_PERMS ) -REG_TARGET("loadavg", 0, KTT_AVENRUN, KTM_RO_PERMS ) -REG_TARGET("physmem", &physmem, KTT_INT, KTM_RO_PERMS ) -#ifdef KERNFS_HAVE_ROOTDIR -DIR_TARGET("root", 0, KTT_NULL, KTM_DIR_PERMS ) -#endif -BLK_TARGET("rootdev", 0, KTT_NULL, KTM_RO_PERMS ) -CHR_TARGET("rrootdev", 0, KTT_NULL, KTM_RO_PERMS ) -REG_TARGET("time", 0, KTT_TIME, KTM_RO_PERMS ) -REG_TARGET("version", version, KTT_STRING, KTM_RO_PERMS ) + /* name data tag ro/rw */ + { ".", 0, KTT_NULL, KTM_RO, VDIR }, + { "..", 0, KTT_NULL, KTM_RO, VDIR }, + { "copyright", copyright, KTT_STRING, KTM_RO, VREG }, + { "hostname", 0, KTT_HOSTNAME, KTM_RW, VREG }, + { "hz", &hz, KTT_INT, KTM_RO, VREG }, + { "loadavg", 0, KTT_AVENRUN, KTM_RO, VREG }, + { "physmem", &physmem, KTT_INT, KTM_RO, VREG }, +#if 0 + { "root", 0, KTT_NULL, KTM_RO, VDIR }, +#endif + { "rootdev", 0, KTT_NULL, KTM_RO, VBLK }, +#ifdef notdef + { "rrootdev", 0, KTT_NULL, KTM_RO, VCHR }, +#endif + { "time", 0, KTT_TIME, KTM_RO, VREG }, + { "version", version, KTT_STRING, KTM_RO, VREG }, }; -static int nkernfs_targets = sizeof(kernfs_targets) / sizeof(kernfs_targets[0]); +static int nkern_targets = sizeof(kern_targets) / sizeof(kern_targets[0]); static int kernfs_xread(kt, buf, len, lenp) - struct kernfs_target *kt; + struct kern_target *kt; char *buf; int len; int *lenp; @@ -115,10 +144,10 @@ kernfs_xread(kt, buf, len, lenp) char *cp = hostname; int xlen = hostnamelen; - if (xlen + 2 > len) /* extra space for null and newline */ + if (xlen >= (len-2)) return (EINVAL); - bcopy(cp, buf, xlen); /* safer than sprintf */ + bcopy(cp, buf, xlen); buf[xlen] = '\n'; buf[xlen+1] = '\0'; break; @@ -126,10 +155,10 @@ kernfs_xread(kt, buf, len, lenp) case KTT_AVENRUN: sprintf(buf, "%d %d %d %d\n", - averunnable.ldavg[0], - averunnable.ldavg[1], - averunnable.ldavg[2], - FSCALE); + averunnable.ldavg[0], + averunnable.ldavg[1], + averunnable.ldavg[2], + averunnable.fscale); break; default: @@ -142,7 +171,7 @@ kernfs_xread(kt, buf, len, lenp) static int kernfs_xwrite(kt, buf, len) - struct kernfs_target *kt; + struct kern_target *kt; char *buf; int len; { @@ -151,11 +180,8 @@ kernfs_xwrite(kt, buf, len) if (buf[len-1] == '\n') --len; bcopy(buf, hostname, len); - /* kernfs_write set buf[value_passed_as_len] = \0. - * therefore, buf len (hostnamelen) = len. - */ + hostname[len] = '\0'; hostnamelen = len; - hostname[hostnamelen] = '\0'; /* null end of string. */ return (0); } @@ -165,6 +191,64 @@ kernfs_xwrite(kt, buf, len) } /* + * implement access checking. + * + * something very similar to this code is duplicated + * throughout the 4bsd kernel and should be moved + * into kern/vfs_subr.c sometime. + * + * actually, the check for super-user is slightly + * broken since it will allow read access to write-only + * objects. this doesn't cause any particular trouble + * but does mean that the i/o entry points need to check + * that the operation really does make sense. + */ +kernfs_access(vp, mode, cred, p) + struct vnode *vp; + int mode; + struct ucred *cred; + struct proc *p; +{ + struct vattr *vap; + struct vattr vattr; + int error; + + /* + * If you're the super-user, + * you always get access. + */ + if (cred->cr_uid == (uid_t) 0) + return (0); + vap = &vattr; + if (error = VOP_GETATTR(vp, vap, cred, p)) + return (error); + + /* + * Access check is based on only one of owner, group, public. + * If not owner, then check group. If not a member of the + * group, then check public access. + */ + if (cred->cr_uid != vap->va_uid) { + gid_t *gp; + int i; + + mode >>= 3; + gp = cred->cr_groups; + for (i = 0; i < cred->cr_ngroups; i++, gp++) + if (vap->va_gid == *gp) + goto found; + mode >>= 3; +found: + ; + } + + if ((vap->va_mode & mode) == mode) + return (0); + + return (EACCES); +} + +/* * vp is the current namei directory * ndp is the name to locate in that directory... */ @@ -189,48 +273,32 @@ kernfs_lookup(dvp, ndp, p) return (0); } -#ifdef KERNFS_HAVE_ROOTDIR +#if 0 if (ndp->ni_namelen == 4 && bcmp(pname, "root", 4) == 0) { - ndp->ni_dvp = dvp; + ndp->ni_dvp = rootdir; ndp->ni_vp = rootdir; VREF(rootdir); + VREF(rootdir); VOP_LOCK(rootdir); return (0); } #endif - + /* * /kern/rootdev is the root device */ if (ndp->ni_namelen == 7 && bcmp(pname, "rootdev", 7) == 0) { - if (!rootvp) { - error = ENOENT; - goto bad; - } - ndp->ni_dvp = dvp; - ndp->ni_vp = rootvp; - VREF(rootvp); - VOP_LOCK(rootvp); - return (0); - } - - /* - * /kern/rrootdev is the raw root device - */ - if (ndp->ni_namelen == 8 && bcmp(pname, "rrootdev", 7) == 0) { - if (!rrootdevvp) { - error = ENOENT; - goto bad; - } + if (vfinddev(rootdev, VBLK, &fvp)) + return (ENXIO); ndp->ni_dvp = dvp; - ndp->ni_vp = rrootdevvp; - VREF(rrootdevvp); - VOP_LOCK(rrootdevvp); + ndp->ni_vp = fvp; + VREF(fvp); + VOP_LOCK(fvp); return (0); } - for (i = 0; i < nkernfs_targets; i++) { - struct kernfs_target *kt = &kernfs_targets[i]; + for (i = 0; i < nkern_targets; i++) { + struct kern_target *kt = &kern_targets[i]; if (ndp->ni_namelen == strlen(kt->kt_name) && bcmp(kt->kt_name, pname, ndp->ni_namelen) == 0) { error = 0; @@ -251,7 +319,7 @@ kernfs_lookup(dvp, ndp, p) error = getnewvnode(VT_KERNFS, dvp->v_mount, &kernfs_vnodeops, &fvp); if (error) goto bad; - VTOKERN(fvp)->kf_kt = &kernfs_targets[i]; + VTOKERN(fvp)->kf_kt = &kern_targets[i]; fvp->v_type = VTOKERN(fvp)->kf_kt->kt_vtype; ndp->ni_dvp = dvp; ndp->ni_vp = fvp; @@ -275,55 +343,31 @@ kernfs_open(vp, mode, cred, p) struct ucred *cred; struct proc *p; { - /* if access succeeded, this always does, too */ - - return (0); -} + int error; + struct filedesc *fdp; + struct file *fp; + int dfd; + int fd; -/* - * Check mode permission on target pointer. Mode is READ, WRITE or EXEC. - * The mode is shifted to select the owner/group/other fields. The - * super user is granted all permissions. - */ -kernfs_access(vp, mode, cred, p) - struct vnode *vp; - register int mode; - struct ucred *cred; - struct proc *p; -{ - struct kernfs_target *kt = VTOKERN(vp)->kf_kt; - register gid_t *gp; - int i, error; - -#ifdef KERN_DIAGNOSTIC - if (!VOP_ISLOCKED(vp)) { - vprint("kernfs_access: not locked", vp); - panic("kernfs_access: not locked"); - } +#ifdef KERNFS_DIAGNOSTIC + printf("kernfs_open\n"); #endif + /* - * If you're the super-user, you always get access. - */ - if (cred->cr_uid == 0) - return (0); - /* - * Access check is based on only one of owner, group, public. - * If not owner, then check group. If not a member of the - * group, then check public access. + * Can always open the root (modulo perms) */ - if (cred->cr_uid != /* kt->kt_uid XXX */ 0) { - mode >>= 3; - gp = cred->cr_groups; - for (i = 0; i < cred->cr_ngroups; i++, gp++) - if (/* kt->kt_gid XXX */ 0 == *gp) - goto found; - mode >>= 3; -found: - ; - } - if ((kt->kt_perms & mode) == mode) + if (vp->v_flag & VROOT) return (0); - return (EACCES); + +#ifdef KERNFS_DIAGNOSTIC + printf("kernfs_open, mode = %x, file = %s\n", + mode, VTOKERN(vp)->kf_kt->kt_name); +#endif + + if ((mode & FWRITE) && VTOKERN(vp)->kf_kt->kt_rw != KTM_RW) + return (EACCES); + + return (0); } kernfs_getattr(vp, vap, cred, p) @@ -334,14 +378,13 @@ kernfs_getattr(vp, vap, cred, p) { int error = 0; char strbuf[KSTRING]; - struct kernfs_target *kt = VTOKERN(vp)->kf_kt; + struct kern_target *kt = VTOKERN(vp)->kf_kt; bzero((caddr_t) vap, sizeof(*vap)); vattr_null(vap); - vap->va_uid = kt->kt_uid; - vap->va_gid = kt->kt_gid; + vap->va_uid = 0; + vap->va_gid = 0; vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; - /* vap->va_qsize = 0; */ vap->va_blocksize = DEV_BSIZE; microtime(&vap->va_atime); vap->va_mtime = vap->va_atime; @@ -349,25 +392,28 @@ kernfs_getattr(vp, vap, cred, p) vap->va_gen = 0; vap->va_flags = 0; vap->va_rdev = 0; - /* vap->va_qbytes = 0; */ vap->va_bytes = 0; - vap->va_type = kt->kt_vtype; - vap->va_mode = kt->kt_perms; if (vp->v_flag & VROOT) { #ifdef KERNFS_DIAGNOSTIC printf("kernfs_getattr: stat rootdir\n"); #endif + vap->va_type = VDIR; + vap->va_mode = KTM_DIR_MODE; vap->va_nlink = 2; vap->va_fileid = 2; vap->va_size = DEV_BSIZE; } else { + int nbytes; #ifdef KERNFS_DIAGNOSTIC printf("kernfs_getattr: stat target %s\n", kt->kt_name); #endif + vap->va_type = kt->kt_vtype; + vap->va_mode = (kt->kt_rw ? KTM_RW_MODE : KTM_RO_MODE); vap->va_nlink = 1; - vap->va_fileid = 3 + (kt - kernfs_targets) / sizeof(*kt); - error = kernfs_xread(kt, strbuf, sizeof(strbuf), &vap->va_size); + vap->va_fileid = 3 + (kt - kern_targets) / sizeof(*kt); + error = kernfs_xread(kt, strbuf, sizeof(strbuf), &nbytes); + vap->va_size = nbytes; } vp->v_type = vap->va_type; @@ -377,140 +423,20 @@ kernfs_getattr(vp, vap, cred, p) return (error); } - -/* - * Change the mode on a file. - */ -kernfs_chmod1(vp, mode, p) - register struct vnode *vp; - register int mode; - struct proc *p; -{ - register struct ucred *cred = p->p_ucred; - register struct kernfs_target *kt = VTOKERN(vp)->kf_kt; - int error; - - if ((mode & kt->kt_maxperms) != mode) /* can't set ro var to rw */ - return (EPERM); - - if (cred->cr_uid != kt->kt_uid && - (error = suser(cred, &p->p_acflag))) - return (error); - if (cred->cr_uid) { - if (vp->v_type != VDIR && (mode & S_ISVTX)) - return (EFTYPE); - if (!groupmember(kt->kt_gid, cred) && (mode & S_ISGID)) - return (EPERM); - } - kt->kt_perms &= ~07777; - kt->kt_perms |= mode & 07777; -/* ip->i_flag |= ICHG;*/ - return (0); -} - -/* - * Perform chown operation on kernfs_target kt - */ -kernfs_chown1(vp, uid, gid, p) - register struct vnode *vp; - uid_t uid; - gid_t gid; - struct proc *p; -{ - register struct kernfs_target *kt = VTOKERN(vp)->kf_kt; - register struct ucred *cred = p->p_ucred; - uid_t ouid; - gid_t ogid; - int error = 0; - - if (uid == (u_short)VNOVAL) - uid = kt->kt_uid; - if (gid == (u_short)VNOVAL) - gid = kt->kt_gid; - /* - * If we don't own the file, are trying to change the owner - * of the file, or are not a member of the target group, - * the caller must be superuser or the call fails. - */ - if ((cred->cr_uid != kt->kt_uid || uid != kt->kt_uid || - !groupmember((gid_t)gid, cred)) && - (error = suser(cred, &p->p_acflag))) - return (error); - ouid = kt->kt_uid; - ogid = kt->kt_gid; - - kt->kt_uid = uid; - kt->kt_gid = gid; - -/* if (ouid != uid || ogid != gid) - ip->i_flag |= ICHG;*/ - if (ouid != uid && cred->cr_uid != 0) - kt->kt_perms &= ~S_ISUID; - if (ogid != gid && cred->cr_uid != 0) - kt->kt_perms &= ~S_ISGID; - return (0); -} - -/* - * Set attribute vnode op. called from several syscalls - */ kernfs_setattr(vp, vap, cred, p) struct vnode *vp; struct vattr *vap; struct ucred *cred; struct proc *p; { - int error = 0; /* - * Check for unsetable attributes. - */ - if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || - (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || - (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || - ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { - return (EINVAL); - } - /* - * Go through the fields and update iff not VNOVAL. + * 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. */ - if (vap->va_uid != (u_short)VNOVAL || vap->va_gid != (u_short)VNOVAL) - if (error = kernfs_chown1(vp, vap->va_uid, vap->va_gid, p)) - return (error); - if (vap->va_size != VNOVAL) { - if (vp->v_type == VDIR) - return (EISDIR); - /* else just nod and smile... */ - } - if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { -/* if (cred->cr_uid != ip->i_uid && - (error = suser(cred, &p->p_acflag))) - return (error); - if (vap->va_atime.tv_sec != VNOVAL) - ip->i_flag |= IACC; - if (vap->va_mtime.tv_sec != VNOVAL) - ip->i_flag |= IUPD; - ip->i_flag |= ICHG; - if (error = iupdat(ip, &vap->va_atime, &vap->va_mtime, 1)) - return (error); -*/ - } - if (vap->va_mode != (u_short)VNOVAL) - error = kernfs_chmod1(vp, (int)vap->va_mode, p); - if (vap->va_flags != VNOVAL) { -/* if (cred->cr_uid != ip->i_uid && - (error = suser(cred, &p->p_acflag))) - return (error); - if (cred->cr_uid == 0) { - ip->i_flags = vap->va_flags; - } else { - ip->i_flags &= 0xffff0000; - ip->i_flags |= (vap->va_flags & 0xffff); - } - ip->i_flag |= ICHG; -*/ - } - return (error); + return (0); } static int @@ -520,7 +446,7 @@ kernfs_read(vp, uio, ioflag, cred) int ioflag; struct ucred *cred; { - struct kernfs_target *kt = VTOKERN(vp)->kf_kt; + struct kern_target *kt = VTOKERN(vp)->kf_kt; char strbuf[KSTRING]; int off = uio->uio_offset; int len = 0; @@ -530,6 +456,9 @@ kernfs_read(vp, uio, ioflag, cred) printf("kern_read %s\n", kt->kt_name); #endif + if (vp->v_flag & VROOT) + return (EOPNOTSUPP); + error = kernfs_xread(kt, strbuf, sizeof(strbuf), &len); if (error) return (error); @@ -545,7 +474,7 @@ kernfs_write(vp, uio, ioflag, cred) int ioflag; struct ucred *cred; { - struct kernfs_target *kt = VTOKERN(vp)->kf_kt; + struct kern_target *kt = VTOKERN(vp)->kf_kt; char strbuf[KSTRING]; int len = uio->uio_resid; char *cp = strbuf; @@ -564,16 +493,15 @@ kernfs_write(vp, uio, ioflag, cred) return (EIO); strbuf[xlen] = '\0'; + xlen = strlen(strbuf); return (kernfs_xwrite(kt, strbuf, xlen)); } -kernfs_readdir(vp, uio, cred, eofflagp, cookies, ncookies) +kernfs_readdir(vp, uio, cred, eofflagp) struct vnode *vp; struct uio *uio; struct ucred *cred; int *eofflagp; - u_int *cookies; - int ncookies; { struct filedesc *fdp; int i; @@ -581,18 +509,18 @@ kernfs_readdir(vp, uio, cred, eofflagp, i = uio->uio_offset / UIO_MX; error = 0; - while (uio->uio_resid > 0 && (!cookies || ncookies > 0)) { + while (uio->uio_resid > 0) { #ifdef KERNFS_DIAGNOSTIC printf("kernfs_readdir: i = %d\n", i); #endif - if (i >= nkernfs_targets) { + if (i >= nkern_targets) { *eofflagp = 1; break; } { struct direct d; struct direct *dp = &d; - struct kernfs_target *kt = &kernfs_targets[i]; + struct kern_target *kt = &kern_targets[i]; bzero((caddr_t) dp, UIO_MX); @@ -614,10 +542,6 @@ kernfs_readdir(vp, uio, cred, eofflagp, error = uiomove((caddr_t) dp, UIO_MX, uio); if (error) break; - if (cookies) { - *cookies = (i + 1) * UIO_MX; - ncookies--; - } } i++; } @@ -646,12 +570,10 @@ kernfs_inactive(vp, p) * Print out the contents of a kernfs vnode. */ /* ARGSUSED */ -int kernfs_print(vp) struct vnode *vp; { - printf("tag VT_KERNFS, kernfs vnode\n"); - return (0); + printf("tag VT_NON, kernfs vnode\n"); } /*