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