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