1 /* 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 2000 5 * Poul-Henning Kamp. All rights reserved. 6 * 7 * This code is derived from software donated to Berkeley by 8 * Jan-Simon Pendry. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)kernfs_vnops.c 8.15 (Berkeley) 5/21/95 32 * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vnops.c 1.43 33 * 34 * $FreeBSD$ 35 */ 36 37 /* 38 * TODO: 39 * remove empty directories 40 * mknod: hunt down DE_DELETED, compare name, reinstantiate. 41 * mkdir: want it ? 42 */ 43 44 #include <opt_devfs.h> 45 #include <opt_mac.h> 46 #ifndef NODEVFS 47 48 #include <sys/param.h> 49 #include <sys/systm.h> 50 #include <sys/conf.h> 51 #include <sys/dirent.h> 52 #include <sys/kernel.h> 53 #include <sys/lock.h> 54 #include <sys/mac.h> 55 #include <sys/malloc.h> 56 #include <sys/mount.h> 57 #include <sys/namei.h> 58 #include <sys/proc.h> 59 #include <sys/time.h> 60 #include <sys/unistd.h> 61 #include <sys/vnode.h> 62 63 #include <fs/devfs/devfs.h> 64 65 static int devfs_access(struct vop_access_args *ap); 66 static int devfs_getattr(struct vop_getattr_args *ap); 67 static int devfs_ioctl(struct vop_ioctl_args *ap); 68 static int devfs_lookupx(struct vop_lookup_args *ap); 69 static int devfs_mknod(struct vop_mknod_args *ap); 70 static int devfs_pathconf(struct vop_pathconf_args *ap); 71 static int devfs_read(struct vop_read_args *ap); 72 static int devfs_readdir(struct vop_readdir_args *ap); 73 static int devfs_readlink(struct vop_readlink_args *ap); 74 static int devfs_reclaim(struct vop_reclaim_args *ap); 75 static int devfs_remove(struct vop_remove_args *ap); 76 static int devfs_revoke(struct vop_revoke_args *ap); 77 static int devfs_setattr(struct vop_setattr_args *ap); 78 #ifdef MAC 79 static int devfs_setlabel(struct vop_setlabel_args *ap); 80 #endif 81 static int devfs_symlink(struct vop_symlink_args *ap); 82 83 static vop_t **devfs_vnodeop_p; 84 static vop_t **devfs_specop_p; 85 86 /* 87 * Construct the fully qualified path name relative to the mountpoint 88 */ 89 static char * 90 devfs_fqpn(char *buf, struct vnode *dvp, struct componentname *cnp) 91 { 92 int i; 93 struct devfs_dirent *de, *dd; 94 struct devfs_mount *dmp; 95 96 dmp = VFSTODEVFS(dvp->v_mount); 97 dd = dvp->v_data; 98 i = SPECNAMELEN; 99 buf[i] = '\0'; 100 i -= cnp->cn_namelen; 101 if (i < 0) 102 return (NULL); 103 bcopy(cnp->cn_nameptr, buf + i, cnp->cn_namelen); 104 de = dd; 105 while (de != dmp->dm_basedir) { 106 i--; 107 if (i < 0) 108 return (NULL); 109 buf[i] = '/'; 110 i -= de->de_dirent->d_namlen; 111 if (i < 0) 112 return (NULL); 113 bcopy(de->de_dirent->d_name, buf + i, 114 de->de_dirent->d_namlen); 115 de = TAILQ_FIRST(&de->de_dlist); /* "." */ 116 de = TAILQ_NEXT(de, de_list); /* ".." */ 117 de = de->de_dir; 118 } 119 return (buf + i); 120 } 121 122 int 123 devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct thread *td) 124 { 125 int error; 126 struct vnode *vp; 127 dev_t dev; 128 129 if (td == NULL) 130 td = curthread; /* XXX */ 131 loop: 132 vp = de->de_vnode; 133 if (vp != NULL) { 134 if (vget(vp, LK_EXCLUSIVE, td ? td : curthread)) 135 goto loop; 136 *vpp = vp; 137 return (0); 138 } 139 if (de->de_dirent->d_type == DT_CHR) { 140 dev = *devfs_itod(de->de_inode); 141 if (dev == NULL) 142 return (ENOENT); 143 } else { 144 dev = NODEV; 145 } 146 error = getnewvnode("devfs", mp, devfs_vnodeop_p, &vp); 147 if (error != 0) { 148 printf("devfs_allocv: failed to allocate new vnode\n"); 149 return (error); 150 } 151 152 if (de->de_dirent->d_type == DT_CHR) { 153 vp->v_type = VCHR; 154 vp = addaliasu(vp, dev->si_udev); 155 vp->v_op = devfs_specop_p; 156 } else if (de->de_dirent->d_type == DT_DIR) { 157 vp->v_type = VDIR; 158 } else if (de->de_dirent->d_type == DT_LNK) { 159 vp->v_type = VLNK; 160 } else { 161 vp->v_type = VBAD; 162 } 163 vp->v_data = de; 164 de->de_vnode = vp; 165 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 166 #ifdef MAC 167 mac_associate_vnode_devfs(mp, de, vp); 168 #endif 169 *vpp = vp; 170 return (0); 171 } 172 173 static int 174 devfs_access(ap) 175 struct vop_access_args /* { 176 struct vnode *a_vp; 177 int a_mode; 178 struct ucred *a_cred; 179 struct thread *a_td; 180 } */ *ap; 181 { 182 struct vnode *vp = ap->a_vp; 183 struct devfs_dirent *de; 184 int error; 185 186 de = vp->v_data; 187 if (vp->v_type == VDIR) 188 de = de->de_dir; 189 190 error = vaccess(vp->v_type, de->de_mode, de->de_uid, de->de_gid, 191 ap->a_mode, ap->a_cred, NULL); 192 if (!error) 193 return (error); 194 if (error != EACCES) 195 return (error); 196 /* We do, however, allow access to the controlling terminal */ 197 if (!(ap->a_td->td_proc->p_flag & P_CONTROLT)) 198 return (error); 199 if (ap->a_td->td_proc->p_session->s_ttyvp == de->de_vnode) 200 return (0); 201 return (error); 202 } 203 204 static int 205 devfs_getattr(ap) 206 struct vop_getattr_args /* { 207 struct vnode *a_vp; 208 struct vattr *a_vap; 209 struct ucred *a_cred; 210 struct thread *a_td; 211 } */ *ap; 212 { 213 struct vnode *vp = ap->a_vp; 214 struct vattr *vap = ap->a_vap; 215 int error = 0; 216 struct devfs_dirent *de; 217 dev_t dev; 218 219 de = vp->v_data; 220 if (vp->v_type == VDIR) 221 de = de->de_dir; 222 bzero((caddr_t) vap, sizeof(*vap)); 223 vattr_null(vap); 224 vap->va_uid = de->de_uid; 225 vap->va_gid = de->de_gid; 226 vap->va_mode = de->de_mode; 227 if (vp->v_type == VLNK) 228 vap->va_size = de->de_dirent->d_namlen; 229 else if (vp->v_type == VDIR) 230 vap->va_size = vap->va_bytes = DEV_BSIZE; 231 else 232 vap->va_size = 0; 233 if (vp->v_type != VDIR) 234 vap->va_bytes = 0; 235 vap->va_blocksize = DEV_BSIZE; 236 vap->va_type = vp->v_type; 237 238 #define fix(aa) \ 239 do { \ 240 if ((aa).tv_sec == 0) { \ 241 (aa).tv_sec = boottime.tv_sec; \ 242 (aa).tv_nsec = boottime.tv_usec * 1000; \ 243 } \ 244 } while (0) 245 246 if (vp->v_type != VCHR) { 247 fix(de->de_atime); 248 vap->va_atime = de->de_atime; 249 fix(de->de_mtime); 250 vap->va_mtime = de->de_mtime; 251 fix(de->de_ctime); 252 vap->va_ctime = de->de_ctime; 253 } else { 254 dev = vp->v_rdev; 255 fix(dev->si_atime); 256 vap->va_atime = dev->si_atime; 257 fix(dev->si_mtime); 258 vap->va_mtime = dev->si_mtime; 259 fix(dev->si_ctime); 260 vap->va_ctime = dev->si_ctime; 261 vap->va_rdev = dev->si_udev; 262 } 263 vap->va_gen = 0; 264 vap->va_flags = 0; 265 vap->va_nlink = de->de_links; 266 vap->va_fileid = de->de_inode; 267 268 return (error); 269 } 270 271 static int 272 devfs_ioctl(ap) 273 struct vop_ioctl_args /* { 274 struct vnode *a_vp; 275 u_long a_command; 276 caddr_t a_data; 277 int a_fflag; 278 struct ucred *a_cred; 279 struct thread *a_td; 280 } */ *ap; 281 { 282 int error; 283 284 error = devfs_rules_ioctl(ap->a_vp->v_mount, ap->a_command, ap->a_data, 285 ap->a_td); 286 return (error); 287 } 288 289 static int 290 devfs_lookupx(ap) 291 struct vop_lookup_args /* { 292 struct vnode * a_dvp; 293 struct vnode ** a_vpp; 294 struct componentname * a_cnp; 295 } */ *ap; 296 { 297 struct componentname *cnp; 298 struct vnode *dvp, **vpp; 299 struct thread *td; 300 struct devfs_dirent *de, *dd; 301 struct devfs_mount *dmp; 302 dev_t cdev, *cpdev; 303 int error, cloned, flags, nameiop; 304 char specname[SPECNAMELEN + 1], *pname; 305 306 cnp = ap->a_cnp; 307 vpp = ap->a_vpp; 308 dvp = ap->a_dvp; 309 pname = cnp->cn_nameptr; 310 td = cnp->cn_thread; 311 flags = cnp->cn_flags; 312 nameiop = cnp->cn_nameiop; 313 dmp = VFSTODEVFS(dvp->v_mount); 314 cloned = 0; 315 dd = dvp->v_data; 316 317 *vpp = NULLVP; 318 cnp->cn_flags &= ~PDIRUNLOCK; 319 320 if ((flags & ISLASTCN) && nameiop == RENAME) 321 return (EOPNOTSUPP); 322 323 if (dvp->v_type != VDIR) 324 return (ENOTDIR); 325 326 if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT)) 327 return (EIO); 328 329 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td); 330 if (error) 331 return (error); 332 333 if (cnp->cn_namelen == 1 && *pname == '.') { 334 if ((flags & ISLASTCN) && nameiop != LOOKUP) 335 return (EINVAL); 336 *vpp = dvp; 337 VREF(dvp); 338 return (0); 339 } 340 341 if (flags & ISDOTDOT) { 342 if ((flags & ISLASTCN) && nameiop != LOOKUP) 343 return (EINVAL); 344 VOP_UNLOCK(dvp, 0, td); 345 cnp->cn_flags |= PDIRUNLOCK; 346 de = TAILQ_FIRST(&dd->de_dlist); /* "." */ 347 de = TAILQ_NEXT(de, de_list); /* ".." */ 348 de = de->de_dir; 349 error = devfs_allocv(de, dvp->v_mount, vpp, td); 350 if (error || ((flags & LOCKPARENT) && (flags & ISLASTCN))) { 351 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); 352 cnp->cn_flags &= ~PDIRUNLOCK; 353 } 354 return (error); 355 } 356 357 devfs_populate(dmp); 358 dd = dvp->v_data; 359 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 360 if (cnp->cn_namelen != de->de_dirent->d_namlen) 361 continue; 362 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 363 de->de_dirent->d_namlen) != 0) 364 continue; 365 if (de->de_flags & DE_WHITEOUT) 366 goto notfound; 367 goto found; 368 } 369 370 if (nameiop == DELETE) 371 goto notfound; 372 373 /* 374 * OK, we didn't have an entry for the name we were asked for 375 * so we try to see if anybody can create it on demand. 376 */ 377 pname = devfs_fqpn(specname, dvp, cnp); 378 if (pname == NULL) 379 goto notfound; 380 381 cdev = NODEV; 382 EVENTHANDLER_INVOKE(dev_clone, pname, strlen(pname), &cdev); 383 if (cdev == NODEV) 384 goto notfound; 385 386 devfs_populate(dmp); 387 dd = dvp->v_data; 388 389 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 390 cpdev = devfs_itod(de->de_inode); 391 if (cpdev != NULL && cdev == *cpdev) 392 goto found; 393 continue; 394 } 395 396 notfound: 397 398 if ((nameiop == CREATE || nameiop == RENAME) && 399 (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) { 400 cnp->cn_flags |= SAVENAME; 401 if (!(flags & LOCKPARENT)) { 402 VOP_UNLOCK(dvp, 0, td); 403 cnp->cn_flags |= PDIRUNLOCK; 404 } 405 return (EJUSTRETURN); 406 } 407 return (ENOENT); 408 409 410 found: 411 412 if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) { 413 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 414 if (error) 415 return (error); 416 if (*vpp == dvp) { 417 VREF(dvp); 418 *vpp = dvp; 419 return (0); 420 } 421 error = devfs_allocv(de, dvp->v_mount, vpp, td); 422 if (error) 423 return (error); 424 if (!(flags & LOCKPARENT)) { 425 VOP_UNLOCK(dvp, 0, td); 426 cnp->cn_flags |= PDIRUNLOCK; 427 } 428 return (0); 429 } 430 error = devfs_allocv(de, dvp->v_mount, vpp, td); 431 if (error) 432 return (error); 433 if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) { 434 VOP_UNLOCK(dvp, 0, td); 435 cnp->cn_flags |= PDIRUNLOCK; 436 } 437 return (0); 438 } 439 440 static int 441 devfs_lookup(struct vop_lookup_args *ap) 442 { 443 int j; 444 struct devfs_mount *dmp; 445 446 dmp = VFSTODEVFS(ap->a_dvp->v_mount); 447 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread); 448 j = devfs_lookupx(ap); 449 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 450 return (j); 451 } 452 453 static int 454 devfs_mknod(struct vop_mknod_args *ap) 455 /* 456 struct vop_mknod_args { 457 struct vnodeop_desc *a_desc; 458 struct vnode *a_dvp; 459 struct vnode **a_vpp; 460 struct componentname *a_cnp; 461 struct vattr *a_vap; 462 }; 463 */ 464 { 465 struct componentname *cnp; 466 struct vnode *dvp, **vpp; 467 struct thread *td; 468 struct devfs_dirent *dd, *de; 469 struct devfs_mount *dmp; 470 int cloned, flags, nameiop; 471 int error; 472 473 dvp = ap->a_dvp; 474 dmp = VFSTODEVFS(dvp->v_mount); 475 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 476 477 cnp = ap->a_cnp; 478 vpp = ap->a_vpp; 479 td = cnp->cn_thread; 480 flags = cnp->cn_flags; 481 nameiop = cnp->cn_nameiop; 482 cloned = 0; 483 dd = dvp->v_data; 484 485 error = ENOENT; 486 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 487 if (cnp->cn_namelen != de->de_dirent->d_namlen) 488 continue; 489 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 490 de->de_dirent->d_namlen) != 0) 491 continue; 492 if (de->de_flags & DE_WHITEOUT) 493 break; 494 goto notfound; 495 } 496 if (de == NULL) 497 goto notfound; 498 de->de_flags &= ~DE_WHITEOUT; 499 error = devfs_allocv(de, dvp->v_mount, vpp, td); 500 notfound: 501 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 502 return (error); 503 } 504 505 506 static int 507 devfs_pathconf(ap) 508 struct vop_pathconf_args /* { 509 struct vnode *a_vp; 510 int a_name; 511 int *a_retval; 512 } */ *ap; 513 { 514 515 switch (ap->a_name) { 516 case _PC_NAME_MAX: 517 *ap->a_retval = NAME_MAX; 518 return (0); 519 case _PC_PATH_MAX: 520 *ap->a_retval = PATH_MAX; 521 return (0); 522 case _PC_MAC_PRESENT: 523 #ifdef MAC 524 /* 525 * If MAC is enabled, devfs automatically supports 526 * trivial non-persistant label storage. 527 */ 528 *ap->a_retval = 1; 529 #else 530 *ap->a_retval = 0; 531 #endif 532 return (0); 533 default: 534 return (vop_stdpathconf(ap)); 535 } 536 /* NOTREACHED */ 537 } 538 539 static int 540 devfs_read(ap) 541 struct vop_read_args /* { 542 struct vnode *a_vp; 543 struct uio *a_uio; 544 int a_ioflag; 545 struct ucred *a_cred; 546 } */ *ap; 547 { 548 549 if (ap->a_vp->v_type != VDIR) 550 return (EINVAL); 551 return (VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred, NULL, NULL, NULL)); 552 } 553 554 static int 555 devfs_readdir(ap) 556 struct vop_readdir_args /* { 557 struct vnode *a_vp; 558 struct uio *a_uio; 559 struct ucred *a_cred; 560 int *a_eofflag; 561 int *a_ncookies; 562 u_long **a_cookies; 563 } */ *ap; 564 { 565 int error; 566 struct uio *uio; 567 struct dirent *dp; 568 struct devfs_dirent *dd; 569 struct devfs_dirent *de; 570 struct devfs_mount *dmp; 571 off_t off, oldoff; 572 int ncookies = 0; 573 u_long *cookiebuf, *cookiep; 574 struct dirent *dps, *dpe; 575 576 if (ap->a_vp->v_type != VDIR) 577 return (ENOTDIR); 578 579 uio = ap->a_uio; 580 if (uio->uio_offset < 0) 581 return (EINVAL); 582 583 dmp = VFSTODEVFS(ap->a_vp->v_mount); 584 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread); 585 devfs_populate(dmp); 586 error = 0; 587 de = ap->a_vp->v_data; 588 off = 0; 589 oldoff = uio->uio_offset; 590 TAILQ_FOREACH(dd, &de->de_dlist, de_list) { 591 if (dd->de_flags & DE_WHITEOUT) 592 continue; 593 if (dd->de_dirent->d_type == DT_DIR) 594 de = dd->de_dir; 595 else 596 de = dd; 597 dp = dd->de_dirent; 598 if (dp->d_reclen > uio->uio_resid) 599 break; 600 dp->d_fileno = de->de_inode; 601 if (off >= uio->uio_offset) { 602 ncookies++; 603 error = uiomove((caddr_t)dp, dp->d_reclen, uio); 604 if (error) 605 break; 606 } 607 off += dp->d_reclen; 608 } 609 if( !error && ap->a_ncookies != NULL && ap->a_cookies != NULL ) { 610 MALLOC(cookiebuf, u_long *, ncookies * sizeof(u_long), 611 M_TEMP, 0); 612 cookiep = cookiebuf; 613 dps = (struct dirent *)((char *)uio->uio_iov->iov_base - 614 (uio->uio_offset - oldoff)); 615 dpe = (struct dirent *) uio->uio_iov->iov_base; 616 for( dp = dps; 617 dp < dpe; 618 dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) { 619 oldoff += dp->d_reclen; 620 *cookiep++ = (u_long) oldoff; 621 } 622 *ap->a_ncookies = ncookies; 623 *ap->a_cookies = cookiebuf; 624 } 625 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 626 uio->uio_offset = off; 627 return (error); 628 } 629 630 static int 631 devfs_readlink(ap) 632 struct vop_readlink_args /* { 633 struct vnode *a_vp; 634 struct uio *a_uio; 635 struct ucred *a_cead; 636 } */ *ap; 637 { 638 int error; 639 struct devfs_dirent *de; 640 641 de = ap->a_vp->v_data; 642 error = uiomove(de->de_symlink, strlen(de->de_symlink), ap->a_uio); 643 return (error); 644 } 645 646 static int 647 devfs_reclaim(ap) 648 struct vop_reclaim_args /* { 649 struct vnode *a_vp; 650 } */ *ap; 651 { 652 struct vnode *vp = ap->a_vp; 653 struct devfs_dirent *de; 654 int i; 655 656 de = vp->v_data; 657 if (de != NULL) 658 de->de_vnode = NULL; 659 vp->v_data = NULL; 660 if (vp->v_rdev != NODEV && vp->v_rdev != NULL) { 661 i = vcount(vp); 662 if ((vp->v_rdev->si_flags & SI_CHEAPCLONE) && i == 0 && 663 (vp->v_rdev->si_flags & SI_NAMED)) 664 destroy_dev(vp->v_rdev); 665 } 666 return (0); 667 } 668 669 static int 670 devfs_remove(ap) 671 struct vop_remove_args /* { 672 struct vnode *a_dvp; 673 struct vnode *a_vp; 674 struct componentname *a_cnp; 675 } */ *ap; 676 { 677 struct vnode *vp = ap->a_vp; 678 struct devfs_dirent *dd; 679 struct devfs_dirent *de; 680 struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount); 681 682 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 683 dd = ap->a_dvp->v_data; 684 de = vp->v_data; 685 if (de->de_dirent->d_type == DT_LNK) { 686 TAILQ_REMOVE(&dd->de_dlist, de, de_list); 687 if (de->de_vnode) 688 de->de_vnode->v_data = NULL; 689 #ifdef MAC 690 mac_destroy_devfsdirent(de); 691 #endif 692 FREE(de, M_DEVFS); 693 } else { 694 de->de_flags |= DE_WHITEOUT; 695 } 696 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 697 return (0); 698 } 699 700 /* 701 * Revoke is called on a tty when a terminal session ends. The vnode 702 * is orphaned by setting v_op to deadfs so we need to let go of it 703 * as well so that we create a new one next time around. 704 */ 705 static int 706 devfs_revoke(ap) 707 struct vop_revoke_args /* { 708 struct vnode *a_vp; 709 int a_flags; 710 } */ *ap; 711 { 712 struct vnode *vp = ap->a_vp; 713 struct devfs_dirent *de; 714 715 de = vp->v_data; 716 de->de_vnode = NULL; 717 vop_revoke(ap); 718 return (0); 719 } 720 721 static int 722 devfs_setattr(ap) 723 struct vop_setattr_args /* { 724 struct vnode *a_vp; 725 struct vattr *a_vap; 726 struct ucred *a_cred; 727 struct proc *a_p; 728 } */ *ap; 729 { 730 struct devfs_dirent *de; 731 struct vattr *vap; 732 struct vnode *vp; 733 int c, error; 734 uid_t uid; 735 gid_t gid; 736 737 vap = ap->a_vap; 738 vp = ap->a_vp; 739 if ((vap->va_type != VNON) || 740 (vap->va_nlink != VNOVAL) || 741 (vap->va_fsid != VNOVAL) || 742 (vap->va_fileid != VNOVAL) || 743 (vap->va_blocksize != VNOVAL) || 744 (vap->va_flags != VNOVAL && vap->va_flags != 0) || 745 (vap->va_rdev != VNOVAL) || 746 ((int)vap->va_bytes != VNOVAL) || 747 (vap->va_gen != VNOVAL)) { 748 return (EINVAL); 749 } 750 751 de = vp->v_data; 752 if (vp->v_type == VDIR) 753 de = de->de_dir; 754 755 error = c = 0; 756 if (vap->va_uid == (uid_t)VNOVAL) 757 uid = de->de_uid; 758 else 759 uid = vap->va_uid; 760 if (vap->va_gid == (gid_t)VNOVAL) 761 gid = de->de_gid; 762 else 763 gid = vap->va_gid; 764 if (uid != de->de_uid || gid != de->de_gid) { 765 if (((ap->a_cred->cr_uid != de->de_uid) || uid != de->de_uid || 766 (gid != de->de_gid && !groupmember(gid, ap->a_cred))) && 767 (error = suser_cred(ap->a_td->td_ucred, PRISON_ROOT)) != 0) 768 return (error); 769 de->de_uid = uid; 770 de->de_gid = gid; 771 c = 1; 772 } 773 774 if (vap->va_mode != (mode_t)VNOVAL) { 775 if ((ap->a_cred->cr_uid != de->de_uid) && 776 (error = suser_cred(ap->a_td->td_ucred, PRISON_ROOT))) 777 return (error); 778 de->de_mode = vap->va_mode; 779 c = 1; 780 } 781 782 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 783 /* See the comment in ufs_vnops::ufs_setattr(). */ 784 if ((error = VOP_ACCESS(vp, VADMIN, ap->a_cred, ap->a_td)) && 785 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 786 (error = VOP_ACCESS(vp, VWRITE, ap->a_cred, ap->a_td)))) 787 return (error); 788 if (vap->va_atime.tv_sec != VNOVAL) { 789 if (vp->v_type == VCHR) 790 vp->v_rdev->si_atime = vap->va_atime; 791 else 792 de->de_atime = vap->va_atime; 793 } 794 if (vap->va_mtime.tv_sec != VNOVAL) { 795 if (vp->v_type == VCHR) 796 vp->v_rdev->si_mtime = vap->va_mtime; 797 else 798 de->de_mtime = vap->va_mtime; 799 } 800 c = 1; 801 } 802 803 if (c) { 804 if (vp->v_type == VCHR) 805 vfs_timestamp(&vp->v_rdev->si_ctime); 806 else 807 vfs_timestamp(&de->de_mtime); 808 } 809 return (0); 810 } 811 812 #ifdef MAC 813 static int 814 devfs_setlabel(ap) 815 struct vop_setlabel_args /* { 816 struct vnode *a_vp; 817 struct mac *a_label; 818 struct ucred *a_cred; 819 struct thread *a_td; 820 } */ *ap; 821 { 822 struct vnode *vp; 823 struct devfs_dirent *de; 824 825 vp = ap->a_vp; 826 de = vp->v_data; 827 828 mac_relabel_vnode(ap->a_cred, vp, ap->a_label); 829 mac_update_devfsdirent(vp->v_mount, de, vp); 830 831 return (0); 832 } 833 #endif 834 835 static int 836 devfs_symlink(ap) 837 struct vop_symlink_args /* { 838 struct vnode *a_dvp; 839 struct vnode **a_vpp; 840 struct componentname *a_cnp; 841 struct vattr *a_vap; 842 char *a_target; 843 } */ *ap; 844 { 845 int i, error; 846 struct devfs_dirent *dd; 847 struct devfs_dirent *de; 848 struct devfs_mount *dmp; 849 850 error = suser(ap->a_cnp->cn_thread); 851 if (error) 852 return(error); 853 dmp = VFSTODEVFS(ap->a_dvp->v_mount); 854 dd = ap->a_dvp->v_data; 855 de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen); 856 de->de_uid = 0; 857 de->de_gid = 0; 858 de->de_mode = 0755; 859 de->de_inode = dmp->dm_inode++; 860 de->de_dirent->d_type = DT_LNK; 861 i = strlen(ap->a_target) + 1; 862 MALLOC(de->de_symlink, char *, i, M_DEVFS, 0); 863 bcopy(ap->a_target, de->de_symlink, i); 864 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 865 #ifdef MAC 866 mac_create_devfs_symlink(ap->a_cnp->cn_cred, dmp->dm_mount, dd, de); 867 #endif 868 TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); 869 devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, 0); 870 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 871 return (0); 872 } 873 874 static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = { 875 { &vop_default_desc, (vop_t *) vop_defaultop }, 876 { &vop_access_desc, (vop_t *) devfs_access }, 877 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 878 { &vop_ioctl_desc, (vop_t *) devfs_ioctl }, 879 { &vop_lookup_desc, (vop_t *) devfs_lookup }, 880 { &vop_mknod_desc, (vop_t *) devfs_mknod }, 881 { &vop_pathconf_desc, (vop_t *) devfs_pathconf }, 882 { &vop_print_desc, (vop_t *) vop_null }, 883 { &vop_read_desc, (vop_t *) devfs_read }, 884 { &vop_readdir_desc, (vop_t *) devfs_readdir }, 885 { &vop_readlink_desc, (vop_t *) devfs_readlink }, 886 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 887 { &vop_remove_desc, (vop_t *) devfs_remove }, 888 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 889 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 890 #ifdef MAC 891 { &vop_setlabel_desc, (vop_t *) devfs_setlabel }, 892 #endif 893 { &vop_symlink_desc, (vop_t *) devfs_symlink }, 894 { NULL, NULL } 895 }; 896 static struct vnodeopv_desc devfs_vnodeop_opv_desc = 897 { &devfs_vnodeop_p, devfs_vnodeop_entries }; 898 899 VNODEOP_SET(devfs_vnodeop_opv_desc); 900 901 static struct vnodeopv_entry_desc devfs_specop_entries[] = { 902 { &vop_default_desc, (vop_t *) spec_vnoperate }, 903 { &vop_access_desc, (vop_t *) devfs_access }, 904 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 905 { &vop_pathconf_desc, (vop_t *) devfs_pathconf }, 906 { &vop_print_desc, (vop_t *) vop_null }, 907 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 908 { &vop_remove_desc, (vop_t *) devfs_remove }, 909 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 910 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 911 #ifdef MAC 912 { &vop_setlabel_desc, (vop_t *) devfs_setlabel }, 913 #endif 914 { NULL, NULL } 915 }; 916 static struct vnodeopv_desc devfs_specop_opv_desc = 917 { &devfs_specop_p, devfs_specop_entries }; 918 919 VNODEOP_SET(devfs_specop_opv_desc); 920 #endif 921