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