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_vflag & VV_ROOT)) 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 case _POSIX_MAC_PRESENT: 513 #ifdef MAC 514 /* 515 * If MAC is enabled, devfs automatically supports 516 * trivial non-persistant label storage. 517 */ 518 *ap->a_retval = 1; 519 #else 520 *ap->a_retval = 0; 521 #endif /* MAC */ 522 return (0); 523 default: 524 return (vop_stdpathconf(ap)); 525 } 526 /* NOTREACHED */ 527 } 528 529 /* ARGSUSED */ 530 static int 531 devfs_print(ap) 532 struct vop_print_args /* { 533 struct vnode *a_vp; 534 } */ *ap; 535 { 536 537 printf("tag VT_DEVFS, devfs vnode\n"); 538 return (0); 539 } 540 541 static int 542 devfs_read(ap) 543 struct vop_read_args /* { 544 struct vnode *a_vp; 545 struct uio *a_uio; 546 int a_ioflag; 547 struct ucred *a_cred; 548 } */ *ap; 549 { 550 551 if (ap->a_vp->v_type != VDIR) 552 return (EINVAL); 553 return (VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred, NULL, NULL, NULL)); 554 } 555 556 static int 557 devfs_readdir(ap) 558 struct vop_readdir_args /* { 559 struct vnode *a_vp; 560 struct uio *a_uio; 561 struct ucred *a_cred; 562 int *a_eofflag; 563 int *a_ncookies; 564 u_long **a_cookies; 565 } */ *ap; 566 { 567 int error; 568 struct uio *uio; 569 struct dirent *dp; 570 struct devfs_dirent *dd; 571 struct devfs_dirent *de; 572 struct devfs_mount *dmp; 573 off_t off, oldoff; 574 int ncookies = 0; 575 u_long *cookiebuf, *cookiep; 576 struct dirent *dps, *dpe; 577 578 if (ap->a_vp->v_type != VDIR) 579 return (ENOTDIR); 580 581 uio = ap->a_uio; 582 if (uio->uio_offset < 0) 583 return (EINVAL); 584 585 dmp = VFSTODEVFS(ap->a_vp->v_mount); 586 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread); 587 devfs_populate(dmp); 588 error = 0; 589 de = ap->a_vp->v_data; 590 off = 0; 591 oldoff = uio->uio_offset; 592 TAILQ_FOREACH(dd, &de->de_dlist, de_list) { 593 if (dd->de_flags & DE_WHITEOUT) 594 continue; 595 if (dd->de_dirent->d_type == DT_DIR) 596 de = dd->de_dir; 597 else 598 de = dd; 599 dp = dd->de_dirent; 600 if (dp->d_reclen > uio->uio_resid) 601 break; 602 dp->d_fileno = de->de_inode; 603 if (off >= uio->uio_offset) { 604 ncookies++; 605 error = uiomove((caddr_t)dp, dp->d_reclen, uio); 606 if (error) 607 break; 608 } 609 off += dp->d_reclen; 610 } 611 if( !error && ap->a_ncookies != NULL && ap->a_cookies != NULL ) { 612 MALLOC(cookiebuf, u_long *, ncookies * sizeof(u_long), 613 M_TEMP, M_WAITOK); 614 cookiep = cookiebuf; 615 dps = (struct dirent *) 616 (uio->uio_iov->iov_base - (uio->uio_offset - oldoff)); 617 dpe = (struct dirent *) uio->uio_iov->iov_base; 618 for( dp = dps; 619 dp < dpe; 620 dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) { 621 oldoff += dp->d_reclen; 622 *cookiep++ = (u_long) oldoff; 623 } 624 *ap->a_ncookies = ncookies; 625 *ap->a_cookies = cookiebuf; 626 } 627 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 628 uio->uio_offset = off; 629 return (error); 630 } 631 632 static int 633 devfs_readlink(ap) 634 struct vop_readlink_args /* { 635 struct vnode *a_vp; 636 struct uio *a_uio; 637 struct ucred *a_cead; 638 } */ *ap; 639 { 640 int error; 641 struct devfs_dirent *de; 642 643 de = ap->a_vp->v_data; 644 error = uiomove(de->de_symlink, strlen(de->de_symlink), ap->a_uio); 645 return (error); 646 } 647 648 static int 649 devfs_reclaim(ap) 650 struct vop_reclaim_args /* { 651 struct vnode *a_vp; 652 } */ *ap; 653 { 654 struct vnode *vp = ap->a_vp; 655 struct devfs_dirent *de; 656 int i; 657 658 de = vp->v_data; 659 if (de != NULL) 660 de->de_vnode = NULL; 661 vp->v_data = NULL; 662 if (vp->v_rdev != NODEV && vp->v_rdev != NULL) { 663 i = vcount(vp); 664 if ((vp->v_rdev->si_flags & SI_CHEAPCLONE) && i == 0 && 665 (vp->v_rdev->si_flags & SI_NAMED)) 666 destroy_dev(vp->v_rdev); 667 } 668 return (0); 669 } 670 671 #ifdef MAC 672 static int 673 devfs_refreshlabel(ap) 674 struct vop_refreshlabel_args /* { 675 struct vnode *a_vp; 676 struct ucred *a_cred; 677 } */ *ap; 678 { 679 680 /* Labels are always in sync. */ 681 return (0); 682 } 683 #endif 684 685 static int 686 devfs_remove(ap) 687 struct vop_remove_args /* { 688 struct vnode *a_dvp; 689 struct vnode *a_vp; 690 struct componentname *a_cnp; 691 } */ *ap; 692 { 693 struct vnode *vp = ap->a_vp; 694 struct devfs_dirent *dd; 695 struct devfs_dirent *de; 696 struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount); 697 698 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 699 dd = ap->a_dvp->v_data; 700 de = vp->v_data; 701 if (de->de_dirent->d_type == DT_LNK) { 702 TAILQ_REMOVE(&dd->de_dlist, de, de_list); 703 if (de->de_vnode) 704 de->de_vnode->v_data = NULL; 705 #ifdef MAC 706 mac_destroy_devfsdirent(de); 707 #endif 708 FREE(de, M_DEVFS); 709 } else { 710 de->de_flags |= DE_WHITEOUT; 711 } 712 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 713 return (0); 714 } 715 716 /* 717 * Revoke is called on a tty when a terminal session ends. The vnode 718 * is orphaned by setting v_op to deadfs so we need to let go of it 719 * as well so that we create a new one next time around. 720 */ 721 static int 722 devfs_revoke(ap) 723 struct vop_revoke_args /* { 724 struct vnode *a_vp; 725 int a_flags; 726 } */ *ap; 727 { 728 struct vnode *vp = ap->a_vp; 729 struct devfs_dirent *de; 730 731 de = vp->v_data; 732 de->de_vnode = NULL; 733 vop_revoke(ap); 734 return (0); 735 } 736 737 static int 738 devfs_setattr(ap) 739 struct vop_setattr_args /* { 740 struct vnode *a_vp; 741 struct vattr *a_vap; 742 struct ucred *a_cred; 743 struct proc *a_p; 744 } */ *ap; 745 { 746 struct devfs_dirent *de; 747 struct vattr *vap; 748 struct vnode *vp; 749 int c, error; 750 uid_t uid; 751 gid_t gid; 752 753 vap = ap->a_vap; 754 vp = ap->a_vp; 755 if ((vap->va_type != VNON) || 756 (vap->va_nlink != VNOVAL) || 757 (vap->va_fsid != VNOVAL) || 758 (vap->va_fileid != VNOVAL) || 759 (vap->va_blocksize != VNOVAL) || 760 (vap->va_flags != VNOVAL && vap->va_flags != 0) || 761 (vap->va_rdev != VNOVAL) || 762 ((int)vap->va_bytes != VNOVAL) || 763 (vap->va_gen != VNOVAL)) { 764 return (EINVAL); 765 } 766 767 de = vp->v_data; 768 if (vp->v_type == VDIR) 769 de = de->de_dir; 770 771 error = c = 0; 772 if (vap->va_uid == (uid_t)VNOVAL) 773 uid = de->de_uid; 774 else 775 uid = vap->va_uid; 776 if (vap->va_gid == (gid_t)VNOVAL) 777 gid = de->de_gid; 778 else 779 gid = vap->va_gid; 780 if (uid != de->de_uid || gid != de->de_gid) { 781 if (((ap->a_cred->cr_uid != de->de_uid) || uid != de->de_uid || 782 (gid != de->de_gid && !groupmember(gid, ap->a_cred))) && 783 (error = suser_cred(ap->a_td->td_ucred, PRISON_ROOT)) != 0) 784 return (error); 785 de->de_uid = uid; 786 de->de_gid = gid; 787 c = 1; 788 } 789 790 if (vap->va_mode != (mode_t)VNOVAL) { 791 if ((ap->a_cred->cr_uid != de->de_uid) && 792 (error = suser_cred(ap->a_td->td_ucred, PRISON_ROOT))) 793 return (error); 794 de->de_mode = vap->va_mode; 795 c = 1; 796 } 797 798 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 799 /* See the comment in ufs_vnops::ufs_setattr(). */ 800 if ((error = VOP_ACCESS(vp, VADMIN, ap->a_cred, ap->a_td)) && 801 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 802 (error = VOP_ACCESS(vp, VWRITE, ap->a_cred, ap->a_td)))) 803 return (error); 804 if (vap->va_atime.tv_sec != VNOVAL) { 805 if (vp->v_type == VCHR) 806 vp->v_rdev->si_atime = vap->va_atime; 807 else 808 de->de_atime = vap->va_atime; 809 } 810 if (vap->va_mtime.tv_sec != VNOVAL) { 811 if (vp->v_type == VCHR) 812 vp->v_rdev->si_mtime = vap->va_mtime; 813 else 814 de->de_mtime = vap->va_mtime; 815 } 816 c = 1; 817 } 818 819 if (c) { 820 if (vp->v_type == VCHR) 821 vfs_timestamp(&vp->v_rdev->si_ctime); 822 else 823 vfs_timestamp(&de->de_mtime); 824 } 825 return (0); 826 } 827 828 #ifdef MAC 829 static int 830 devfs_setlabel(ap) 831 struct vop_setlabel_args /* { 832 struct vnode *a_vp; 833 struct mac *a_label; 834 struct ucred *a_cred; 835 struct thread *a_td; 836 } */ *ap; 837 { 838 struct vnode *vp; 839 struct devfs_dirent *de; 840 841 vp = ap->a_vp; 842 de = vp->v_data; 843 844 mac_relabel_vnode(ap->a_cred, vp, ap->a_label); 845 mac_update_devfsdirent(de, vp); 846 847 return (0); 848 } 849 #endif 850 851 static int 852 devfs_symlink(ap) 853 struct vop_symlink_args /* { 854 struct vnode *a_dvp; 855 struct vnode **a_vpp; 856 struct componentname *a_cnp; 857 struct vattr *a_vap; 858 char *a_target; 859 } */ *ap; 860 { 861 int i, error; 862 struct devfs_dirent *dd; 863 struct devfs_dirent *de; 864 struct devfs_mount *dmp; 865 866 error = suser(ap->a_cnp->cn_thread); 867 if (error) 868 return(error); 869 dmp = VFSTODEVFS(ap->a_dvp->v_mount); 870 dd = ap->a_dvp->v_data; 871 de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen); 872 de->de_uid = 0; 873 de->de_gid = 0; 874 de->de_mode = 0755; 875 de->de_inode = dmp->dm_inode++; 876 de->de_dirent->d_type = DT_LNK; 877 i = strlen(ap->a_target) + 1; 878 MALLOC(de->de_symlink, char *, i, M_DEVFS, M_WAITOK); 879 bcopy(ap->a_target, de->de_symlink, i); 880 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 881 TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); 882 devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, 0); 883 #ifdef MAC 884 mac_create_vnode(ap->a_cnp->cn_cred, ap->a_dvp, *ap->a_vpp); 885 mac_update_devfsdirent(de, *ap->a_vpp); 886 #endif /* MAC */ 887 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 888 return (0); 889 } 890 891 static vop_t **devfs_vnodeop_p; 892 static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = { 893 { &vop_default_desc, (vop_t *) vop_defaultop }, 894 { &vop_access_desc, (vop_t *) devfs_access }, 895 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 896 { &vop_ioctl_desc, (vop_t *) devfs_ioctl }, 897 { &vop_islocked_desc, (vop_t *) vop_stdislocked }, 898 { &vop_lock_desc, (vop_t *) vop_stdlock }, 899 { &vop_lookup_desc, (vop_t *) devfs_lookup }, 900 { &vop_mknod_desc, (vop_t *) devfs_mknod }, 901 { &vop_pathconf_desc, (vop_t *) devfs_pathconf }, 902 { &vop_print_desc, (vop_t *) devfs_print }, 903 { &vop_read_desc, (vop_t *) devfs_read }, 904 { &vop_readdir_desc, (vop_t *) devfs_readdir }, 905 { &vop_readlink_desc, (vop_t *) devfs_readlink }, 906 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 907 { &vop_remove_desc, (vop_t *) devfs_remove }, 908 #ifdef MAC 909 { &vop_refreshlabel_desc, (vop_t *) devfs_refreshlabel }, 910 #endif 911 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 912 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 913 #ifdef MAC 914 { &vop_setlabel_desc, (vop_t *) devfs_setlabel }, 915 #endif 916 { &vop_symlink_desc, (vop_t *) devfs_symlink }, 917 { &vop_unlock_desc, (vop_t *) vop_stdunlock }, 918 { NULL, NULL } 919 }; 920 static struct vnodeopv_desc devfs_vnodeop_opv_desc = 921 { &devfs_vnodeop_p, devfs_vnodeop_entries }; 922 923 VNODEOP_SET(devfs_vnodeop_opv_desc); 924 925 static vop_t **devfs_specop_p; 926 static struct vnodeopv_entry_desc devfs_specop_entries[] = { 927 { &vop_default_desc, (vop_t *) spec_vnoperate }, 928 { &vop_access_desc, (vop_t *) devfs_access }, 929 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 930 { &vop_islocked_desc, (vop_t *) vop_stdislocked }, 931 { &vop_lock_desc, (vop_t *) vop_stdlock }, 932 { &vop_pathconf_desc, (vop_t *) devfs_pathconf }, 933 { &vop_print_desc, (vop_t *) devfs_print }, 934 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 935 #ifdef MAC 936 { &vop_refreshlabel_desc, (vop_t *) devfs_refreshlabel }, 937 #endif 938 { &vop_remove_desc, (vop_t *) devfs_remove }, 939 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 940 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 941 #ifdef MAC 942 { &vop_setlabel_desc, (vop_t *) devfs_setlabel }, 943 #endif 944 { &vop_unlock_desc, (vop_t *) vop_stdunlock }, 945 { NULL, NULL } 946 }; 947 static struct vnodeopv_desc devfs_specop_opv_desc = 948 { &devfs_specop_p, devfs_specop_entries }; 949 950 VNODEOP_SET(devfs_specop_opv_desc); 951 #endif 952