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