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