|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright 1997,1998 Julian Elischer. All rights reserved. ! 24: * [email protected] ! 25: * ! 26: * Redistribution and use in source and binary forms, with or without ! 27: * modification, are permitted provided that the following conditions are ! 28: * met: ! 29: * 1. Redistributions of source code must retain the above copyright ! 30: * notice, this list of conditions and the following disclaimer. ! 31: * 2. Redistributions in binary form must reproduce the above copyright notice, ! 32: * this list of conditions and the following disclaimer in the documentation ! 33: * and/or other materials provided with the distribution. ! 34: * ! 35: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS ! 36: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ! 37: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ! 38: * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR ! 39: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 40: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ! 41: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ! 42: * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 43: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 44: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 45: * SUCH DAMAGE. ! 46: * ! 47: * devfs_vnops.c ! 48: */ ! 49: ! 50: /* ! 51: * HISTORY ! 52: * Clark Warner ([email protected]) Tue Feb 10 2000 ! 53: * - Added err_copyfile to the vnode operations table ! 54: * Dieter Siegmund ([email protected]) Thu Apr 8 14:08:19 PDT 1999 ! 55: * - instead of duplicating specfs here, created a vnode-ops table ! 56: * that redirects most operations to specfs (as is done with ufs); ! 57: * - removed routines that made no sense ! 58: * - cleaned up reclaim: replaced devfs_vntodn() with a macro VTODN() ! 59: * - cleaned up symlink, link locking ! 60: * - added the devfs_lock to protect devfs data structures against ! 61: * driver's calling devfs_add_devswf()/etc. ! 62: * Dieter Siegmund ([email protected]) Wed Jul 14 13:37:59 PDT 1999 ! 63: * - free the devfs devnode in devfs_inactive(), not just in devfs_reclaim() ! 64: * to free up kernel memory as soon as it's available ! 65: * - got rid of devfsspec_{read, write} ! 66: * Dieter Siegmund ([email protected]) Fri Sep 17 09:58:38 PDT 1999 ! 67: * - update the mod/access times ! 68: */ ! 69: ! 70: #include <sys/param.h> ! 71: #include <sys/systm.h> ! 72: #include <sys/buf.h> ! 73: #include <sys/namei.h> ! 74: #include <sys/kernel.h> ! 75: #include <sys/fcntl.h> ! 76: #include <sys/conf.h> ! 77: #include <sys/disklabel.h> ! 78: #include <sys/lock.h> ! 79: #include <sys/stat.h> ! 80: #include <sys/mount.h> ! 81: #include <sys/proc.h> ! 82: #include <sys/time.h> ! 83: #include <sys/vnode.h> ! 84: #include <miscfs/specfs/specdev.h> ! 85: #include <sys/dirent.h> ! 86: #include <sys/vmmeter.h> ! 87: #include <sys/vm.h> ! 88: ! 89: #include "devfsdefs.h" ! 90: ! 91: /* ! 92: * Convert a component of a pathname into a pointer to a locked node. ! 93: * This is a very central and rather complicated routine. ! 94: * If the file system is not maintained in a strict tree hierarchy, ! 95: * this can result in a deadlock situation (see comments in code below). ! 96: * ! 97: * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on ! 98: * whether the name is to be looked up, created, renamed, or deleted. ! 99: * When CREATE, RENAME, or DELETE is specified, information usable in ! 100: * creating, renaming, or deleting a directory entry may be calculated. ! 101: * If flag has LOCKPARENT or'ed into it and the target of the pathname ! 102: * exists, lookup returns both the target and its parent directory locked. ! 103: * When creating or renaming and LOCKPARENT is specified, the target may ! 104: * not be ".". When deleting and LOCKPARENT is specified, the target may ! 105: * be "."., but the caller must check to ensure it does an vrele and DNUNLOCK ! 106: * instead of two DNUNLOCKs. ! 107: * ! 108: * Overall outline of devfs_lookup: ! 109: * ! 110: * check accessibility of directory ! 111: * null terminate the component (lookup leaves the whole string alone) ! 112: * look for name in cache, if found, then if at end of path ! 113: * and deleting or creating, drop it, else return name ! 114: * search for name in directory, to found or notfound ! 115: * notfound: ! 116: * if creating, return locked directory, ! 117: * else return error ! 118: * found: ! 119: * if at end of path and deleting, return information to allow delete ! 120: * if at end of path and rewriting (RENAME and LOCKPARENT), lock target ! 121: * node and return info to allow rewrite ! 122: * if not at end, add name to cache; if at end and neither creating ! 123: * nor deleting, add name to cache ! 124: * On return to lookup, remove the null termination we put in at the start. ! 125: * ! 126: * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent node unlocked. ! 127: */ ! 128: static int ! 129: devfs_lookup(struct vop_lookup_args *ap) ! 130: /*struct vop_lookup_args { ! 131: struct vnode * a_dvp; directory vnode ptr ! 132: struct vnode ** a_vpp; where to put the result ! 133: struct componentname * a_cnp; the name we want ! 134: };*/ ! 135: { ! 136: struct componentname *cnp = ap->a_cnp; ! 137: struct vnode *dir_vnode = ap->a_dvp; ! 138: struct vnode **result_vnode = ap->a_vpp; ! 139: devnode_t * dir_node; /* the directory we are searching */ ! 140: devnode_t * node = NULL; /* the node we are searching for */ ! 141: devdirent_t * nodename; ! 142: int flags = cnp->cn_flags; ! 143: int op = cnp->cn_nameiop; /* LOOKUP, CREATE, RENAME, or DELETE */ ! 144: int lockparent = flags & LOCKPARENT; ! 145: int wantparent = flags & (LOCKPARENT|WANTPARENT); ! 146: int error = 0; ! 147: struct proc *p = cnp->cn_proc; ! 148: char heldchar; /* the char at the end of the name componet */ ! 149: ! 150: *result_vnode = NULL; /* safe not sorry */ /*XXX*/ ! 151: ! 152: if (dir_vnode->v_usecount == 0) ! 153: printf("devfs_lookup: dir had no refs "); ! 154: dir_node = VTODN(dir_vnode); ! 155: ! 156: /* ! 157: * Check accessiblity of directory. ! 158: */ ! 159: if (dir_node->dn_type != DEV_DIR) { ! 160: return (ENOTDIR); ! 161: } ! 162: ! 163: if ((error = VOP_ACCESS(dir_vnode, VEXEC, cnp->cn_cred, p)) != 0) { ! 164: return (error); ! 165: } ! 166: ! 167: /* temporarily terminate string component */ ! 168: heldchar = cnp->cn_nameptr[cnp->cn_namelen]; ! 169: cnp->cn_nameptr[cnp->cn_namelen] = '\0'; ! 170: DEVFS_LOCK(p); ! 171: nodename = dev_findname(dir_node,cnp->cn_nameptr); ! 172: if (nodename) { ! 173: /* entry exists */ ! 174: node = nodename->de_dnp; ! 175: node->dn_last_lookup = nodename; /* for unlink */ ! 176: /* Do potential vnode allocation here inside the lock ! 177: * to make sure that our device node has a non-NULL dn_vn ! 178: * associated with it. The device node might otherwise ! 179: * get deleted out from under us (see devfs_dn_free()). ! 180: */ ! 181: error = devfs_dntovn(node, result_vnode, p); ! 182: } ! 183: DEVFS_UNLOCK(p); ! 184: /* restore saved character */ ! 185: cnp->cn_nameptr[cnp->cn_namelen] = heldchar; ! 186: ! 187: if (error) ! 188: return (error); ! 189: ! 190: if (!nodename) { /* no entry */ ! 191: /* If it doesn't exist and we're not the last component, ! 192: * or we're at the last component, but we're not creating ! 193: * or renaming, return ENOENT. ! 194: */ ! 195: if (!(flags & ISLASTCN) || !(op == CREATE || op == RENAME)) { ! 196: return ENOENT; ! 197: } ! 198: /* ! 199: * Access for write is interpreted as allowing ! 200: * creation of files in the directory. ! 201: */ ! 202: if ((error = VOP_ACCESS(dir_vnode, VWRITE, ! 203: cnp->cn_cred, p)) != 0) ! 204: { ! 205: return (error); ! 206: } ! 207: /* ! 208: * We return with the directory locked, so that ! 209: * the parameters we set up above will still be ! 210: * valid if we actually decide to add a new entry. ! 211: * We return ni_vp == NULL to indicate that the entry ! 212: * does not currently exist; we leave a pointer to ! 213: * the (locked) directory vnode in namei_data->ni_dvp. ! 214: * The pathname buffer is saved so that the name ! 215: * can be obtained later. ! 216: * ! 217: * NB - if the directory is unlocked, then this ! 218: * information cannot be used. ! 219: */ ! 220: cnp->cn_flags |= SAVENAME; ! 221: if (!lockparent) ! 222: VOP_UNLOCK(dir_vnode, 0, p); ! 223: return (EJUSTRETURN); ! 224: } ! 225: ! 226: /* ! 227: * If deleting, and at end of pathname, return ! 228: * parameters which can be used to remove file. ! 229: * If the wantparent flag isn't set, we return only ! 230: * the directory (in namei_data->ni_dvp), otherwise we go ! 231: * on and lock the node, being careful with ".". ! 232: */ ! 233: if (op == DELETE && (flags & ISLASTCN)) { ! 234: /* ! 235: * Write access to directory required to delete files. ! 236: */ ! 237: if ((error = VOP_ACCESS(dir_vnode, VWRITE, ! 238: cnp->cn_cred, p)) != 0) ! 239: return (error); ! 240: /* ! 241: * we are trying to delete '.'. What does this mean? XXX ! 242: */ ! 243: if (dir_node == node) { ! 244: VREF(dir_vnode); ! 245: *result_vnode = dir_vnode; ! 246: return (0); ! 247: } ! 248: #ifdef NOTYET ! 249: /* ! 250: * If directory is "sticky", then user must own ! 251: * the directory, or the file in it, else she ! 252: * may not delete it (unless she's root). This ! 253: * implements append-only directories. ! 254: */ ! 255: if ((dir_node->mode & ISVTX) && ! 256: cnp->cn_cred->cr_uid != 0 && ! 257: cnp->cn_cred->cr_uid != dir_node->uid && ! 258: cnp->cn_cred->cr_uid != node->uid) { ! 259: VOP_UNLOCK(*result_vnode, 0, p); ! 260: return (EPERM); ! 261: } ! 262: #endif ! 263: if (!lockparent) ! 264: VOP_UNLOCK(dir_vnode, 0, p); ! 265: return (0); ! 266: } ! 267: ! 268: /* ! 269: * If rewriting (RENAME), return the vnode and the ! 270: * information required to rewrite the present directory ! 271: * Must get node of directory entry to verify it's a ! 272: * regular file, or empty directory. ! 273: */ ! 274: if (op == RENAME && wantparent && (flags & ISLASTCN)) { ! 275: /* ! 276: * Are we allowed to change the holding directory? ! 277: */ ! 278: if ((error = VOP_ACCESS(dir_vnode, VWRITE, ! 279: cnp->cn_cred, p)) != 0) ! 280: return (error); ! 281: /* ! 282: * Careful about locking second node. ! 283: * This can only occur if the target is ".". ! 284: */ ! 285: if (dir_node == node) ! 286: return (EISDIR); ! 287: /* hmm save the 'from' name (we need to delete it) */ ! 288: cnp->cn_flags |= SAVENAME; ! 289: if (!lockparent) ! 290: VOP_UNLOCK(dir_vnode, 0, p); ! 291: return (0); ! 292: } ! 293: ! 294: /* ! 295: * Step through the translation in the name. We do not unlock the ! 296: * directory because we may need it again if a symbolic link ! 297: * is relative to the current directory. Instead we save it ! 298: * unlocked as "saved_dir_node" XXX. We must get the target ! 299: * node before unlocking ! 300: * the directory to insure that the node will not be removed ! 301: * before we get it. We prevent deadlock by always fetching ! 302: * nodes from the root, moving down the directory tree. Thus ! 303: * when following backward pointers ".." we must unlock the ! 304: * parent directory before getting the requested directory. ! 305: * There is a potential race condition here if both the current ! 306: * and parent directories are removed before the lock for the ! 307: * node associated with ".." returns. We hope that this occurs ! 308: * infrequently since we cannot avoid this race condition without ! 309: * implementing a sophisticated deadlock detection algorithm. ! 310: * Note also that this simple deadlock detection scheme will not ! 311: * work if the file system has any hard links other than ".." ! 312: * that point backwards in the directory structure. ! 313: */ ! 314: if (flags & ISDOTDOT) { ! 315: VOP_UNLOCK(dir_vnode, 0, p); /* race to get the node */ ! 316: if (lockparent && (flags & ISLASTCN)) ! 317: vn_lock(dir_vnode, LK_EXCLUSIVE | LK_RETRY, p); ! 318: } else if (dir_node == node) { ! 319: #if 0 ! 320: /* ! 321: * this next statement is wrong: we already did a vget in ! 322: * devfs_dntovn(); DWS 4/16/1999 ! 323: */ ! 324: VREF(dir_vnode); /* we want ourself, ie "." */ ! 325: #endif ! 326: *result_vnode = dir_vnode; ! 327: } else { ! 328: if (!lockparent || (flags & ISLASTCN)) ! 329: VOP_UNLOCK(dir_vnode, 0, p); ! 330: } ! 331: ! 332: return (0); ! 333: } ! 334: ! 335: static int ! 336: devfs_access(struct vop_access_args *ap) ! 337: /*struct vop_access_args { ! 338: struct vnode *a_vp; ! 339: int a_mode; ! 340: struct ucred *a_cred; ! 341: struct proc *a_p; ! 342: } */ ! 343: { ! 344: /* ! 345: * mode is filled with a combination of VREAD, VWRITE, ! 346: * and/or VEXEC bits turned on. In an octal number these ! 347: * are the Y in 0Y00. ! 348: */ ! 349: struct vnode *vp = ap->a_vp; ! 350: int mode = ap->a_mode; ! 351: struct ucred *cred = ap->a_cred; ! 352: devnode_t * file_node; ! 353: gid_t *gp; ! 354: int i; ! 355: struct proc *p = ap->a_p; ! 356: ! 357: file_node = VTODN(vp); ! 358: /* ! 359: * if we are not running as a process, we are in the ! 360: * kernel and we DO have permission ! 361: */ ! 362: if (p == NULL) ! 363: return 0; ! 364: ! 365: /* ! 366: * Access check is based on only one of owner, group, public. ! 367: * If not owner, then check group. If not a member of the ! 368: * group, then check public access. ! 369: */ ! 370: if (cred->cr_uid != file_node->dn_uid) ! 371: { ! 372: /* failing that.. try groups */ ! 373: mode >>= 3; ! 374: gp = cred->cr_groups; ! 375: for (i = 0; i < cred->cr_ngroups; i++, gp++) ! 376: { ! 377: if (file_node->dn_gid == *gp) ! 378: { ! 379: goto found; ! 380: } ! 381: } ! 382: /* failing that.. try general access */ ! 383: mode >>= 3; ! 384: found: ! 385: ; ! 386: } ! 387: if ((file_node->dn_mode & mode) == mode) ! 388: return (0); ! 389: /* ! 390: * Root gets to do anything. ! 391: * but only use suser prives as a last resort ! 392: * (Use of super powers is recorded in ap->a_p->p_acflag) ! 393: */ ! 394: if( suser(cred, &ap->a_p->p_acflag) == 0) /* XXX what if no proc? */ ! 395: return 0; ! 396: return (EACCES); ! 397: } ! 398: ! 399: static int ! 400: devfs_getattr(struct vop_getattr_args *ap) ! 401: /*struct vop_getattr_args { ! 402: struct vnode *a_vp; ! 403: struct vattr *a_vap; ! 404: struct ucred *a_cred; ! 405: struct proc *a_p; ! 406: } */ ! 407: { ! 408: struct vnode *vp = ap->a_vp; ! 409: struct vattr *vap = ap->a_vap; ! 410: devnode_t * file_node; ! 411: struct timeval tv; ! 412: ! 413: file_node = VTODN(vp); ! 414: tv = time; ! 415: dn_times(file_node, tv, tv); ! 416: vap->va_rdev = 0;/* default value only */ ! 417: vap->va_mode = file_node->dn_mode; ! 418: switch (file_node->dn_type) ! 419: { ! 420: case DEV_DIR: ! 421: vap->va_rdev = (dev_t)file_node->dn_dvm; ! 422: vap->va_mode |= (S_IFDIR); ! 423: break; ! 424: case DEV_CDEV: ! 425: vap->va_rdev = file_node->dn_typeinfo.dev; ! 426: vap->va_mode |= (S_IFCHR); ! 427: break; ! 428: case DEV_BDEV: ! 429: vap->va_rdev = file_node->dn_typeinfo.dev; ! 430: vap->va_mode |= (S_IFBLK); ! 431: break; ! 432: case DEV_SLNK: ! 433: vap->va_mode |= (S_IFLNK); ! 434: break; ! 435: } ! 436: vap->va_type = vp->v_type; ! 437: vap->va_nlink = file_node->dn_links; ! 438: vap->va_uid = file_node->dn_uid; ! 439: vap->va_gid = file_node->dn_gid; ! 440: vap->va_fsid = (int32_t)(void *)file_node->dn_dvm; ! 441: vap->va_fileid = (int32_t)(void *)file_node; ! 442: vap->va_size = file_node->dn_len; /* now a u_quad_t */ ! 443: /* this doesn't belong here */ ! 444: if (vp->v_type == VBLK) ! 445: vap->va_blocksize = BLKDEV_IOSIZE; ! 446: else if (vp->v_type == VCHR) ! 447: vap->va_blocksize = MAXPHYSIO; ! 448: else ! 449: vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize; ! 450: /* if the time is bogus, set it to the boot time */ ! 451: if (file_node->dn_ctime.tv_sec == 0) ! 452: file_node->dn_ctime.tv_sec = boottime.tv_sec; ! 453: if (file_node->dn_mtime.tv_sec == 0) ! 454: file_node->dn_mtime.tv_sec = boottime.tv_sec; ! 455: if (file_node->dn_atime.tv_sec == 0) ! 456: file_node->dn_atime.tv_sec = boottime.tv_sec; ! 457: vap->va_ctime = file_node->dn_ctime; ! 458: vap->va_mtime = file_node->dn_mtime; ! 459: vap->va_atime = file_node->dn_atime; ! 460: vap->va_gen = 0; ! 461: vap->va_flags = 0; ! 462: vap->va_bytes = file_node->dn_len; /* u_quad_t */ ! 463: vap->va_filerev = 0; /* XXX */ /* u_quad_t */ ! 464: vap->va_vaflags = 0; /* XXX */ ! 465: return 0; ! 466: } ! 467: ! 468: static int ! 469: devfs_setattr(struct vop_setattr_args *ap) ! 470: /*struct vop_setattr_args { ! 471: struct vnode *a_vp; ! 472: struct vattr *a_vap; ! 473: struct ucred *a_cred; ! 474: struct proc *a_p; ! 475: } */ ! 476: { ! 477: struct vnode *vp = ap->a_vp; ! 478: struct vattr *vap = ap->a_vap; ! 479: struct ucred *cred = ap->a_cred; ! 480: struct proc *p = ap->a_p; ! 481: int error = 0; ! 482: gid_t *gp; ! 483: int i; ! 484: devnode_t * file_node; ! 485: struct timeval atimeval, mtimeval; ! 486: ! 487: if (vap->va_flags != VNOVAL) /* XXX needs to be implemented */ ! 488: return (EOPNOTSUPP); ! 489: ! 490: file_node = VTODN(vp); ! 491: ! 492: if ((vap->va_type != VNON) || ! 493: (vap->va_nlink != VNOVAL) || ! 494: (vap->va_fsid != VNOVAL) || ! 495: (vap->va_fileid != VNOVAL) || ! 496: (vap->va_blocksize != VNOVAL) || ! 497: (vap->va_rdev != VNOVAL) || ! 498: (vap->va_bytes != VNOVAL) || ! 499: (vap->va_gen != VNOVAL )) ! 500: { ! 501: return EINVAL; ! 502: } ! 503: ! 504: /* ! 505: * Go through the fields and update iff not VNOVAL. ! 506: */ ! 507: if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { ! 508: if (cred->cr_uid != file_node->dn_uid && ! 509: (error = suser(cred, &p->p_acflag)) && ! 510: ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || ! 511: (error = VOP_ACCESS(vp, VWRITE, cred, p)))) ! 512: return (error); ! 513: if (vap->va_atime.tv_sec != VNOVAL) ! 514: file_node->dn_flags |= DN_ACCESS; ! 515: if (vap->va_mtime.tv_sec != VNOVAL) ! 516: file_node->dn_flags |= DN_CHANGE | DN_UPDATE; ! 517: atimeval.tv_sec = vap->va_atime.tv_sec; ! 518: atimeval.tv_usec = vap->va_atime.tv_nsec / 1000; ! 519: mtimeval.tv_sec = vap->va_mtime.tv_sec; ! 520: mtimeval.tv_usec = vap->va_mtime.tv_nsec / 1000; ! 521: if (error = VOP_UPDATE(vp, &atimeval, &mtimeval, 1)) ! 522: return (error); ! 523: } ! 524: ! 525: /* ! 526: * Change the permissions.. must be root or owner to do this. ! 527: */ ! 528: if (vap->va_mode != (u_short)VNOVAL) { ! 529: if ((cred->cr_uid != file_node->dn_uid) ! 530: && (error = suser(cred, &p->p_acflag))) ! 531: return (error); ! 532: file_node->dn_mode &= ~07777; ! 533: file_node->dn_mode |= vap->va_mode & 07777; ! 534: } ! 535: ! 536: /* ! 537: * Change the owner.. must be root to do this. ! 538: */ ! 539: if (vap->va_uid != (uid_t)VNOVAL) { ! 540: if (error = suser(cred, &p->p_acflag)) ! 541: return (error); ! 542: file_node->dn_uid = vap->va_uid; ! 543: } ! 544: ! 545: /* ! 546: * Change the group.. must be root or owner to do this. ! 547: * If we are the owner, we must be in the target group too. ! 548: * don't use suser() unless you have to as it reports ! 549: * whether you needed suser powers or not. ! 550: */ ! 551: if (vap->va_gid != (gid_t)VNOVAL) { ! 552: if (cred->cr_uid == file_node->dn_uid){ ! 553: gp = cred->cr_groups; ! 554: for (i = 0; i < cred->cr_ngroups; i++, gp++) { ! 555: if (vap->va_gid == *gp) ! 556: goto cando; ! 557: } ! 558: } ! 559: /* ! 560: * we can't do it with normal privs, ! 561: * do we have an ace up our sleeve? ! 562: */ ! 563: if (error = suser(cred, &p->p_acflag)) ! 564: return (error); ! 565: cando: ! 566: file_node->dn_gid = vap->va_gid; ! 567: } ! 568: #if 0 ! 569: /* ! 570: * Copied from somewhere else ! 571: * but only kept as a marker and reminder of the fact that ! 572: * flags should be handled some day ! 573: */ ! 574: if (vap->va_flags != VNOVAL) { ! 575: if (error = suser(cred, &p->p_acflag)) ! 576: return error; ! 577: if (cred->cr_uid == 0) ! 578: ; ! 579: else { ! 580: } ! 581: } ! 582: #endif ! 583: return error; ! 584: } ! 585: ! 586: static int ! 587: devfs_read(struct vop_read_args *ap) ! 588: /*struct vop_read_args { ! 589: struct vnode *a_vp; ! 590: struct uio *a_uio; ! 591: int a_ioflag; ! 592: struct ucred *a_cred; ! 593: } */ ! 594: { ! 595: devnode_t * dn_p = VTODN(ap->a_vp); ! 596: ! 597: switch (ap->a_vp->v_type) { ! 598: case VDIR: { ! 599: dn_p->dn_flags |= DN_ACCESS; ! 600: return VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred, ! 601: NULL, NULL, NULL); ! 602: } ! 603: default: { ! 604: printf("devfs_read(): bad file type %d", ap->a_vp->v_type); ! 605: return(EINVAL); ! 606: break; ! 607: } ! 608: } ! 609: return (0); /* not reached */ ! 610: } ! 611: ! 612: static int ! 613: devfs_close(ap) ! 614: struct vop_close_args /* { ! 615: struct vnode *a_vp; ! 616: int a_fflag; ! 617: struct ucred *a_cred; ! 618: struct proc *a_p; ! 619: } */ *ap; ! 620: { ! 621: struct vnode * vp = ap->a_vp; ! 622: register devnode_t * dnp = VTODN(vp); ! 623: ! 624: simple_lock(&vp->v_interlock); ! 625: if (vp->v_usecount > 1) ! 626: dn_times(dnp, time, time); ! 627: simple_unlock(&vp->v_interlock); ! 628: return (0); ! 629: } ! 630: ! 631: static int ! 632: devfsspec_close(ap) ! 633: struct vop_close_args /* { ! 634: struct vnode *a_vp; ! 635: int a_fflag; ! 636: struct ucred *a_cred; ! 637: struct proc *a_p; ! 638: } */ *ap; ! 639: { ! 640: struct vnode * vp = ap->a_vp; ! 641: register devnode_t * dnp = VTODN(vp); ! 642: ! 643: simple_lock(&vp->v_interlock); ! 644: if (vp->v_usecount > 1) ! 645: dn_times(dnp, time, time); ! 646: simple_unlock(&vp->v_interlock); ! 647: return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap)); ! 648: } ! 649: ! 650: static int ! 651: devfsspec_read(struct vop_read_args *ap) ! 652: /*struct vop_read_args { ! 653: struct vnode *a_vp; ! 654: struct uio *a_uio; ! 655: int a_ioflag; ! 656: struct ucred *a_cred; ! 657: } */ ! 658: { ! 659: VTODN(ap->a_vp)->dn_flags |= DN_ACCESS; ! 660: return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap)); ! 661: } ! 662: ! 663: static int ! 664: devfsspec_write(struct vop_write_args *ap) ! 665: /*struct vop_write_args { ! 666: struct vnode *a_vp; ! 667: struct uio *a_uio; ! 668: int a_ioflag; ! 669: struct ucred *a_cred; ! 670: } */ ! 671: { ! 672: VTODN(ap->a_vp)->dn_flags |= DN_CHANGE | DN_UPDATE; ! 673: return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap)); ! 674: } ! 675: ! 676: /* ! 677: * Write data to a file or directory. ! 678: */ ! 679: static int ! 680: devfs_write(struct vop_write_args *ap) ! 681: /*struct vop_write_args { ! 682: struct vnode *a_vp; ! 683: struct uio *a_uio; ! 684: int a_ioflag; ! 685: struct ucred *a_cred; ! 686: } */ ! 687: { ! 688: switch (ap->a_vp->v_type) { ! 689: case VDIR: ! 690: return(EISDIR); ! 691: default: ! 692: printf("devfs_write(): bad file type %d", ap->a_vp->v_type); ! 693: return (EINVAL); ! 694: } ! 695: return 0; /* not reached */ ! 696: } ! 697: ! 698: static int ! 699: devfs_remove(struct vop_remove_args *ap) ! 700: /*struct vop_remove_args { ! 701: struct vnode *a_dvp; ! 702: struct vnode *a_vp; ! 703: struct componentname *a_cnp; ! 704: } */ ! 705: { ! 706: struct vnode *vp = ap->a_vp; ! 707: struct vnode *dvp = ap->a_dvp; ! 708: struct componentname *cnp = ap->a_cnp; ! 709: devnode_t * tp; ! 710: devnode_t * tdp; ! 711: devdirent_t * tnp; ! 712: int doingdirectory = 0; ! 713: int error = 0; ! 714: uid_t ouruid = cnp->cn_cred->cr_uid; ! 715: struct proc *p = cnp->cn_proc; ! 716: ! 717: /* ! 718: * Lock our directories and get our name pointers ! 719: * assume that the names are null terminated as they ! 720: * are the end of the path. Get pointers to all our ! 721: * devfs structures. ! 722: */ ! 723: tp = VTODN(vp); ! 724: tdp = VTODN(dvp); ! 725: /* ! 726: * Assuming we are atomic, dev_lookup left this for us ! 727: */ ! 728: tnp = tp->dn_last_lookup; ! 729: ! 730: /* ! 731: * Check we are doing legal things WRT the new flags ! 732: */ ! 733: if ((tp->dn_flags & (IMMUTABLE | APPEND)) ! 734: || (tdp->dn_flags & APPEND) /*XXX eh?*/ ) { ! 735: error = EPERM; ! 736: goto abort; ! 737: } ! 738: ! 739: /* ! 740: * Make sure that we don't try do something stupid ! 741: */ ! 742: if ((tp->dn_type) == DEV_DIR) { ! 743: /* ! 744: * Avoid ".", "..", and aliases of "." for obvious reasons. ! 745: */ ! 746: if ( (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') ! 747: || (cnp->cn_flags&ISDOTDOT) ) { ! 748: error = EINVAL; ! 749: goto abort; ! 750: } ! 751: doingdirectory++; ! 752: } ! 753: ! 754: /*********************************** ! 755: * Start actually doing things.... * ! 756: ***********************************/ ! 757: tdp->dn_flags |= DN_CHANGE | DN_UPDATE; ! 758: ! 759: /* ! 760: * own the parent directory, or the destination of the rename, ! 761: * otherwise the destination may not be changed (except by ! 762: * root). This implements append-only directories. ! 763: * XXX shoudn't this be in generic code? ! 764: */ ! 765: if ((tdp->dn_mode & S_ISTXT) ! 766: && ouruid != 0 ! 767: && ouruid != tdp->dn_uid ! 768: && ouruid != tp->dn_uid ) { ! 769: error = EPERM; ! 770: goto abort; ! 771: } ! 772: /* ! 773: * Target must be empty if a directory and have no links ! 774: * to it. Also, ensure source and target are compatible ! 775: * (both directories, or both not directories). ! 776: */ ! 777: if (( doingdirectory) && (tp->dn_links > 2)) { ! 778: error = ENOTEMPTY; ! 779: goto abort; ! 780: } ! 781: DEVFS_LOCK(p); ! 782: dev_free_name(tnp); ! 783: DEVFS_UNLOCK(p); ! 784: abort: ! 785: if (dvp == vp) ! 786: vrele(vp); ! 787: else ! 788: vput(vp); ! 789: vput(dvp); ! 790: return (error); ! 791: } ! 792: ! 793: /* ! 794: */ ! 795: static int ! 796: devfs_link(struct vop_link_args *ap) ! 797: /*struct vop_link_args { ! 798: struct vnode *a_tdvp; ! 799: struct vnode *a_vp; ! 800: struct componentname *a_cnp; ! 801: } */ ! 802: { ! 803: struct vnode *vp = ap->a_vp; ! 804: struct vnode *tdvp = ap->a_tdvp; ! 805: struct componentname *cnp = ap->a_cnp; ! 806: struct proc *p = cnp->cn_proc; ! 807: devnode_t * fp; ! 808: devnode_t * tdp; ! 809: devdirent_t * tnp; ! 810: int error = 0; ! 811: struct timeval tv; ! 812: ! 813: /* ! 814: * First catch an arbitrary restriction for this FS ! 815: */ ! 816: if (cnp->cn_namelen > DEVMAXNAMESIZE) { ! 817: error = ENAMETOOLONG; ! 818: goto out1; ! 819: } ! 820: ! 821: /* ! 822: * Lock our directories and get our name pointers ! 823: * assume that the names are null terminated as they ! 824: * are the end of the path. Get pointers to all our ! 825: * devfs structures. ! 826: */ ! 827: tdp = VTODN(tdvp); ! 828: fp = VTODN(vp); ! 829: ! 830: if (tdvp->v_mount != vp->v_mount) { ! 831: error = EXDEV; ! 832: VOP_ABORTOP(tdvp, cnp); ! 833: goto out2; ! 834: } ! 835: if (tdvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, p))) { ! 836: VOP_ABORTOP(tdvp, cnp); ! 837: goto out2; ! 838: } ! 839: ! 840: /* ! 841: * Check we are doing legal things WRT the new flags ! 842: */ ! 843: if (fp->dn_flags & (IMMUTABLE | APPEND)) { ! 844: VOP_ABORTOP(tdvp, cnp); ! 845: error = EPERM; ! 846: goto out1; ! 847: } ! 848: ! 849: /*********************************** ! 850: * Start actually doing things.... * ! 851: ***********************************/ ! 852: fp->dn_flags |= DN_CHANGE; ! 853: tv = time; ! 854: error = VOP_UPDATE(vp, &tv, &tv, 1); ! 855: if (!error) { ! 856: DEVFS_LOCK(p); ! 857: error = dev_add_name(cnp->cn_nameptr, tdp, NULL, fp, &tnp); ! 858: DEVFS_UNLOCK(p); ! 859: } ! 860: out1: ! 861: if (tdvp != vp) ! 862: VOP_UNLOCK(vp, 0, p); ! 863: out2: ! 864: vput(tdvp); ! 865: return (error); ! 866: } ! 867: ! 868: /* ! 869: * Check if source directory is in the path of the target directory. ! 870: * Target is supplied locked, source is unlocked. ! 871: * The target is always vput before returning. ! 872: */ ! 873: int ! 874: devfs_checkpath(source, target) ! 875: devnode_t *source, *target; ! 876: { ! 877: int error = 0; ! 878: devnode_t * ntmp; ! 879: devnode_t * tmp; ! 880: struct vnode *vp; ! 881: ! 882: vp = target->dn_vn; ! 883: tmp = target; ! 884: ! 885: do { ! 886: if (tmp == source) { ! 887: error = EINVAL; ! 888: break; ! 889: } ! 890: ntmp = tmp; ! 891: } while ((tmp = tmp->dn_typeinfo.Dir.parent) != ntmp); ! 892: ! 893: if (vp != NULL) ! 894: vput(vp); ! 895: return (error); ! 896: } ! 897: ! 898: /* ! 899: * Rename system call. Seems overly complicated to me... ! 900: * rename("foo", "bar"); ! 901: * is essentially ! 902: * unlink("bar"); ! 903: * link("foo", "bar"); ! 904: * unlink("foo"); ! 905: * but ``atomically''. ! 906: * ! 907: * When the target exists, both the directory ! 908: * and target vnodes are locked. ! 909: * the source and source-parent vnodes are referenced ! 910: * ! 911: * ! 912: * Basic algorithm is: ! 913: * ! 914: * 1) Bump link count on source while we're linking it to the ! 915: * target. This also ensure the inode won't be deleted out ! 916: * from underneath us while we work (it may be truncated by ! 917: * a concurrent `trunc' or `open' for creation). ! 918: * 2) Link source to destination. If destination already exists, ! 919: * delete it first. ! 920: * 3) Unlink source reference to node if still around. If a ! 921: * directory was moved and the parent of the destination ! 922: * is different from the source, patch the ".." entry in the ! 923: * directory. ! 924: */ ! 925: static int ! 926: devfs_rename(struct vop_rename_args *ap) ! 927: /*struct vop_rename_args { ! 928: struct vnode *a_fdvp; ! 929: struct vnode *a_fvp; ! 930: struct componentname *a_fcnp; ! 931: struct vnode *a_tdvp; ! 932: struct vnode *a_tvp; ! 933: struct componentname *a_tcnp; ! 934: } */ ! 935: { ! 936: struct vnode *tvp = ap->a_tvp; ! 937: struct vnode *tdvp = ap->a_tdvp; ! 938: struct vnode *fvp = ap->a_fvp; ! 939: struct vnode *fdvp = ap->a_fdvp; ! 940: struct componentname *tcnp = ap->a_tcnp; ! 941: struct componentname *fcnp = ap->a_fcnp; ! 942: struct proc *p = fcnp->cn_proc; ! 943: devnode_t *fp, *fdp, *tp, *tdp; ! 944: devdirent_t *fnp,*tnp; ! 945: int doingdirectory = 0; ! 946: int error = 0; ! 947: struct timeval tv; ! 948: ! 949: /* ! 950: * First catch an arbitrary restriction for this FS ! 951: */ ! 952: if(tcnp->cn_namelen > DEVMAXNAMESIZE) { ! 953: error = ENAMETOOLONG; ! 954: goto abortit; ! 955: } ! 956: ! 957: /* ! 958: * Lock our directories and get our name pointers ! 959: * assume that the names are null terminated as they ! 960: * are the end of the path. Get pointers to all our ! 961: * devfs structures. ! 962: */ ! 963: tdp = VTODN(tdvp); ! 964: fdp = VTODN(fdvp); ! 965: fp = VTODN(fvp); ! 966: fnp = fp->dn_last_lookup; ! 967: tp = NULL; ! 968: tnp = NULL; ! 969: if (tvp) { ! 970: tp = VTODN(tvp); ! 971: tnp = tp->dn_last_lookup; ! 972: } ! 973: ! 974: /* ! 975: * trying to move it out of devfs? ! 976: * if we move a dir across mnt points. we need to fix all ! 977: * the mountpoint pointers! XXX ! 978: * so for now keep dirs within the same mount ! 979: */ ! 980: if ((fvp->v_mount != tdvp->v_mount) || ! 981: (tvp && (fvp->v_mount != tvp->v_mount))) { ! 982: error = EXDEV; ! 983: abortit: ! 984: VOP_ABORTOP(tdvp, tcnp); ! 985: if (tdvp == tvp) /* eh? */ ! 986: vrele(tdvp); ! 987: else ! 988: vput(tdvp); ! 989: if (tvp) ! 990: vput(tvp); ! 991: VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */ ! 992: vrele(fdvp); ! 993: vrele(fvp); ! 994: return (error); ! 995: } ! 996: ! 997: /* ! 998: * Check we are doing legal things WRT the new flags ! 999: */ ! 1000: if ((tp && (tp->dn_flags & (IMMUTABLE | APPEND))) ! 1001: || (fp->dn_flags & (IMMUTABLE | APPEND)) ! 1002: || (fdp->dn_flags & APPEND)) { ! 1003: error = EPERM; ! 1004: goto abortit; ! 1005: } ! 1006: ! 1007: /* ! 1008: * Make sure that we don't try do something stupid ! 1009: */ ! 1010: if ((fp->dn_type) == DEV_DIR) { ! 1011: /* ! 1012: * Avoid ".", "..", and aliases of "." for obvious reasons. ! 1013: */ ! 1014: if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ! 1015: || (fcnp->cn_flags&ISDOTDOT) ! 1016: || (tcnp->cn_namelen == 1 && tcnp->cn_nameptr[0] == '.') ! 1017: || (tcnp->cn_flags&ISDOTDOT) ! 1018: || (tdp == fp )) { ! 1019: error = EINVAL; ! 1020: goto abortit; ! 1021: } ! 1022: doingdirectory++; ! 1023: } ! 1024: ! 1025: /* ! 1026: * If ".." must be changed (ie the directory gets a new ! 1027: * parent) then the source directory must not be in the ! 1028: * directory hierarchy above the target, as this would ! 1029: * orphan everything below the source directory. Also ! 1030: * the user must have write permission in the source so ! 1031: * as to be able to change "..". ! 1032: */ ! 1033: if (doingdirectory && (tdp != fdp)) { ! 1034: devnode_t * tmp, *ntmp; ! 1035: error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc); ! 1036: tmp = tdp; ! 1037: do { ! 1038: if(tmp == fp) { ! 1039: /* XXX unlock stuff here probably */ ! 1040: error = EINVAL; ! 1041: goto out; ! 1042: } ! 1043: ntmp = tmp; ! 1044: } while ((tmp = tmp->dn_typeinfo.Dir.parent) != ntmp); ! 1045: } ! 1046: ! 1047: /*********************************** ! 1048: * Start actually doing things.... * ! 1049: ***********************************/ ! 1050: fp->dn_flags |= DN_CHANGE; ! 1051: tv = time; ! 1052: if (error = VOP_UPDATE(fvp, &tv, &tv, 1)) { ! 1053: VOP_UNLOCK(fvp, 0, p); ! 1054: goto bad; ! 1055: } ! 1056: /* ! 1057: * Check if just deleting a link name. ! 1058: */ ! 1059: if (fvp == tvp) { ! 1060: if (fvp->v_type == VDIR) { ! 1061: error = EINVAL; ! 1062: goto abortit; ! 1063: } ! 1064: ! 1065: /* Release destination completely. */ ! 1066: VOP_ABORTOP(tdvp, tcnp); ! 1067: vput(tdvp); ! 1068: vput(tvp); ! 1069: ! 1070: /* Delete source. */ ! 1071: VOP_ABORTOP(fdvp, fcnp); /*XXX*/ ! 1072: vrele(fdvp); ! 1073: vrele(fvp); ! 1074: dev_free_name(fnp); ! 1075: return 0; ! 1076: } ! 1077: ! 1078: vrele(fdvp); ! 1079: ! 1080: /* ! 1081: * 1) Bump link count while we're moving stuff ! 1082: * around. If we crash somewhere before ! 1083: * completing our work, too bad :) ! 1084: */ ! 1085: fp->dn_links++; ! 1086: /* ! 1087: * If the target exists zap it (unless it's a non-empty directory) ! 1088: * We could do that as well but won't ! 1089: */ ! 1090: if (tp) { ! 1091: int ouruid = tcnp->cn_cred->cr_uid; ! 1092: /* ! 1093: * If the parent directory is "sticky", then the user must ! 1094: * own the parent directory, or the destination of the rename, ! 1095: * otherwise the destination may not be changed (except by ! 1096: * root). This implements append-only directories. ! 1097: * XXX shoudn't this be in generic code? ! 1098: */ ! 1099: if ((tdp->dn_mode & S_ISTXT) ! 1100: && ouruid != 0 ! 1101: && ouruid != tdp->dn_uid ! 1102: && ouruid != tp->dn_uid ) { ! 1103: error = EPERM; ! 1104: goto bad; ! 1105: } ! 1106: /* ! 1107: * Target must be empty if a directory and have no links ! 1108: * to it. Also, ensure source and target are compatible ! 1109: * (both directories, or both not directories). ! 1110: */ ! 1111: if (( doingdirectory) && (tp->dn_links > 2)) { ! 1112: error = ENOTEMPTY; ! 1113: goto bad; ! 1114: } ! 1115: dev_free_name(tnp); ! 1116: tp = NULL; ! 1117: } ! 1118: dev_add_name(tcnp->cn_nameptr,tdp,NULL,fp,&tnp); ! 1119: fnp->de_dnp = NULL; ! 1120: fp->dn_links--; /* one less link to it.. */ ! 1121: dev_free_name(fnp); ! 1122: fp->dn_links--; /* we added one earlier*/ ! 1123: if (tdp) ! 1124: vput(tdvp); ! 1125: if (tp) ! 1126: vput(fvp); ! 1127: vrele(fvp); ! 1128: return (error); ! 1129: ! 1130: bad: ! 1131: if (tp) ! 1132: vput(tvp); ! 1133: vput(tdvp); ! 1134: out: ! 1135: if (vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p) == 0) { ! 1136: fp->dn_links--; /* we added one earlier*/ ! 1137: vput(fvp); ! 1138: } else ! 1139: vrele(fvp); ! 1140: return (error); ! 1141: } ! 1142: ! 1143: static int ! 1144: devfs_symlink(struct vop_symlink_args *ap) ! 1145: /*struct vop_symlink_args { ! 1146: struct vnode *a_dvp; ! 1147: struct vnode **a_vpp; ! 1148: struct componentname *a_cnp; ! 1149: struct vattr *a_vap; ! 1150: char *a_target; ! 1151: } */ ! 1152: { ! 1153: struct componentname * cnp = ap->a_cnp; ! 1154: struct vnode *vp = NULL; ! 1155: int error = 0; ! 1156: devnode_t * dir_p; ! 1157: devnode_type_t typeinfo; ! 1158: devdirent_t * nm_p; ! 1159: devnode_t * dev_p; ! 1160: struct vattr * vap = ap->a_vap; ! 1161: struct vnode * * vpp = ap->a_vpp; ! 1162: struct proc *p = cnp->cn_proc; ! 1163: struct timeval tv; ! 1164: ! 1165: dir_p = VTODN(ap->a_dvp); ! 1166: typeinfo.Slnk.name = ap->a_target; ! 1167: typeinfo.Slnk.namelen = strlen(ap->a_target); ! 1168: DEVFS_LOCK(p); ! 1169: error = dev_add_entry(cnp->cn_nameptr, dir_p, DEV_SLNK, ! 1170: &typeinfo, NULL, NULL, &nm_p); ! 1171: DEVFS_UNLOCK(p); ! 1172: if (error) { ! 1173: goto failure; ! 1174: } ! 1175: ! 1176: dev_p = nm_p->de_dnp; ! 1177: dev_p->dn_uid = dir_p->dn_uid; ! 1178: dev_p->dn_gid = dir_p->dn_gid; ! 1179: dev_p->dn_mode = vap->va_mode; ! 1180: dn_copy_times(dev_p, dir_p); ! 1181: error = devfs_dntovn(dev_p, vpp, p); ! 1182: if (error) ! 1183: goto failure; ! 1184: vp = *vpp; ! 1185: vput(vp); ! 1186: failure: ! 1187: if ((cnp->cn_flags & SAVESTART) == 0) ! 1188: FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI); ! 1189: vput(ap->a_dvp); ! 1190: return error; ! 1191: } ! 1192: ! 1193: /* ! 1194: * Mknod vnode call ! 1195: */ ! 1196: /* ARGSUSED */ ! 1197: int ! 1198: devfs_mknod(ap) ! 1199: struct vop_mknod_args /* { ! 1200: struct vnode *a_dvp; ! 1201: struct vnode **a_vpp; ! 1202: struct componentname *a_cnp; ! 1203: struct vattr *a_vap; ! 1204: } */ *ap; ! 1205: { ! 1206: struct componentname * cnp = ap->a_cnp; ! 1207: devnode_t * dev_p; ! 1208: devdirent_t * devent; ! 1209: devnode_t * dir_p; /* devnode for parent directory */ ! 1210: struct vnode * dvp = ap->a_dvp; ! 1211: int error = 0; ! 1212: devnode_type_t typeinfo; ! 1213: struct vattr * vap = ap->a_vap; ! 1214: struct vnode ** vpp = ap->a_vpp; ! 1215: struct proc * p = cnp->cn_proc; ! 1216: ! 1217: *vpp = NULL; ! 1218: if (!vap->va_type == VBLK && !vap->va_type == VCHR) { ! 1219: error = EINVAL; /* only support mknod of special files */ ! 1220: goto failure; ! 1221: } ! 1222: dir_p = VTODN(dvp); ! 1223: typeinfo.dev = vap->va_rdev; ! 1224: DEVFS_LOCK(p); ! 1225: error = dev_add_entry(cnp->cn_nameptr, dir_p, ! 1226: (vap->va_type == VBLK) ? DEV_BDEV : DEV_CDEV, ! 1227: &typeinfo, NULL, NULL, &devent); ! 1228: DEVFS_UNLOCK(p); ! 1229: if (error) { ! 1230: goto failure; ! 1231: } ! 1232: dev_p = devent->de_dnp; ! 1233: error = devfs_dntovn(dev_p, vpp, p); ! 1234: if (error) ! 1235: goto failure; ! 1236: dev_p->dn_uid = cnp->cn_cred->cr_uid; ! 1237: dev_p->dn_gid = dir_p->dn_gid; ! 1238: dev_p->dn_mode = vap->va_mode; ! 1239: failure: ! 1240: if (*vpp) { ! 1241: vput(*vpp); ! 1242: *vpp = 0; ! 1243: } ! 1244: if ((cnp->cn_flags & SAVESTART) == 0) ! 1245: FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI); ! 1246: vput(dvp); ! 1247: return (error); ! 1248: } ! 1249: ! 1250: /* ! 1251: * Vnode op for readdir ! 1252: */ ! 1253: static int ! 1254: devfs_readdir(struct vop_readdir_args *ap) ! 1255: /*struct vop_readdir_args { ! 1256: struct vnode *a_vp; ! 1257: struct uio *a_uio; ! 1258: struct ucred *a_cred; ! 1259: int *eofflag; ! 1260: int *ncookies; ! 1261: u_int **cookies; ! 1262: } */ ! 1263: { ! 1264: struct vnode *vp = ap->a_vp; ! 1265: struct uio *uio = ap->a_uio; ! 1266: struct dirent dirent; ! 1267: devnode_t * dir_node; ! 1268: devdirent_t * name_node; ! 1269: char *name; ! 1270: int error = 0; ! 1271: int reclen; ! 1272: int nodenumber; ! 1273: int startpos,pos; ! 1274: struct proc * p = uio->uio_procp; ! 1275: ! 1276: /* set up refs to dir */ ! 1277: dir_node = VTODN(vp); ! 1278: if(dir_node->dn_type != DEV_DIR) ! 1279: return(ENOTDIR); ! 1280: ! 1281: pos = 0; ! 1282: startpos = uio->uio_offset; ! 1283: DEVFS_LOCK(p); ! 1284: name_node = dir_node->dn_typeinfo.Dir.dirlist; ! 1285: nodenumber = 0; ! 1286: dir_node->dn_flags |= DN_ACCESS; ! 1287: ! 1288: while ((name_node || (nodenumber < 2)) && (uio->uio_resid > 0)) ! 1289: { ! 1290: switch(nodenumber) ! 1291: { ! 1292: case 0: ! 1293: dirent.d_fileno = (int32_t)(void *)dir_node; ! 1294: name = "."; ! 1295: dirent.d_namlen = 1; ! 1296: dirent.d_type = DT_DIR; ! 1297: break; ! 1298: case 1: ! 1299: if(dir_node->dn_typeinfo.Dir.parent) ! 1300: dirent.d_fileno ! 1301: = (int32_t)dir_node->dn_typeinfo.Dir.parent; ! 1302: else ! 1303: dirent.d_fileno = (u_int32_t)dir_node; ! 1304: name = ".."; ! 1305: dirent.d_namlen = 2; ! 1306: dirent.d_type = DT_DIR; ! 1307: break; ! 1308: default: ! 1309: dirent.d_fileno = (int32_t)(void *)name_node->de_dnp; ! 1310: dirent.d_namlen = strlen(name_node->de_name); ! 1311: name = name_node->de_name; ! 1312: switch(name_node->de_dnp->dn_type) { ! 1313: case DEV_BDEV: ! 1314: dirent.d_type = DT_BLK; ! 1315: break; ! 1316: case DEV_CDEV: ! 1317: dirent.d_type = DT_CHR; ! 1318: break; ! 1319: case DEV_DIR: ! 1320: dirent.d_type = DT_DIR; ! 1321: break; ! 1322: case DEV_SLNK: ! 1323: dirent.d_type = DT_LNK; ! 1324: break; ! 1325: default: ! 1326: dirent.d_type = DT_UNKNOWN; ! 1327: } ! 1328: } ! 1329: #define GENERIC_DIRSIZ(dp) \ ! 1330: ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) ! 1331: ! 1332: reclen = dirent.d_reclen = GENERIC_DIRSIZ(&dirent); ! 1333: ! 1334: if(pos >= startpos) /* made it to the offset yet? */ ! 1335: { ! 1336: if (uio->uio_resid < reclen) /* will it fit? */ ! 1337: break; ! 1338: strcpy( dirent.d_name,name); ! 1339: if ((error = uiomove ((caddr_t)&dirent, ! 1340: dirent.d_reclen, uio)) != 0) ! 1341: break; ! 1342: } ! 1343: pos += reclen; ! 1344: if((nodenumber >1) && name_node) ! 1345: name_node = name_node->de_next; ! 1346: nodenumber++; ! 1347: } ! 1348: DEVFS_UNLOCK(p); ! 1349: uio->uio_offset = pos; ! 1350: ! 1351: return (error); ! 1352: } ! 1353: ! 1354: ! 1355: /* ! 1356: */ ! 1357: static int ! 1358: devfs_readlink(struct vop_readlink_args *ap) ! 1359: /*struct vop_readlink_args { ! 1360: struct vnode *a_vp; ! 1361: struct uio *a_uio; ! 1362: struct ucred *a_cred; ! 1363: } */ ! 1364: { ! 1365: struct vnode *vp = ap->a_vp; ! 1366: struct uio *uio = ap->a_uio; ! 1367: devnode_t * lnk_node; ! 1368: int error = 0; ! 1369: ! 1370: /* set up refs to dir */ ! 1371: lnk_node = VTODN(vp); ! 1372: if(lnk_node->dn_type != DEV_SLNK) ! 1373: return(EINVAL); ! 1374: if ((error = VOP_ACCESS(vp, VREAD, ap->a_cred, NULL)) != 0) { /* XXX */ ! 1375: return error; ! 1376: } ! 1377: error = uiomove(lnk_node->dn_typeinfo.Slnk.name, ! 1378: lnk_node->dn_typeinfo.Slnk.namelen, uio); ! 1379: return error; ! 1380: } ! 1381: ! 1382: static int ! 1383: devfs_abortop(struct vop_abortop_args *ap) ! 1384: /*struct vop_abortop_args { ! 1385: struct vnode *a_dvp; ! 1386: struct componentname *a_cnp; ! 1387: } */ ! 1388: { ! 1389: if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) { ! 1390: FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI); ! 1391: } ! 1392: return 0; ! 1393: } ! 1394: ! 1395: ! 1396: static int ! 1397: devfs_reclaim(struct vop_reclaim_args *ap) ! 1398: /*struct vop_reclaim_args { ! 1399: struct vnode *a_vp; ! 1400: } */ ! 1401: { ! 1402: struct vnode * vp = ap->a_vp; ! 1403: devnode_t * dnp = VTODN(vp); ! 1404: ! 1405: if (dnp) { ! 1406: /* ! 1407: * do the same as devfs_inactive in case it is not called ! 1408: * before us (can that ever happen?) ! 1409: */ ! 1410: dnp->dn_vn = NULL; ! 1411: vp->v_data = NULL; ! 1412: if (dnp->dn_delete) { ! 1413: devnode_free(dnp); ! 1414: } ! 1415: } ! 1416: return(0); ! 1417: } ! 1418: ! 1419: /* ! 1420: * Print out the contents of a /devfs vnode. ! 1421: */ ! 1422: static int ! 1423: devfs_print(struct vop_print_args *ap) ! 1424: /*struct vop_print_args { ! 1425: struct vnode *a_vp; ! 1426: } */ ! 1427: { ! 1428: ! 1429: return (0); ! 1430: } ! 1431: ! 1432: /**************************************************************************\ ! 1433: * pseudo ops * ! 1434: \**************************************************************************/ ! 1435: ! 1436: /* ! 1437: * ! 1438: * struct vop_inactive_args { ! 1439: * struct vnode *a_vp; ! 1440: * struct proc *a_p; ! 1441: * } ! 1442: */ ! 1443: ! 1444: static int ! 1445: devfs_inactive(struct vop_inactive_args *ap) ! 1446: { ! 1447: struct vnode * vp = ap->a_vp; ! 1448: devnode_t * dnp = VTODN(vp); ! 1449: ! 1450: if (dnp) { ! 1451: dnp->dn_vn = NULL; ! 1452: vp->v_data = NULL; ! 1453: if (dnp->dn_delete) { ! 1454: devnode_free(dnp); ! 1455: } ! 1456: } ! 1457: VOP_UNLOCK(vp, 0, ap->a_p); ! 1458: return (0); ! 1459: } ! 1460: ! 1461: int ! 1462: devfs_update(ap) ! 1463: struct vop_update_args /* { ! 1464: struct vnode *a_vp; ! 1465: struct timeval *a_access; ! 1466: struct timeval *a_modify; ! 1467: int a_waitfor; ! 1468: } */ *ap; ! 1469: { ! 1470: register struct fs *fs; ! 1471: int error; ! 1472: devnode_t * ip; ! 1473: ! 1474: ip = VTODN(ap->a_vp); ! 1475: if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) { ! 1476: ip->dn_flags &= ! 1477: ~(DN_ACCESS | DN_CHANGE | DN_MODIFIED | DN_UPDATE); ! 1478: return (0); ! 1479: } ! 1480: if ((ip->dn_flags & ! 1481: (DN_ACCESS | DN_CHANGE | DN_MODIFIED | DN_UPDATE)) == 0) ! 1482: return (0); ! 1483: dn_times(ip, time, time); ! 1484: return (0); ! 1485: } ! 1486: ! 1487: /* The following ops are used by directories and symlinks */ ! 1488: int (**devfs_vnodeop_p)(); ! 1489: static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = { ! 1490: { &vop_default_desc, vn_default_error }, ! 1491: { &vop_lookup_desc, devfs_lookup }, /* lookup */ ! 1492: { &vop_create_desc, err_create }, /* create */ ! 1493: { &vop_whiteout_desc, err_whiteout }, /* whiteout */ ! 1494: { &vop_mknod_desc, devfs_mknod }, /* mknod */ ! 1495: { &vop_open_desc, nop_open }, /* open */ ! 1496: { &vop_close_desc, devfs_close }, /* close */ ! 1497: { &vop_access_desc, devfs_access }, /* access */ ! 1498: { &vop_getattr_desc, devfs_getattr }, /* getattr */ ! 1499: { &vop_setattr_desc, devfs_setattr }, /* setattr */ ! 1500: { &vop_read_desc, devfs_read }, /* read */ ! 1501: { &vop_write_desc, devfs_write }, /* write */ ! 1502: { &vop_lease_desc, nop_lease }, /* lease */ ! 1503: { &vop_ioctl_desc, err_ioctl }, /* ioctl */ ! 1504: { &vop_select_desc, err_select }, /* select */ ! 1505: { &vop_revoke_desc, err_revoke }, /* revoke */ ! 1506: { &vop_mmap_desc, err_mmap }, /* mmap */ ! 1507: { &vop_fsync_desc, nop_fsync }, /* fsync */ ! 1508: { &vop_seek_desc, err_seek }, /* seek */ ! 1509: { &vop_remove_desc, devfs_remove }, /* remove */ ! 1510: { &vop_link_desc, devfs_link }, /* link */ ! 1511: { &vop_rename_desc, devfs_rename }, /* rename */ ! 1512: { &vop_mkdir_desc, err_mkdir }, /* mkdir */ ! 1513: { &vop_rmdir_desc, err_rmdir }, /* rmdir */ ! 1514: { &vop_symlink_desc, devfs_symlink }, /* symlink */ ! 1515: { &vop_readdir_desc, devfs_readdir }, /* readdir */ ! 1516: { &vop_readlink_desc, devfs_readlink }, /* readlink */ ! 1517: { &vop_abortop_desc, devfs_abortop }, /* abortop */ ! 1518: { &vop_inactive_desc, devfs_inactive }, /* inactive */ ! 1519: { &vop_reclaim_desc, devfs_reclaim }, /* reclaim */ ! 1520: { &vop_lock_desc, nop_lock }, /* lock */ ! 1521: { &vop_unlock_desc, nop_unlock }, /* unlock */ ! 1522: { &vop_bmap_desc, err_bmap }, /* bmap */ ! 1523: { &vop_strategy_desc, err_strategy }, /* strategy */ ! 1524: { &vop_print_desc, err_print }, /* print */ ! 1525: { &vop_islocked_desc, nop_islocked }, /* islocked */ ! 1526: { &vop_pathconf_desc, err_pathconf }, /* pathconf */ ! 1527: { &vop_advlock_desc, err_advlock }, /* advlock */ ! 1528: { &vop_blkatoff_desc, err_blkatoff }, /* blkatoff */ ! 1529: { &vop_valloc_desc, err_valloc }, /* valloc */ ! 1530: { &vop_reallocblks_desc, err_reallocblks }, /* reallocblks */ ! 1531: { &vop_vfree_desc, err_vfree }, /* vfree */ ! 1532: { &vop_truncate_desc, err_truncate }, /* truncate */ ! 1533: { &vop_update_desc, devfs_update }, /* update */ ! 1534: { &vop_bwrite_desc, err_bwrite }, ! 1535: { &vop_pagein_desc, err_pagein }, /* Pagein */ ! 1536: { &vop_pageout_desc, err_pageout }, /* Pageout */ ! 1537: { &vop_copyfile_desc, err_copyfile }, /* Copyfile */ ! 1538: { (struct vnodeop_desc*)NULL, (int(*)())NULL } ! 1539: }; ! 1540: struct vnodeopv_desc devfs_vnodeop_opv_desc = ! 1541: { &devfs_vnodeop_p, devfs_vnodeop_entries }; ! 1542: ! 1543: /* The following ops are used by the device nodes */ ! 1544: int (**devfs_spec_vnodeop_p)(); ! 1545: static struct vnodeopv_entry_desc devfs_spec_vnodeop_entries[] = { ! 1546: { &vop_default_desc, vn_default_error }, ! 1547: { &vop_lookup_desc, spec_lookup }, /* lookup */ ! 1548: { &vop_create_desc, spec_create }, /* create */ ! 1549: { &vop_mknod_desc, spec_mknod }, /* mknod */ ! 1550: { &vop_open_desc, spec_open }, /* open */ ! 1551: { &vop_close_desc, devfsspec_close }, /* close */ ! 1552: { &vop_access_desc, devfs_access }, /* access */ ! 1553: { &vop_getattr_desc, devfs_getattr }, /* getattr */ ! 1554: { &vop_setattr_desc, devfs_setattr }, /* setattr */ ! 1555: { &vop_read_desc, devfsspec_read }, /* read */ ! 1556: { &vop_write_desc, devfsspec_write }, /* write */ ! 1557: { &vop_lease_desc, spec_lease_check }, /* lease */ ! 1558: { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ ! 1559: { &vop_select_desc, spec_select }, /* select */ ! 1560: { &vop_revoke_desc, spec_revoke }, /* revoke */ ! 1561: { &vop_mmap_desc, spec_mmap }, /* mmap */ ! 1562: { &vop_fsync_desc, spec_fsync }, /* fsync */ ! 1563: { &vop_seek_desc, spec_seek }, /* seek */ ! 1564: { &vop_remove_desc, devfs_remove }, /* remove */ ! 1565: { &vop_link_desc, devfs_link }, /* link */ ! 1566: { &vop_rename_desc, spec_rename }, /* rename */ ! 1567: { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ ! 1568: { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ ! 1569: { &vop_symlink_desc, spec_symlink }, /* symlink */ ! 1570: { &vop_readdir_desc, spec_readdir }, /* readdir */ ! 1571: { &vop_readlink_desc, spec_readlink }, /* readlink */ ! 1572: { &vop_abortop_desc, spec_abortop }, /* abortop */ ! 1573: { &vop_inactive_desc, devfs_inactive }, /* inactive */ ! 1574: { &vop_reclaim_desc, devfs_reclaim }, /* reclaim */ ! 1575: { &vop_lock_desc, nop_lock }, /* lock */ ! 1576: { &vop_unlock_desc, nop_unlock }, /* unlock */ ! 1577: { &vop_bmap_desc, spec_bmap }, /* bmap */ ! 1578: { &vop_strategy_desc, spec_strategy }, /* strategy */ ! 1579: { &vop_print_desc, devfs_print }, /* print */ ! 1580: { &vop_islocked_desc, nop_islocked }, /* islocked */ ! 1581: { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ ! 1582: { &vop_advlock_desc, spec_advlock }, /* advlock */ ! 1583: { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ ! 1584: { &vop_valloc_desc, spec_valloc }, /* valloc */ ! 1585: { &vop_reallocblks_desc, spec_reallocblks }, /* reallocblks */ ! 1586: { &vop_vfree_desc, nop_vfree }, /* vfree */ ! 1587: { &vop_truncate_desc, spec_truncate }, /* truncate */ ! 1588: { &vop_update_desc, devfs_update }, /* update */ ! 1589: { &vop_bwrite_desc, vn_bwrite }, ! 1590: #ifdef NeXT ! 1591: { &vop_devblocksize_desc, spec_devblocksize }, /* devblocksize */ ! 1592: #endif /* NeXT */ ! 1593: { &vop_pagein_desc, spec_pagein }, /* Pagein */ ! 1594: { &vop_pageout_desc, spec_pageout }, /* Pageout */ ! 1595: { &vop_copyfile_desc, err_copyfile }, /* Copyfile */ ! 1596: { (struct vnodeop_desc*)NULL, (int(*)())NULL } ! 1597: }; ! 1598: struct vnodeopv_desc devfs_spec_vnodeop_opv_desc = ! 1599: { &devfs_spec_vnodeop_p, devfs_spec_vnodeop_entries }; ! 1600:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.