200 return (error); 201} 202 203static int 204devfs_lookupx(ap) 205 struct vop_lookup_args /* { 206 struct vnode * a_dvp; 207 struct vnode ** a_vpp; 208 struct componentname * a_cnp; 209 } */ *ap; 210{ 211 struct componentname *cnp; 212 struct vnode *dvp, **vpp; 213 struct proc *p; 214 struct devfs_dirent *de, *dd; 215 struct devfs_mount *dmp; 216 dev_t cdev; 217 int error, cloned, i, flags, nameiop; 218 char specname[SPECNAMELEN + 1], *pname; 219 220 cnp = ap->a_cnp; 221 vpp = ap->a_vpp; 222 dvp = ap->a_dvp; 223 pname = cnp->cn_nameptr; 224 p = cnp->cn_proc; 225 flags = cnp->cn_flags; 226 nameiop = cnp->cn_nameiop; 227 dmp = VFSTODEVFS(dvp->v_mount); 228 cloned = 0; 229 dd = dvp->v_data; 230 231 *vpp = NULLVP; 232 233 if (nameiop == RENAME) 234 return (EOPNOTSUPP); 235 236 if (dvp->v_type != VDIR) 237 return (ENOTDIR); 238 239 if ((flags & ISDOTDOT) && (dvp->v_flag & VROOT)) 240 return (EIO); 241 242 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_proc); 243 if (error) 244 return (error); 245 246 if (cnp->cn_namelen == 1 && *pname == '.') { 247 if (nameiop != LOOKUP) 248 return (EINVAL); 249 *vpp = dvp; 250 VREF(dvp); 251 return (0); 252 } 253 254 if (flags & ISDOTDOT) { 255 if (nameiop != LOOKUP) 256 return (EINVAL); 257 VOP_UNLOCK(dvp, 0, p); 258 de = TAILQ_FIRST(&dd->de_dlist); /* "." */ 259 de = TAILQ_NEXT(de, de_list); /* ".." */ 260 de = de->de_dir; 261 error = devfs_allocv(de, dvp->v_mount, vpp, p); 262 if (error) { 263 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); 264 return (error); 265 } 266 if ((flags & LOCKPARENT) && (flags & ISLASTCN)) 267 error = vn_lock(dvp, LK_EXCLUSIVE, p); 268 if (error) 269 vput(*vpp); 270 return (error); 271 } 272 273 devfs_populate(dmp); 274 dd = dvp->v_data; 275 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 276 if (cnp->cn_namelen != de->de_dirent->d_namlen) 277 continue; 278 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 279 de->de_dirent->d_namlen) != 0) 280 continue; 281 goto found; 282 } 283 284 /* 285 * OK, we didn't have an entry for the name we were asked for 286 * so we try to see if anybody can create it on demand. 287 * We need to construct the full "devname" for this device 288 * relative to "basedir" or the clone functions would not 289 * be able to tell "/dev/foo" from "/dev/bar/foo" 290 */ 291 i = SPECNAMELEN; 292 specname[i] = '\0'; 293 i -= cnp->cn_namelen; 294 if (i < 0) 295 goto notfound; 296 bcopy(cnp->cn_nameptr, specname + i, cnp->cn_namelen); 297 de = dd; 298 while (de != dmp->dm_basedir) { 299 i--; 300 if (i < 0) 301 goto notfound; 302 specname[i] = '/'; 303 i -= de->de_dirent->d_namlen; 304 if (i < 0) 305 goto notfound; 306 bcopy(de->de_dirent->d_name, specname + i, 307 de->de_dirent->d_namlen); 308 de = TAILQ_FIRST(&de->de_dlist); /* "." */ 309 de = TAILQ_NEXT(de, de_list); /* ".." */ 310 de = de->de_dir; 311 } 312 313#if 0 314 printf("Finished specname: %d \"%s\"\n", i, specname + i); 315#endif 316 cdev = NODEV; 317 EVENTHANDLER_INVOKE(dev_clone, specname + i, 318 strlen(specname + i), &cdev); 319#if 0 320 printf("cloned %s -> %p %s\n", specname + i, cdev, 321 cdev == NODEV ? "NODEV" : cdev->si_name); 322#endif 323 if (cdev == NODEV) 324 goto notfound; 325 326 devfs_populate(dmp); 327 dd = dvp->v_data; 328 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 329 if (cnp->cn_namelen != de->de_dirent->d_namlen) 330 continue; 331 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 332 de->de_dirent->d_namlen) != 0) 333 continue; 334 goto found; 335 } 336 337notfound: 338 339 if ((nameiop == CREATE || nameiop == RENAME) && 340 (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) { 341 cnp->cn_flags |= SAVENAME; 342 if (!(flags & LOCKPARENT)) 343 VOP_UNLOCK(dvp, 0, p); 344 return (EJUSTRETURN); 345 } 346 return (ENOENT); 347 348 349found: 350 351 if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) { 352 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, p); 353 if (error) 354 return (error); 355 if (*vpp == dvp) { 356 VREF(dvp); 357 *vpp = dvp; 358 return (0); 359 } 360 error = devfs_allocv(de, dvp->v_mount, vpp, p); 361 if (error) 362 return (error); 363 if (!(flags & LOCKPARENT)) 364 VOP_UNLOCK(dvp, 0, p); 365 return (0); 366 } 367 error = devfs_allocv(de, dvp->v_mount, vpp, p); 368 if (error) 369 return (error); 370 if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) 371 VOP_UNLOCK(dvp, 0, p); 372 return (0); 373} 374 375static int 376devfs_lookup(struct vop_lookup_args *ap) 377{ 378 int j; 379 struct devfs_mount *dmp; 380 381 dmp = VFSTODEVFS(ap->a_dvp->v_mount); 382 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curproc); 383 j = devfs_lookupx(ap); 384 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc); 385 return (j); 386} 387 388/* ARGSUSED */ 389static int 390devfs_print(ap) 391 struct vop_print_args /* { 392 struct vnode *a_vp; 393 } */ *ap; 394{ 395 396 printf("tag VT_DEVFS, devfs vnode\n"); 397 return (0); 398} 399 400static int 401devfs_read(ap) 402 struct vop_read_args /* { 403 struct vnode *a_vp; 404 struct uio *a_uio; 405 int a_ioflag; 406 struct ucred *a_cred; 407 } */ *ap; 408{ 409 410 if (ap->a_vp->v_type != VDIR) 411 return (EINVAL); 412 return (VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred, NULL, NULL, NULL)); 413} 414 415static int 416devfs_readdir(ap) 417 struct vop_readdir_args /* { 418 struct vnode *a_vp; 419 struct uio *a_uio; 420 struct ucred *a_cred; 421 int *a_eofflag; 422 int *a_ncookies; 423 u_long **a_cookies; 424 } */ *ap; 425{ 426 int error; 427 struct uio *uio; 428 struct dirent *dp; 429 struct devfs_dirent *dd; 430 struct devfs_dirent *de; 431 struct devfs_mount *dmp; 432 off_t off; 433 434 if (ap->a_vp->v_type != VDIR) 435 return (ENOTDIR); 436 437 if (ap->a_ncookies) 438 return (EOPNOTSUPP); 439 440 uio = ap->a_uio; 441 if (uio->uio_offset < 0) 442 return (EINVAL); 443 444 dmp = VFSTODEVFS(ap->a_vp->v_mount); 445 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curproc); 446 devfs_populate(dmp); 447 error = 0; 448 de = ap->a_vp->v_data; 449 dd = TAILQ_FIRST(&de->de_dlist); 450 off = 0; 451 while (dd != NULL) { 452 if (dd->de_dirent->d_type == DT_DIR) 453 de = dd->de_dir; 454 else 455 de = dd; 456 dp = dd->de_dirent; 457 if (dp->d_reclen > uio->uio_resid) 458 break; 459 dp->d_fileno = de->de_inode; 460 if (off >= uio->uio_offset) { 461 error = uiomove((caddr_t)dp, dp->d_reclen, uio); 462 if (error) 463 break; 464 } 465 off += dp->d_reclen; 466 dd = TAILQ_NEXT(dd, de_list); 467 } 468 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc); 469 uio->uio_offset = off; 470 return (error); 471} 472 473static int 474devfs_readlink(ap) 475 struct vop_readlink_args /* { 476 struct vnode *a_vp; 477 struct uio *a_uio; 478 struct ucred *a_cead; 479 } */ *ap; 480{ 481 int error; 482 struct devfs_dirent *de; 483 484 de = ap->a_vp->v_data; 485 error = uiomove(de->de_symlink, strlen(de->de_symlink) + 1, ap->a_uio); 486 return (error); 487} 488 489static int 490devfs_reclaim(ap) 491 struct vop_reclaim_args /* { 492 struct vnode *a_vp; 493 } */ *ap; 494{ 495 struct vnode *vp = ap->a_vp; 496 struct devfs_dirent *de; 497 int i; 498 499 de = vp->v_data; 500 if (de != NULL) 501 de->de_vnode = NULL; 502 if (de != NULL && de->de_flags & DE_ORPHAN) { 503 if (de->de_symlink) 504 FREE(de->de_symlink, M_DEVFS); 505 FREE(de, M_DEVFS); 506 } 507 vp->v_data = NULL; 508 if (vp->v_rdev != NODEV && vp->v_rdev != NULL) { 509 i = vcount(vp); 510 if ((vp->v_rdev->si_flags & SI_CHEAPCLONE) && i == 0) 511 destroy_dev(vp->v_rdev); 512 } 513 return (0); 514} 515 516static int 517devfs_remove(ap) 518 struct vop_remove_args /* { 519 struct vnode *a_dvp; 520 struct vnode *a_vp; 521 struct componentname *a_cnp; 522 } */ *ap; 523{ 524 struct vnode *vp = ap->a_vp; 525 struct devfs_dirent *dd; 526 struct devfs_dirent *de, **dep; 527 struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount); 528 529 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curproc); 530 dd = ap->a_dvp->v_data; 531 de = vp->v_data; 532 TAILQ_REMOVE(&dd->de_dlist, de, de_list); 533 dep = devfs_itode(dmp, de->de_inode); 534 if (dep != NULL) 535 *dep = DE_DELETED; 536 de->de_flags |= DE_ORPHAN; 537 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc); 538 return (0); 539} 540 541/* 542 * Revoke is called on a tty when a terminal session ends. The vnode 543 * is orphaned by setting v_op to deadfs so we need to let go of it 544 * as well so that we create a new one next time around. 545 */ 546static int 547devfs_revoke(ap) 548 struct vop_revoke_args /* { 549 struct vnode *a_vp; 550 int a_flags; 551 } */ *ap; 552{ 553 struct vnode *vp = ap->a_vp; 554 struct devfs_dirent *de; 555 556 de = vp->v_data; 557 de->de_vnode = NULL; 558 vop_revoke(ap); 559 return (0); 560} 561 562static int 563devfs_setattr(ap) 564 struct vop_setattr_args /* { 565 struct vnode *a_vp; 566 struct vattr *a_vap; 567 struct ucred *a_cred; 568 struct proc *a_p; 569 } */ *ap; 570{ 571 struct devfs_dirent *de; 572 struct vattr *vap; 573 int c, error; 574 uid_t uid; 575 gid_t gid; 576 577 vap = ap->a_vap; 578 if ((vap->va_type != VNON) || 579 (vap->va_nlink != VNOVAL) || 580 (vap->va_fsid != VNOVAL) || 581 (vap->va_fileid != VNOVAL) || 582 (vap->va_blocksize != VNOVAL) || 583 (vap->va_flags != VNOVAL && vap->va_flags != 0) || 584 (vap->va_rdev != VNOVAL) || 585 ((int)vap->va_bytes != VNOVAL) || 586 (vap->va_gen != VNOVAL)) { 587 return (EINVAL); 588 } 589 590 de = ap->a_vp->v_data; 591 if (ap->a_vp->v_type == VDIR) 592 de = de->de_dir; 593 594 error = c = 0; 595 if (vap->va_uid == (uid_t)VNOVAL) 596 uid = de->de_uid; 597 else 598 uid = vap->va_uid; 599 if (vap->va_gid == (gid_t)VNOVAL) 600 gid = de->de_gid; 601 else 602 gid = vap->va_gid; 603 if (uid != de->de_uid || gid != de->de_gid) { 604 if (((ap->a_cred->cr_uid != de->de_uid) || uid != de->de_uid || 605 (gid != de->de_gid && !groupmember(gid, ap->a_cred))) && 606 (error = suser(ap->a_p)) != 0) 607 return (error); 608 de->de_uid = uid; 609 de->de_gid = gid; 610 c = 1; 611 } 612 if (vap->va_mode != (mode_t)VNOVAL) { 613 if ((ap->a_cred->cr_uid != de->de_uid) && 614 (error = suser(ap->a_p))) 615 return (error); 616 de->de_mode = vap->va_mode; 617 c = 1; 618 } 619 if (vap->va_atime.tv_sec != VNOVAL) { 620 if ((ap->a_cred->cr_uid != de->de_uid) && 621 (error = suser(ap->a_p))) 622 return (error); 623 de->de_atime = vap->va_atime; 624 c = 1; 625 } 626 if (vap->va_mtime.tv_sec != VNOVAL) { 627 if ((ap->a_cred->cr_uid != de->de_uid) && 628 (error = suser(ap->a_p))) 629 return (error); 630 de->de_mtime = vap->va_mtime; 631 c = 1; 632 } 633 634 if (c) 635 getnanotime(&de->de_ctime); 636 return (0); 637} 638 639static int 640devfs_symlink(ap) 641 struct vop_symlink_args /* { 642 struct vnode *a_dvp; 643 struct vnode **a_vpp; 644 struct componentname *a_cnp; 645 struct vattr *a_vap; 646 char *a_target; 647 } */ *ap; 648{ 649 int i, error; 650 struct devfs_dirent *dd; 651 struct devfs_dirent *de; 652 struct devfs_mount *dmp; 653 654 error = suser(ap->a_cnp->cn_proc); 655 if (error) 656 return(error); 657 dmp = VFSTODEVFS(ap->a_dvp->v_mount); 658 dd = ap->a_dvp->v_data; 659 de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen); 660 de->de_uid = 0; 661 de->de_gid = 0; 662 de->de_mode = 0755; 663 de->de_inode = dmp->dm_inode++; 664 de->de_dirent->d_type = DT_LNK; 665 i = strlen(ap->a_target) + 1; 666 MALLOC(de->de_symlink, char *, i, M_DEVFS, M_WAITOK); 667 bcopy(ap->a_target, de->de_symlink, i); 668 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curproc); 669 TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); 670 devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, 0); 671 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc); 672 return (0); 673} 674 675static vop_t **devfs_vnodeop_p; 676static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = { 677 { &vop_default_desc, (vop_t *) vop_defaultop }, 678 { &vop_access_desc, (vop_t *) devfs_access }, 679 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 680 { &vop_lookup_desc, (vop_t *) devfs_lookup }, 681 { &vop_pathconf_desc, (vop_t *) vop_stdpathconf }, 682 { &vop_print_desc, (vop_t *) devfs_print }, 683 { &vop_read_desc, (vop_t *) devfs_read }, 684 { &vop_readdir_desc, (vop_t *) devfs_readdir }, 685 { &vop_readlink_desc, (vop_t *) devfs_readlink }, 686 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 687 { &vop_remove_desc, (vop_t *) devfs_remove }, 688 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 689 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 690 { &vop_symlink_desc, (vop_t *) devfs_symlink }, 691 { NULL, NULL } 692}; 693static struct vnodeopv_desc devfs_vnodeop_opv_desc = 694 { &devfs_vnodeop_p, devfs_vnodeop_entries }; 695 696VNODEOP_SET(devfs_vnodeop_opv_desc); 697 698static vop_t **devfs_specop_p; 699static struct vnodeopv_entry_desc devfs_specop_entries[] = { 700 { &vop_default_desc, (vop_t *) spec_vnoperate }, 701 { &vop_access_desc, (vop_t *) devfs_access }, 702 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 703 { &vop_print_desc, (vop_t *) devfs_print }, 704 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 705 { &vop_remove_desc, (vop_t *) devfs_remove }, 706 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 707 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 708 { NULL, NULL } 709}; 710static struct vnodeopv_desc devfs_specop_opv_desc = 711 { &devfs_specop_p, devfs_specop_entries }; 712 713VNODEOP_SET(devfs_specop_opv_desc);
| 198 return (error); 199} 200 201static int 202devfs_lookupx(ap) 203 struct vop_lookup_args /* { 204 struct vnode * a_dvp; 205 struct vnode ** a_vpp; 206 struct componentname * a_cnp; 207 } */ *ap; 208{ 209 struct componentname *cnp; 210 struct vnode *dvp, **vpp; 211 struct proc *p; 212 struct devfs_dirent *de, *dd; 213 struct devfs_mount *dmp; 214 dev_t cdev; 215 int error, cloned, i, flags, nameiop; 216 char specname[SPECNAMELEN + 1], *pname; 217 218 cnp = ap->a_cnp; 219 vpp = ap->a_vpp; 220 dvp = ap->a_dvp; 221 pname = cnp->cn_nameptr; 222 p = cnp->cn_proc; 223 flags = cnp->cn_flags; 224 nameiop = cnp->cn_nameiop; 225 dmp = VFSTODEVFS(dvp->v_mount); 226 cloned = 0; 227 dd = dvp->v_data; 228 229 *vpp = NULLVP; 230 231 if (nameiop == RENAME) 232 return (EOPNOTSUPP); 233 234 if (dvp->v_type != VDIR) 235 return (ENOTDIR); 236 237 if ((flags & ISDOTDOT) && (dvp->v_flag & VROOT)) 238 return (EIO); 239 240 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_proc); 241 if (error) 242 return (error); 243 244 if (cnp->cn_namelen == 1 && *pname == '.') { 245 if (nameiop != LOOKUP) 246 return (EINVAL); 247 *vpp = dvp; 248 VREF(dvp); 249 return (0); 250 } 251 252 if (flags & ISDOTDOT) { 253 if (nameiop != LOOKUP) 254 return (EINVAL); 255 VOP_UNLOCK(dvp, 0, p); 256 de = TAILQ_FIRST(&dd->de_dlist); /* "." */ 257 de = TAILQ_NEXT(de, de_list); /* ".." */ 258 de = de->de_dir; 259 error = devfs_allocv(de, dvp->v_mount, vpp, p); 260 if (error) { 261 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); 262 return (error); 263 } 264 if ((flags & LOCKPARENT) && (flags & ISLASTCN)) 265 error = vn_lock(dvp, LK_EXCLUSIVE, p); 266 if (error) 267 vput(*vpp); 268 return (error); 269 } 270 271 devfs_populate(dmp); 272 dd = dvp->v_data; 273 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 274 if (cnp->cn_namelen != de->de_dirent->d_namlen) 275 continue; 276 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 277 de->de_dirent->d_namlen) != 0) 278 continue; 279 goto found; 280 } 281 282 /* 283 * OK, we didn't have an entry for the name we were asked for 284 * so we try to see if anybody can create it on demand. 285 * We need to construct the full "devname" for this device 286 * relative to "basedir" or the clone functions would not 287 * be able to tell "/dev/foo" from "/dev/bar/foo" 288 */ 289 i = SPECNAMELEN; 290 specname[i] = '\0'; 291 i -= cnp->cn_namelen; 292 if (i < 0) 293 goto notfound; 294 bcopy(cnp->cn_nameptr, specname + i, cnp->cn_namelen); 295 de = dd; 296 while (de != dmp->dm_basedir) { 297 i--; 298 if (i < 0) 299 goto notfound; 300 specname[i] = '/'; 301 i -= de->de_dirent->d_namlen; 302 if (i < 0) 303 goto notfound; 304 bcopy(de->de_dirent->d_name, specname + i, 305 de->de_dirent->d_namlen); 306 de = TAILQ_FIRST(&de->de_dlist); /* "." */ 307 de = TAILQ_NEXT(de, de_list); /* ".." */ 308 de = de->de_dir; 309 } 310 311#if 0 312 printf("Finished specname: %d \"%s\"\n", i, specname + i); 313#endif 314 cdev = NODEV; 315 EVENTHANDLER_INVOKE(dev_clone, specname + i, 316 strlen(specname + i), &cdev); 317#if 0 318 printf("cloned %s -> %p %s\n", specname + i, cdev, 319 cdev == NODEV ? "NODEV" : cdev->si_name); 320#endif 321 if (cdev == NODEV) 322 goto notfound; 323 324 devfs_populate(dmp); 325 dd = dvp->v_data; 326 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 327 if (cnp->cn_namelen != de->de_dirent->d_namlen) 328 continue; 329 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 330 de->de_dirent->d_namlen) != 0) 331 continue; 332 goto found; 333 } 334 335notfound: 336 337 if ((nameiop == CREATE || nameiop == RENAME) && 338 (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) { 339 cnp->cn_flags |= SAVENAME; 340 if (!(flags & LOCKPARENT)) 341 VOP_UNLOCK(dvp, 0, p); 342 return (EJUSTRETURN); 343 } 344 return (ENOENT); 345 346 347found: 348 349 if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) { 350 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, p); 351 if (error) 352 return (error); 353 if (*vpp == dvp) { 354 VREF(dvp); 355 *vpp = dvp; 356 return (0); 357 } 358 error = devfs_allocv(de, dvp->v_mount, vpp, p); 359 if (error) 360 return (error); 361 if (!(flags & LOCKPARENT)) 362 VOP_UNLOCK(dvp, 0, p); 363 return (0); 364 } 365 error = devfs_allocv(de, dvp->v_mount, vpp, p); 366 if (error) 367 return (error); 368 if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) 369 VOP_UNLOCK(dvp, 0, p); 370 return (0); 371} 372 373static int 374devfs_lookup(struct vop_lookup_args *ap) 375{ 376 int j; 377 struct devfs_mount *dmp; 378 379 dmp = VFSTODEVFS(ap->a_dvp->v_mount); 380 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curproc); 381 j = devfs_lookupx(ap); 382 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc); 383 return (j); 384} 385 386/* ARGSUSED */ 387static int 388devfs_print(ap) 389 struct vop_print_args /* { 390 struct vnode *a_vp; 391 } */ *ap; 392{ 393 394 printf("tag VT_DEVFS, devfs vnode\n"); 395 return (0); 396} 397 398static int 399devfs_read(ap) 400 struct vop_read_args /* { 401 struct vnode *a_vp; 402 struct uio *a_uio; 403 int a_ioflag; 404 struct ucred *a_cred; 405 } */ *ap; 406{ 407 408 if (ap->a_vp->v_type != VDIR) 409 return (EINVAL); 410 return (VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred, NULL, NULL, NULL)); 411} 412 413static int 414devfs_readdir(ap) 415 struct vop_readdir_args /* { 416 struct vnode *a_vp; 417 struct uio *a_uio; 418 struct ucred *a_cred; 419 int *a_eofflag; 420 int *a_ncookies; 421 u_long **a_cookies; 422 } */ *ap; 423{ 424 int error; 425 struct uio *uio; 426 struct dirent *dp; 427 struct devfs_dirent *dd; 428 struct devfs_dirent *de; 429 struct devfs_mount *dmp; 430 off_t off; 431 432 if (ap->a_vp->v_type != VDIR) 433 return (ENOTDIR); 434 435 if (ap->a_ncookies) 436 return (EOPNOTSUPP); 437 438 uio = ap->a_uio; 439 if (uio->uio_offset < 0) 440 return (EINVAL); 441 442 dmp = VFSTODEVFS(ap->a_vp->v_mount); 443 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curproc); 444 devfs_populate(dmp); 445 error = 0; 446 de = ap->a_vp->v_data; 447 dd = TAILQ_FIRST(&de->de_dlist); 448 off = 0; 449 while (dd != NULL) { 450 if (dd->de_dirent->d_type == DT_DIR) 451 de = dd->de_dir; 452 else 453 de = dd; 454 dp = dd->de_dirent; 455 if (dp->d_reclen > uio->uio_resid) 456 break; 457 dp->d_fileno = de->de_inode; 458 if (off >= uio->uio_offset) { 459 error = uiomove((caddr_t)dp, dp->d_reclen, uio); 460 if (error) 461 break; 462 } 463 off += dp->d_reclen; 464 dd = TAILQ_NEXT(dd, de_list); 465 } 466 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc); 467 uio->uio_offset = off; 468 return (error); 469} 470 471static int 472devfs_readlink(ap) 473 struct vop_readlink_args /* { 474 struct vnode *a_vp; 475 struct uio *a_uio; 476 struct ucred *a_cead; 477 } */ *ap; 478{ 479 int error; 480 struct devfs_dirent *de; 481 482 de = ap->a_vp->v_data; 483 error = uiomove(de->de_symlink, strlen(de->de_symlink) + 1, ap->a_uio); 484 return (error); 485} 486 487static int 488devfs_reclaim(ap) 489 struct vop_reclaim_args /* { 490 struct vnode *a_vp; 491 } */ *ap; 492{ 493 struct vnode *vp = ap->a_vp; 494 struct devfs_dirent *de; 495 int i; 496 497 de = vp->v_data; 498 if (de != NULL) 499 de->de_vnode = NULL; 500 if (de != NULL && de->de_flags & DE_ORPHAN) { 501 if (de->de_symlink) 502 FREE(de->de_symlink, M_DEVFS); 503 FREE(de, M_DEVFS); 504 } 505 vp->v_data = NULL; 506 if (vp->v_rdev != NODEV && vp->v_rdev != NULL) { 507 i = vcount(vp); 508 if ((vp->v_rdev->si_flags & SI_CHEAPCLONE) && i == 0) 509 destroy_dev(vp->v_rdev); 510 } 511 return (0); 512} 513 514static int 515devfs_remove(ap) 516 struct vop_remove_args /* { 517 struct vnode *a_dvp; 518 struct vnode *a_vp; 519 struct componentname *a_cnp; 520 } */ *ap; 521{ 522 struct vnode *vp = ap->a_vp; 523 struct devfs_dirent *dd; 524 struct devfs_dirent *de, **dep; 525 struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount); 526 527 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curproc); 528 dd = ap->a_dvp->v_data; 529 de = vp->v_data; 530 TAILQ_REMOVE(&dd->de_dlist, de, de_list); 531 dep = devfs_itode(dmp, de->de_inode); 532 if (dep != NULL) 533 *dep = DE_DELETED; 534 de->de_flags |= DE_ORPHAN; 535 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc); 536 return (0); 537} 538 539/* 540 * Revoke is called on a tty when a terminal session ends. The vnode 541 * is orphaned by setting v_op to deadfs so we need to let go of it 542 * as well so that we create a new one next time around. 543 */ 544static int 545devfs_revoke(ap) 546 struct vop_revoke_args /* { 547 struct vnode *a_vp; 548 int a_flags; 549 } */ *ap; 550{ 551 struct vnode *vp = ap->a_vp; 552 struct devfs_dirent *de; 553 554 de = vp->v_data; 555 de->de_vnode = NULL; 556 vop_revoke(ap); 557 return (0); 558} 559 560static int 561devfs_setattr(ap) 562 struct vop_setattr_args /* { 563 struct vnode *a_vp; 564 struct vattr *a_vap; 565 struct ucred *a_cred; 566 struct proc *a_p; 567 } */ *ap; 568{ 569 struct devfs_dirent *de; 570 struct vattr *vap; 571 int c, error; 572 uid_t uid; 573 gid_t gid; 574 575 vap = ap->a_vap; 576 if ((vap->va_type != VNON) || 577 (vap->va_nlink != VNOVAL) || 578 (vap->va_fsid != VNOVAL) || 579 (vap->va_fileid != VNOVAL) || 580 (vap->va_blocksize != VNOVAL) || 581 (vap->va_flags != VNOVAL && vap->va_flags != 0) || 582 (vap->va_rdev != VNOVAL) || 583 ((int)vap->va_bytes != VNOVAL) || 584 (vap->va_gen != VNOVAL)) { 585 return (EINVAL); 586 } 587 588 de = ap->a_vp->v_data; 589 if (ap->a_vp->v_type == VDIR) 590 de = de->de_dir; 591 592 error = c = 0; 593 if (vap->va_uid == (uid_t)VNOVAL) 594 uid = de->de_uid; 595 else 596 uid = vap->va_uid; 597 if (vap->va_gid == (gid_t)VNOVAL) 598 gid = de->de_gid; 599 else 600 gid = vap->va_gid; 601 if (uid != de->de_uid || gid != de->de_gid) { 602 if (((ap->a_cred->cr_uid != de->de_uid) || uid != de->de_uid || 603 (gid != de->de_gid && !groupmember(gid, ap->a_cred))) && 604 (error = suser(ap->a_p)) != 0) 605 return (error); 606 de->de_uid = uid; 607 de->de_gid = gid; 608 c = 1; 609 } 610 if (vap->va_mode != (mode_t)VNOVAL) { 611 if ((ap->a_cred->cr_uid != de->de_uid) && 612 (error = suser(ap->a_p))) 613 return (error); 614 de->de_mode = vap->va_mode; 615 c = 1; 616 } 617 if (vap->va_atime.tv_sec != VNOVAL) { 618 if ((ap->a_cred->cr_uid != de->de_uid) && 619 (error = suser(ap->a_p))) 620 return (error); 621 de->de_atime = vap->va_atime; 622 c = 1; 623 } 624 if (vap->va_mtime.tv_sec != VNOVAL) { 625 if ((ap->a_cred->cr_uid != de->de_uid) && 626 (error = suser(ap->a_p))) 627 return (error); 628 de->de_mtime = vap->va_mtime; 629 c = 1; 630 } 631 632 if (c) 633 getnanotime(&de->de_ctime); 634 return (0); 635} 636 637static int 638devfs_symlink(ap) 639 struct vop_symlink_args /* { 640 struct vnode *a_dvp; 641 struct vnode **a_vpp; 642 struct componentname *a_cnp; 643 struct vattr *a_vap; 644 char *a_target; 645 } */ *ap; 646{ 647 int i, error; 648 struct devfs_dirent *dd; 649 struct devfs_dirent *de; 650 struct devfs_mount *dmp; 651 652 error = suser(ap->a_cnp->cn_proc); 653 if (error) 654 return(error); 655 dmp = VFSTODEVFS(ap->a_dvp->v_mount); 656 dd = ap->a_dvp->v_data; 657 de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen); 658 de->de_uid = 0; 659 de->de_gid = 0; 660 de->de_mode = 0755; 661 de->de_inode = dmp->dm_inode++; 662 de->de_dirent->d_type = DT_LNK; 663 i = strlen(ap->a_target) + 1; 664 MALLOC(de->de_symlink, char *, i, M_DEVFS, M_WAITOK); 665 bcopy(ap->a_target, de->de_symlink, i); 666 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curproc); 667 TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); 668 devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, 0); 669 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc); 670 return (0); 671} 672 673static vop_t **devfs_vnodeop_p; 674static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = { 675 { &vop_default_desc, (vop_t *) vop_defaultop }, 676 { &vop_access_desc, (vop_t *) devfs_access }, 677 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 678 { &vop_lookup_desc, (vop_t *) devfs_lookup }, 679 { &vop_pathconf_desc, (vop_t *) vop_stdpathconf }, 680 { &vop_print_desc, (vop_t *) devfs_print }, 681 { &vop_read_desc, (vop_t *) devfs_read }, 682 { &vop_readdir_desc, (vop_t *) devfs_readdir }, 683 { &vop_readlink_desc, (vop_t *) devfs_readlink }, 684 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 685 { &vop_remove_desc, (vop_t *) devfs_remove }, 686 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 687 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 688 { &vop_symlink_desc, (vop_t *) devfs_symlink }, 689 { NULL, NULL } 690}; 691static struct vnodeopv_desc devfs_vnodeop_opv_desc = 692 { &devfs_vnodeop_p, devfs_vnodeop_entries }; 693 694VNODEOP_SET(devfs_vnodeop_opv_desc); 695 696static vop_t **devfs_specop_p; 697static struct vnodeopv_entry_desc devfs_specop_entries[] = { 698 { &vop_default_desc, (vop_t *) spec_vnoperate }, 699 { &vop_access_desc, (vop_t *) devfs_access }, 700 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 701 { &vop_print_desc, (vop_t *) devfs_print }, 702 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 703 { &vop_remove_desc, (vop_t *) devfs_remove }, 704 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 705 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 706 { NULL, NULL } 707}; 708static struct vnodeopv_desc devfs_specop_opv_desc = 709 { &devfs_specop_p, devfs_specop_entries }; 710 711VNODEOP_SET(devfs_specop_opv_desc);
|