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