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_dirent **dde; 301 struct devfs_mount *dmp; 302 dev_t cdev; 303 int error, flags, nameiop; 304 char specname[SPECNAMELEN + 1], *pname; 305 306 cnp = ap->a_cnp; 307 vpp = ap->a_vpp; 308 dvp = ap->a_dvp; 309 pname = cnp->cn_nameptr; 310 td = cnp->cn_thread; 311 flags = cnp->cn_flags; 312 nameiop = cnp->cn_nameiop; 313 dmp = VFSTODEVFS(dvp->v_mount); 314 dd = dvp->v_data; 315 316 *vpp = NULLVP; 317 cnp->cn_flags &= ~PDIRUNLOCK; 318 319 if ((flags & ISLASTCN) && nameiop == RENAME) 320 return (EOPNOTSUPP); 321 322 if (dvp->v_type != VDIR) 323 return (ENOTDIR); 324 325 if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT)) 326 return (EIO); 327 328 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td); 329 if (error) 330 return (error); 331 332 if (cnp->cn_namelen == 1 && *pname == '.') { 333 if ((flags & ISLASTCN) && nameiop != LOOKUP) 334 return (EINVAL); 335 *vpp = dvp; 336 VREF(dvp); 337 return (0); 338 } 339 340 if (flags & ISDOTDOT) { 341 if ((flags & ISLASTCN) && nameiop != LOOKUP) 342 return (EINVAL); 343 VOP_UNLOCK(dvp, 0, td); 344 cnp->cn_flags |= PDIRUNLOCK; 345 de = TAILQ_FIRST(&dd->de_dlist); /* "." */ 346 de = TAILQ_NEXT(de, de_list); /* ".." */ 347 de = de->de_dir; 348 error = devfs_allocv(de, dvp->v_mount, vpp, td); 349 if (error || ((flags & LOCKPARENT) && (flags & ISLASTCN))) { 350 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); 351 cnp->cn_flags &= ~PDIRUNLOCK; 352 } 353 return (error); 354 } 355 356 devfs_populate(dmp); 357 dd = dvp->v_data; 358 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 359 if (cnp->cn_namelen != de->de_dirent->d_namlen) 360 continue; 361 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 362 de->de_dirent->d_namlen) != 0) 363 continue; 364 if (de->de_flags & DE_WHITEOUT) 365 goto notfound; 366 goto found; 367 } 368 369 if (nameiop == DELETE) 370 goto notfound; 371 372 /* 373 * OK, we didn't have an entry for the name we were asked for 374 * so we try to see if anybody can create it on demand. 375 */ 376 pname = devfs_fqpn(specname, dvp, cnp); 377 if (pname == NULL) 378 goto notfound; 379 380 cdev = NODEV; 381 EVENTHANDLER_INVOKE(dev_clone, pname, strlen(pname), &cdev); 382 if (cdev == NODEV) 383 goto notfound; 384 385 devfs_populate(dmp); 386 387 dde = devfs_itode(dmp, cdev->si_inode); 388 389 if (dde == NULL || *dde == NULL || *dde == DE_DELETED) 390 goto notfound; 391 392 if ((*dde)->de_flags & DE_WHITEOUT) 393 goto notfound; 394 395 de = *dde; 396 goto found; 397 398 notfound: 399 400 if ((nameiop == CREATE || nameiop == RENAME) && 401 (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) { 402 cnp->cn_flags |= SAVENAME; 403 if (!(flags & LOCKPARENT)) { 404 VOP_UNLOCK(dvp, 0, td); 405 cnp->cn_flags |= PDIRUNLOCK; 406 } 407 return (EJUSTRETURN); 408 } 409 return (ENOENT); 410 411 412 found: 413 414 if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) { 415 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 416 if (error) 417 return (error); 418 if (*vpp == dvp) { 419 VREF(dvp); 420 *vpp = dvp; 421 return (0); 422 } 423 error = devfs_allocv(de, dvp->v_mount, vpp, td); 424 if (error) 425 return (error); 426 if (!(flags & LOCKPARENT)) { 427 VOP_UNLOCK(dvp, 0, td); 428 cnp->cn_flags |= PDIRUNLOCK; 429 } 430 return (0); 431 } 432 error = devfs_allocv(de, dvp->v_mount, vpp, td); 433 if (error) 434 return (error); 435 if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) { 436 VOP_UNLOCK(dvp, 0, td); 437 cnp->cn_flags |= PDIRUNLOCK; 438 } 439 return (0); 440 } 441 442 static int 443 devfs_lookup(struct vop_lookup_args *ap) 444 { 445 int j; 446 struct devfs_mount *dmp; 447 448 dmp = VFSTODEVFS(ap->a_dvp->v_mount); 449 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread); 450 j = devfs_lookupx(ap); 451 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 452 return (j); 453 } 454 455 static int 456 devfs_mknod(struct vop_mknod_args *ap) 457 /* 458 struct vop_mknod_args { 459 struct vnodeop_desc *a_desc; 460 struct vnode *a_dvp; 461 struct vnode **a_vpp; 462 struct componentname *a_cnp; 463 struct vattr *a_vap; 464 }; 465 */ 466 { 467 struct componentname *cnp; 468 struct vnode *dvp, **vpp; 469 struct thread *td; 470 struct devfs_dirent *dd, *de; 471 struct devfs_mount *dmp; 472 int error; 473 474 dvp = ap->a_dvp; 475 dmp = VFSTODEVFS(dvp->v_mount); 476 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 477 478 cnp = ap->a_cnp; 479 vpp = ap->a_vpp; 480 td = cnp->cn_thread; 481 dd = dvp->v_data; 482 483 error = ENOENT; 484 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 485 if (cnp->cn_namelen != de->de_dirent->d_namlen) 486 continue; 487 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 488 de->de_dirent->d_namlen) != 0) 489 continue; 490 if (de->de_flags & DE_WHITEOUT) 491 break; 492 goto notfound; 493 } 494 if (de == NULL) 495 goto notfound; 496 de->de_flags &= ~DE_WHITEOUT; 497 error = devfs_allocv(de, dvp->v_mount, vpp, td); 498 notfound: 499 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 500 return (error); 501 } 502 503 504 static int 505 devfs_pathconf(ap) 506 struct vop_pathconf_args /* { 507 struct vnode *a_vp; 508 int a_name; 509 int *a_retval; 510 } */ *ap; 511 { 512 513 switch (ap->a_name) { 514 case _PC_NAME_MAX: 515 *ap->a_retval = NAME_MAX; 516 return (0); 517 case _PC_PATH_MAX: 518 *ap->a_retval = PATH_MAX; 519 return (0); 520 case _PC_MAC_PRESENT: 521 #ifdef MAC 522 /* 523 * If MAC is enabled, devfs automatically supports 524 * trivial non-persistant label storage. 525 */ 526 *ap->a_retval = 1; 527 #else 528 *ap->a_retval = 0; 529 #endif 530 return (0); 531 default: 532 return (vop_stdpathconf(ap)); 533 } 534 /* NOTREACHED */ 535 } 536 537 static int 538 devfs_read(ap) 539 struct vop_read_args /* { 540 struct vnode *a_vp; 541 struct uio *a_uio; 542 int a_ioflag; 543 struct ucred *a_cred; 544 } */ *ap; 545 { 546 547 if (ap->a_vp->v_type != VDIR) 548 return (EINVAL); 549 return (VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred, NULL, NULL, NULL)); 550 } 551 552 static int 553 devfs_readdir(ap) 554 struct vop_readdir_args /* { 555 struct vnode *a_vp; 556 struct uio *a_uio; 557 struct ucred *a_cred; 558 int *a_eofflag; 559 int *a_ncookies; 560 u_long **a_cookies; 561 } */ *ap; 562 { 563 int error; 564 struct uio *uio; 565 struct dirent *dp; 566 struct devfs_dirent *dd; 567 struct devfs_dirent *de; 568 struct devfs_mount *dmp; 569 off_t off, oldoff; 570 int ncookies = 0; 571 u_long *cookiebuf, *cookiep; 572 struct dirent *dps, *dpe; 573 574 if (ap->a_vp->v_type != VDIR) 575 return (ENOTDIR); 576 577 uio = ap->a_uio; 578 if (uio->uio_offset < 0) 579 return (EINVAL); 580 581 dmp = VFSTODEVFS(ap->a_vp->v_mount); 582 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread); 583 devfs_populate(dmp); 584 error = 0; 585 de = ap->a_vp->v_data; 586 off = 0; 587 oldoff = uio->uio_offset; 588 TAILQ_FOREACH(dd, &de->de_dlist, de_list) { 589 if (dd->de_flags & DE_WHITEOUT) 590 continue; 591 if (dd->de_dirent->d_type == DT_DIR) 592 de = dd->de_dir; 593 else 594 de = dd; 595 dp = dd->de_dirent; 596 if (dp->d_reclen > uio->uio_resid) 597 break; 598 dp->d_fileno = de->de_inode; 599 if (off >= uio->uio_offset) { 600 ncookies++; 601 error = uiomove(dp, dp->d_reclen, uio); 602 if (error) 603 break; 604 } 605 off += dp->d_reclen; 606 } 607 if( !error && ap->a_ncookies != NULL && ap->a_cookies != NULL ) { 608 MALLOC(cookiebuf, u_long *, ncookies * sizeof(u_long), 609 M_TEMP, M_WAITOK); 610 cookiep = cookiebuf; 611 dps = (struct dirent *)((char *)uio->uio_iov->iov_base - 612 (uio->uio_offset - oldoff)); 613 dpe = (struct dirent *) uio->uio_iov->iov_base; 614 for( dp = dps; 615 dp < dpe; 616 dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) { 617 oldoff += dp->d_reclen; 618 *cookiep++ = (u_long) oldoff; 619 } 620 *ap->a_ncookies = ncookies; 621 *ap->a_cookies = cookiebuf; 622 } 623 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 624 uio->uio_offset = off; 625 return (error); 626 } 627 628 static int 629 devfs_readlink(ap) 630 struct vop_readlink_args /* { 631 struct vnode *a_vp; 632 struct uio *a_uio; 633 struct ucred *a_cead; 634 } */ *ap; 635 { 636 int error; 637 struct devfs_dirent *de; 638 639 de = ap->a_vp->v_data; 640 error = uiomove(de->de_symlink, strlen(de->de_symlink), ap->a_uio); 641 return (error); 642 } 643 644 static int 645 devfs_reclaim(ap) 646 struct vop_reclaim_args /* { 647 struct vnode *a_vp; 648 } */ *ap; 649 { 650 struct vnode *vp = ap->a_vp; 651 struct devfs_dirent *de; 652 int i; 653 654 de = vp->v_data; 655 if (de != NULL) 656 de->de_vnode = NULL; 657 vp->v_data = NULL; 658 if (vp->v_rdev != NODEV && vp->v_rdev != NULL) { 659 i = vcount(vp); 660 if ((vp->v_rdev->si_flags & SI_CHEAPCLONE) && i == 0 && 661 (vp->v_rdev->si_flags & SI_NAMED)) 662 destroy_dev(vp->v_rdev); 663 } 664 return (0); 665 } 666 667 static int 668 devfs_remove(ap) 669 struct vop_remove_args /* { 670 struct vnode *a_dvp; 671 struct vnode *a_vp; 672 struct componentname *a_cnp; 673 } */ *ap; 674 { 675 struct vnode *vp = ap->a_vp; 676 struct devfs_dirent *dd; 677 struct devfs_dirent *de; 678 struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount); 679 680 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 681 dd = ap->a_dvp->v_data; 682 de = vp->v_data; 683 if (de->de_dirent->d_type == DT_LNK) { 684 TAILQ_REMOVE(&dd->de_dlist, de, de_list); 685 if (de->de_vnode) 686 de->de_vnode->v_data = NULL; 687 #ifdef MAC 688 mac_destroy_devfsdirent(de); 689 #endif 690 FREE(de, M_DEVFS); 691 } else { 692 de->de_flags |= DE_WHITEOUT; 693 } 694 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 695 return (0); 696 } 697 698 /* 699 * Revoke is called on a tty when a terminal session ends. The vnode 700 * is orphaned by setting v_op to deadfs so we need to let go of it 701 * as well so that we create a new one next time around. 702 */ 703 static int 704 devfs_revoke(ap) 705 struct vop_revoke_args /* { 706 struct vnode *a_vp; 707 int a_flags; 708 } */ *ap; 709 { 710 struct vnode *vp = ap->a_vp; 711 struct devfs_dirent *de; 712 713 de = vp->v_data; 714 de->de_vnode = NULL; 715 vop_revoke(ap); 716 return (0); 717 } 718 719 static int 720 devfs_setattr(ap) 721 struct vop_setattr_args /* { 722 struct vnode *a_vp; 723 struct vattr *a_vap; 724 struct ucred *a_cred; 725 struct proc *a_p; 726 } */ *ap; 727 { 728 struct devfs_dirent *de; 729 struct vattr *vap; 730 struct vnode *vp; 731 int c, error; 732 uid_t uid; 733 gid_t gid; 734 735 vap = ap->a_vap; 736 vp = ap->a_vp; 737 if ((vap->va_type != VNON) || 738 (vap->va_nlink != VNOVAL) || 739 (vap->va_fsid != VNOVAL) || 740 (vap->va_fileid != VNOVAL) || 741 (vap->va_blocksize != VNOVAL) || 742 (vap->va_flags != VNOVAL && vap->va_flags != 0) || 743 (vap->va_rdev != VNOVAL) || 744 ((int)vap->va_bytes != VNOVAL) || 745 (vap->va_gen != VNOVAL)) { 746 return (EINVAL); 747 } 748 749 de = vp->v_data; 750 if (vp->v_type == VDIR) 751 de = de->de_dir; 752 753 error = c = 0; 754 if (vap->va_uid == (uid_t)VNOVAL) 755 uid = de->de_uid; 756 else 757 uid = vap->va_uid; 758 if (vap->va_gid == (gid_t)VNOVAL) 759 gid = de->de_gid; 760 else 761 gid = vap->va_gid; 762 if (uid != de->de_uid || gid != de->de_gid) { 763 if (((ap->a_cred->cr_uid != de->de_uid) || uid != de->de_uid || 764 (gid != de->de_gid && !groupmember(gid, ap->a_cred))) && 765 (error = suser_cred(ap->a_td->td_ucred, PRISON_ROOT)) != 0) 766 return (error); 767 de->de_uid = uid; 768 de->de_gid = gid; 769 c = 1; 770 } 771 772 if (vap->va_mode != (mode_t)VNOVAL) { 773 if ((ap->a_cred->cr_uid != de->de_uid) && 774 (error = suser_cred(ap->a_td->td_ucred, PRISON_ROOT))) 775 return (error); 776 de->de_mode = vap->va_mode; 777 c = 1; 778 } 779 780 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 781 /* See the comment in ufs_vnops::ufs_setattr(). */ 782 if ((error = VOP_ACCESS(vp, VADMIN, ap->a_cred, ap->a_td)) && 783 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 784 (error = VOP_ACCESS(vp, VWRITE, ap->a_cred, ap->a_td)))) 785 return (error); 786 if (vap->va_atime.tv_sec != VNOVAL) { 787 if (vp->v_type == VCHR) 788 vp->v_rdev->si_atime = vap->va_atime; 789 else 790 de->de_atime = vap->va_atime; 791 } 792 if (vap->va_mtime.tv_sec != VNOVAL) { 793 if (vp->v_type == VCHR) 794 vp->v_rdev->si_mtime = vap->va_mtime; 795 else 796 de->de_mtime = vap->va_mtime; 797 } 798 c = 1; 799 } 800 801 if (c) { 802 if (vp->v_type == VCHR) 803 vfs_timestamp(&vp->v_rdev->si_ctime); 804 else 805 vfs_timestamp(&de->de_mtime); 806 } 807 return (0); 808 } 809 810 #ifdef MAC 811 static int 812 devfs_setlabel(ap) 813 struct vop_setlabel_args /* { 814 struct vnode *a_vp; 815 struct mac *a_label; 816 struct ucred *a_cred; 817 struct thread *a_td; 818 } */ *ap; 819 { 820 struct vnode *vp; 821 struct devfs_dirent *de; 822 823 vp = ap->a_vp; 824 de = vp->v_data; 825 826 mac_relabel_vnode(ap->a_cred, vp, ap->a_label); 827 mac_update_devfsdirent(vp->v_mount, de, vp); 828 829 return (0); 830 } 831 #endif 832 833 static int 834 devfs_symlink(ap) 835 struct vop_symlink_args /* { 836 struct vnode *a_dvp; 837 struct vnode **a_vpp; 838 struct componentname *a_cnp; 839 struct vattr *a_vap; 840 char *a_target; 841 } */ *ap; 842 { 843 int i, error; 844 struct devfs_dirent *dd; 845 struct devfs_dirent *de; 846 struct devfs_mount *dmp; 847 848 error = suser(ap->a_cnp->cn_thread); 849 if (error) 850 return(error); 851 dmp = VFSTODEVFS(ap->a_dvp->v_mount); 852 dd = ap->a_dvp->v_data; 853 de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen); 854 de->de_uid = 0; 855 de->de_gid = 0; 856 de->de_mode = 0755; 857 de->de_inode = dmp->dm_inode++; 858 de->de_dirent->d_type = DT_LNK; 859 i = strlen(ap->a_target) + 1; 860 MALLOC(de->de_symlink, char *, i, M_DEVFS, M_WAITOK); 861 bcopy(ap->a_target, de->de_symlink, i); 862 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 863 #ifdef MAC 864 mac_create_devfs_symlink(ap->a_cnp->cn_cred, dmp->dm_mount, dd, de); 865 #endif 866 TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); 867 devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, 0); 868 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 869 return (0); 870 } 871 872 static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = { 873 { &vop_default_desc, (vop_t *) vop_defaultop }, 874 { &vop_access_desc, (vop_t *) devfs_access }, 875 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 876 { &vop_ioctl_desc, (vop_t *) devfs_ioctl }, 877 { &vop_lookup_desc, (vop_t *) devfs_lookup }, 878 { &vop_mknod_desc, (vop_t *) devfs_mknod }, 879 { &vop_pathconf_desc, (vop_t *) devfs_pathconf }, 880 { &vop_read_desc, (vop_t *) devfs_read }, 881 { &vop_readdir_desc, (vop_t *) devfs_readdir }, 882 { &vop_readlink_desc, (vop_t *) devfs_readlink }, 883 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 884 { &vop_remove_desc, (vop_t *) devfs_remove }, 885 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 886 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 887 #ifdef MAC 888 { &vop_setlabel_desc, (vop_t *) devfs_setlabel }, 889 #endif 890 { &vop_symlink_desc, (vop_t *) devfs_symlink }, 891 { NULL, NULL } 892 }; 893 static struct vnodeopv_desc devfs_vnodeop_opv_desc = 894 { &devfs_vnodeop_p, devfs_vnodeop_entries }; 895 896 VNODEOP_SET(devfs_vnodeop_opv_desc); 897 898 static struct vnodeopv_entry_desc devfs_specop_entries[] = { 899 { &vop_default_desc, (vop_t *) spec_vnoperate }, 900 { &vop_access_desc, (vop_t *) devfs_access }, 901 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 902 { &vop_pathconf_desc, (vop_t *) devfs_pathconf }, 903 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 904 { &vop_remove_desc, (vop_t *) devfs_remove }, 905 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 906 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 907 #ifdef MAC 908 { &vop_setlabel_desc, (vop_t *) devfs_setlabel }, 909 #endif 910 { NULL, NULL } 911 }; 912 static struct vnodeopv_desc devfs_specop_opv_desc = 913 { &devfs_specop_p, devfs_specop_entries }; 914 915 VNODEOP_SET(devfs_specop_opv_desc); 916