1 /* 2 * Copyright (c) 1992 The Regents of the University of California 3 * Copyright (c) 1990, 1992 Jan-Simon Pendry 4 * All rights reserved. 5 * 6 * This code is derived from software donated to Berkeley by 7 * Jan-Simon Pendry. 8 * 9 * %sccs.include.redist.c% 10 * 11 * @(#)kernfs_vnops.c 7.3 (Berkeley) 07/19/92 12 */ 13 14 /* 15 * Kernel parameter filesystem (/kern) 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/kernel.h> 21 #include <sys/vmmeter.h> 22 #include <sys/types.h> 23 #include <sys/time.h> 24 #include <sys/proc.h> 25 #include <sys/vnode.h> 26 #include <sys/malloc.h> 27 #include <sys/file.h> 28 #include <sys/stat.h> 29 #include <sys/mount.h> 30 #include <sys/namei.h> 31 #include <sys/buf.h> 32 #include <sys/dirent.h> 33 #include <miscfs/kernfs/kernfs.h> 34 35 #define KSTRING 256 /* Largest I/O available via this filesystem */ 36 #define UIO_MX 32 37 38 struct kern_target { 39 char *kt_name; 40 void *kt_data; 41 #define KTT_NULL 1 42 #define KTT_TIME 5 43 #define KTT_INT 17 44 #define KTT_STRING 31 45 #define KTT_HOSTNAME 47 46 #define KTT_AVENRUN 53 47 int kt_tag; 48 #define KTM_RO 0 49 #define KTM_RO_MODE (S_IRUSR|S_IRGRP|S_IROTH) 50 #define KTM_RW 43 51 #define KTM_RW_MODE (S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH) 52 #define KTM_DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 53 int kt_rw; 54 int kt_vtype; 55 } kern_targets[] = { 56 /* NOTE: The name must be less than UIO_MX-16 chars in length */ 57 /* name data tag ro/rw */ 58 { ".", 0, KTT_NULL, KTM_RO, VDIR }, 59 { "copyright", copyright, KTT_STRING, KTM_RO, VREG }, 60 { "hostname", 0, KTT_HOSTNAME, KTM_RW, VREG }, 61 { "hz", &hz, KTT_INT, KTM_RO, VREG }, 62 { "loadavg", 0, KTT_AVENRUN, KTM_RO, VREG }, 63 { "pagesize", &cnt.v_page_size, KTT_INT, KTM_RO, VREG }, 64 { "physmem", &physmem, KTT_INT, KTM_RO, VREG }, 65 { "root", 0, KTT_NULL, KTM_RO, VDIR }, 66 { "rootdev", 0, KTT_NULL, KTM_RO, VBLK }, 67 { "time", 0, KTT_TIME, KTM_RO, VREG }, 68 { "version", version, KTT_STRING, KTM_RO, VREG }, 69 }; 70 71 static int nkern_targets = sizeof(kern_targets) / sizeof(kern_targets[0]); 72 73 static int 74 kernfs_xread(kt, buf, len, lenp) 75 struct kern_target *kt; 76 char *buf; 77 int len; 78 int *lenp; 79 { 80 int xlen; 81 82 switch (kt->kt_tag) { 83 case KTT_TIME: { 84 struct timeval tv; 85 microtime(&tv); 86 sprintf(buf, "%d %d\n", tv.tv_sec, tv.tv_usec); 87 break; 88 } 89 90 case KTT_INT: { 91 int *ip = kt->kt_data; 92 sprintf(buf, "%d\n", *ip); 93 break; 94 } 95 96 case KTT_STRING: { 97 char *cp = kt->kt_data; 98 int xlen = strlen(cp) + 1; 99 100 if (xlen >= len) 101 return (EINVAL); 102 103 bcopy(cp, buf, xlen); 104 break; 105 } 106 107 case KTT_HOSTNAME: { 108 char *cp = hostname; 109 int xlen = hostnamelen; 110 111 if (xlen >= len) 112 return (EINVAL); 113 114 sprintf(buf, "%s\n", cp); 115 break; 116 } 117 118 case KTT_AVENRUN: 119 sprintf(buf, "%ld %ld %ld %ld\n", 120 averunnable.ldavg[0], 121 averunnable.ldavg[1], 122 averunnable.ldavg[2], 123 averunnable.fscale); 124 break; 125 126 default: 127 return (EINVAL); 128 } 129 130 *lenp = strlen(buf); 131 return (0); 132 } 133 134 static int 135 kernfs_xwrite(kt, buf, len) 136 struct kern_target *kt; 137 char *buf; 138 int len; 139 { 140 switch (kt->kt_tag) { 141 case KTT_HOSTNAME: { 142 if (buf[len-1] == '\n') 143 --len; 144 bcopy(buf, hostname, len); 145 hostnamelen = len - 1; 146 return (0); 147 } 148 149 default: 150 return (EIO); 151 } 152 } 153 154 155 /* 156 * vp is the current namei directory 157 * ndp is the name to locate in that directory... 158 */ 159 kernfs_lookup(ap) 160 struct vop_lookup_args /* { 161 struct vnode * a_dvp; 162 struct vnode ** a_vpp; 163 struct componentname * a_cnp; 164 } */ *ap; 165 { 166 struct vnode **vpp = ap->a_vpp; 167 struct vnode *dvp = ap->a_dvp; 168 struct componentname *cnp = ap->a_cnp; 169 char *pname; 170 struct proc *p; 171 int error; 172 struct vnode *fvp; 173 int i; 174 175 #ifdef KERNFS_DIAGNOSTIC 176 printf("kernfs_lookup(%x)\n", ap); 177 printf("kernfs_lookup(dp = %x, vpp = %x, cnp = %x)\n", dvp, vpp, ap->a_cnp); 178 #endif 179 pname = cnp->cn_nameptr; 180 #ifdef KERNFS_DIAGNOSTIC 181 printf("kernfs_lookup(%s)\n", pname); 182 #endif 183 if (cnp->cn_namelen == 1 && *pname == '.') { 184 *vpp = dvp; 185 VREF(dvp); 186 /*VOP_LOCK(dvp);*/ 187 return (0); 188 } 189 190 if (cnp->cn_namelen == 4 && bcmp(pname, "root", 4) == 0) { 191 *vpp = rootdir; 192 VREF(rootdir); 193 VOP_LOCK(rootdir); 194 return (0); 195 } 196 197 /* 198 * /kern/rootdev is the root device 199 */ 200 if (cnp->cn_namelen == 7 && bcmp(pname, "rootdev", 7) == 0) { 201 *vpp = rootvp; 202 VREF(rootvp); 203 VOP_LOCK(rootvp); 204 return (0); 205 } 206 207 error = ENOENT; 208 209 for (i = 0; i < nkern_targets; i++) { 210 struct kern_target *kt = &kern_targets[i]; 211 if (cnp->cn_namelen == strlen(kt->kt_name) && 212 bcmp(kt->kt_name, pname, cnp->cn_namelen) == 0) { 213 error = 0; 214 break; 215 } 216 } 217 218 #ifdef KERNFS_DIAGNOSTIC 219 printf("kernfs_lookup: i = %d, error = %d\n", i, error); 220 #endif 221 222 if (error) 223 goto bad; 224 225 #ifdef KERNFS_DIAGNOSTIC 226 printf("kernfs_lookup: allocate new vnode\n"); 227 #endif 228 error = getnewvnode(VT_UFS, dvp->v_mount, kernfs_vnodeop_p, &fvp); 229 if (error) 230 goto bad; 231 MALLOC(fvp->v_data, void *, sizeof(struct kernfs_node), M_TEMP, M_WAITOK); 232 VTOKERN(fvp)->kf_kt = &kern_targets[i]; 233 fvp->v_type = VTOKERN(fvp)->kf_kt->kt_vtype; 234 *vpp = fvp; 235 #ifdef KERNFS_DIAGNOSTIC 236 printf("kernfs_lookup: newvp = %x\n", fvp); 237 #endif 238 return (0); 239 240 bad:; 241 *vpp = NULL; 242 #ifdef KERNFS_DIAGNOSTIC 243 printf("kernfs_lookup: error = %d\n", error); 244 #endif 245 return (error); 246 } 247 248 kernfs_open(ap) 249 struct vop_open_args /* { 250 struct vnode *a_vp; 251 int a_mode; 252 struct ucred *a_cred; 253 struct proc *a_p; 254 } */ *ap; 255 { 256 struct vnode *vp = ap->a_vp; 257 258 /* 259 * Can always open the root (modulo perms) 260 */ 261 if (vp->v_flag & VROOT) 262 return (0); 263 264 #ifdef KERNFS_DIAGNOSTIC 265 printf("kernfs_open, mode = %x, file = %s\n", 266 ap->a_mode, VTOKERN(vp)->kf_kt->kt_name); 267 #endif 268 269 if ((ap->a_mode & FWRITE) && VTOKERN(vp)->kf_kt->kt_rw != KTM_RW) 270 return (EBADF); 271 272 return (0); 273 } 274 275 static int 276 kernfs_access(ap) 277 struct vop_access_args /* { 278 struct vnode *a_vp; 279 int a_mode; 280 struct ucred *a_cred; 281 struct proc *a_p; 282 } */ *ap; 283 { 284 struct vnode *vp = ap->a_vp; 285 struct ucred *cred = ap->a_cred; 286 struct kern_target *kt = VTOKERN(vp)->kf_kt; 287 mode_t mode = ap->a_mode; 288 289 if (mode & VEXEC) { 290 if (vp->v_flag & VROOT) 291 return (0); 292 return (EACCES); 293 } 294 295 if (cred->cr_uid == 0) { 296 if ((mode & VWRITE) && (kt->kt_rw != KTM_RW)) 297 return (EROFS); 298 return (0); 299 } 300 301 if (mode & VWRITE) 302 return (EACCES); 303 304 return (0); 305 } 306 307 308 kernfs_getattr(ap) 309 struct vop_getattr_args /* { 310 struct vnode *a_vp; 311 struct vattr *a_vap; 312 struct ucred *a_cred; 313 struct proc *a_p; 314 } */ *ap; 315 { 316 struct vnode *vp = ap->a_vp; 317 struct vattr *vap = ap->a_vap; 318 int error = 0; 319 char strbuf[KSTRING]; 320 struct kern_target *kt = VTOKERN(vp)->kf_kt; 321 322 bzero((caddr_t) vap, sizeof(*vap)); 323 vattr_null(vap); 324 vap->va_uid = 0; 325 vap->va_gid = 0; 326 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 327 /* vap->va_qsize = 0; */ 328 vap->va_blocksize = DEV_BSIZE; 329 microtime(&vap->va_atime); 330 vap->va_mtime = vap->va_atime; 331 vap->va_ctime = vap->va_ctime; 332 vap->va_gen = 0; 333 vap->va_flags = 0; 334 vap->va_rdev = 0; 335 /* vap->va_qbytes = 0; */ 336 vap->va_bytes = 0; 337 338 if (vp->v_flag & VROOT) { 339 #ifdef KERNFS_DIAGNOSTIC 340 printf("kernfs_getattr: stat rootdir\n"); 341 #endif 342 vap->va_type = VDIR; 343 vap->va_mode = KTM_DIR_MODE; 344 vap->va_nlink = 2; 345 vap->va_fileid = 2; 346 vap->va_size = DEV_BSIZE; 347 } else { 348 int nbytes; 349 #ifdef KERNFS_DIAGNOSTIC 350 printf("kernfs_getattr: stat target %s\n", kt->kt_name); 351 #endif 352 vap->va_type = kt->kt_vtype; 353 vap->va_mode = (kt->kt_rw ? KTM_RW_MODE : KTM_RO_MODE); 354 vap->va_nlink = 1; 355 vap->va_fileid = 3 + (kt - kern_targets) / sizeof(*kt); 356 error = kernfs_xread(kt, strbuf, sizeof(strbuf), &nbytes); 357 vap->va_size = nbytes; 358 } 359 360 vp->v_type = vap->va_type; 361 #ifdef KERNFS_DIAGNOSTIC 362 printf("kernfs_getattr: return error %d\n", error); 363 #endif 364 return (error); 365 } 366 367 kernfs_setattr(ap) 368 struct vop_setattr_args /* { 369 struct vnode *a_vp; 370 struct vattr *a_vap; 371 struct ucred *a_cred; 372 struct proc *a_p; 373 } */ *ap; 374 { 375 376 /* 377 * Silently ignore attribute changes. 378 * This allows for open with truncate to have no 379 * effect until some data is written. I want to 380 * do it this way because all writes are atomic. 381 */ 382 return (0); 383 } 384 385 static int 386 kernfs_read(ap) 387 struct vop_read_args /* { 388 struct vnode *a_vp; 389 struct uio *a_uio; 390 int a_ioflag; 391 struct ucred *a_cred; 392 } */ *ap; 393 { 394 struct vnode *vp = ap->a_vp; 395 struct uio *uio = ap->a_uio; 396 struct kern_target *kt = VTOKERN(vp)->kf_kt; 397 char strbuf[KSTRING]; 398 int off = uio->uio_offset; 399 int len = 0; 400 char *cp = strbuf; 401 int error; 402 #ifdef KERNFS_DIAGNOSTIC 403 printf("kern_read %s\n", kt->kt_name); 404 #endif 405 406 error = kernfs_xread(kt, strbuf, sizeof(strbuf), &len); 407 if (error) 408 return (error); 409 cp = strbuf + off; 410 len -= off; 411 return (uiomove(cp, len, uio)); 412 } 413 414 static int 415 kernfs_write(ap) 416 struct vop_write_args /* { 417 struct vnode *a_vp; 418 struct uio *a_uio; 419 int a_ioflag; 420 struct ucred *a_cred; 421 } */ *ap; 422 { 423 struct vnode *vp = ap->a_vp; 424 struct uio *uio = ap->a_uio; 425 struct kern_target *kt = VTOKERN(vp)->kf_kt; 426 char strbuf[KSTRING]; 427 int len = uio->uio_resid; 428 char *cp = strbuf; 429 int xlen; 430 int error; 431 432 if (uio->uio_offset != 0) 433 return (EINVAL); 434 435 xlen = min(uio->uio_resid, KSTRING-1); 436 error = uiomove(strbuf, xlen, uio); 437 if (error) 438 return (error); 439 440 if (uio->uio_resid != 0) 441 return (EIO); 442 443 strbuf[xlen] = '\0'; 444 return (kernfs_xwrite(kt, strbuf, xlen)); 445 } 446 447 448 kernfs_readdir(ap) 449 struct vop_readdir_args /* { 450 struct vnode *a_vp; 451 struct uio *a_uio; 452 struct ucred *a_cred; 453 } */ *ap; 454 { 455 struct uio *uio = ap->a_uio; 456 int i; 457 int error; 458 459 i = uio->uio_offset / UIO_MX; 460 error = 0; 461 while (uio->uio_resid > 0 && i < nkern_targets) { 462 struct dirent d; 463 struct dirent *dp = &d; 464 struct kern_target *kt = &kern_targets[i]; 465 #ifdef KERNFS_DIAGNOSTIC 466 printf("kernfs_readdir: i = %d\n", i); 467 #endif 468 469 bzero((caddr_t) dp, UIO_MX); 470 471 dp->d_namlen = strlen(kt->kt_name); 472 bcopy(kt->kt_name, dp->d_name, dp->d_namlen+1); 473 474 #ifdef KERNFS_DIAGNOSTIC 475 printf("kernfs_readdir: name = %s, len = %d\n", 476 dp->d_name, dp->d_namlen); 477 #endif 478 /* 479 * Fill in the remaining fields 480 */ 481 dp->d_reclen = UIO_MX; 482 dp->d_fileno = i + 3; 483 dp->d_type = DT_UNKNOWN; /* XXX */ 484 /* 485 * And ship to userland 486 */ 487 error = uiomove((caddr_t) dp, UIO_MX, uio); 488 if (error) 489 break; 490 i++; 491 } 492 493 uio->uio_offset = i * UIO_MX; 494 495 return (error); 496 } 497 498 kernfs_inactive(ap) 499 struct vop_inactive_args /* { 500 struct vnode *a_vp; 501 } */ *ap; 502 { 503 struct vnode *vp = ap->a_vp; 504 505 /* 506 * Clear out the v_type field to avoid 507 * nasty things happening in vgone(). 508 */ 509 vp->v_type = VNON; 510 #ifdef KERNFS_DIAGNOSTIC 511 printf("kernfs_inactive(%x)\n", vp); 512 #endif 513 return (0); 514 } 515 516 kernfs_reclaim(ap) 517 struct vop_reclaim_args /* { 518 struct vnode *a_vp; 519 } */ *ap; 520 { 521 struct vnode *vp = ap->a_vp; 522 printf("kernfs_reclaim(%x)\n", vp); 523 if (vp->v_data) { 524 FREE(vp->v_data, M_TEMP); 525 vp->v_data = 0; 526 } 527 return (0); 528 } 529 530 /* 531 * Print out the contents of a /dev/fd vnode. 532 */ 533 /* ARGSUSED */ 534 kernfs_print(ap) 535 struct vop_print_args /* { 536 struct vnode *a_vp; 537 } */ *ap; 538 { 539 540 printf("tag VT_NON, kernfs vnode\n"); 541 return (0); 542 } 543 544 /*void*/ 545 kernfs_vfree(ap) 546 struct vop_vfree_args /* { 547 struct vnode *a_pvp; 548 ino_t a_ino; 549 int a_mode; 550 } */ *ap; 551 { 552 553 return (0); 554 } 555 556 /* 557 * /dev/fd vnode unsupported operation 558 */ 559 kernfs_enotsupp() 560 { 561 562 return (EOPNOTSUPP); 563 } 564 565 /* 566 * /dev/fd "should never get here" operation 567 */ 568 kernfs_badop() 569 { 570 571 panic("kernfs: bad op"); 572 /* NOTREACHED */ 573 } 574 575 /* 576 * kernfs vnode null operation 577 */ 578 kernfs_nullop() 579 { 580 581 return (0); 582 } 583 584 #define kernfs_create ((int (*) __P((struct vop_create_args *)))kernfs_enotsupp) 585 #define kernfs_mknod ((int (*) __P((struct vop_mknod_args *)))kernfs_enotsupp) 586 #define kernfs_close ((int (*) __P((struct vop_close_args *)))nullop) 587 #define kernfs_ioctl ((int (*) __P((struct vop_ioctl_args *)))kernfs_enotsupp) 588 #define kernfs_select ((int (*) __P((struct vop_select_args *)))kernfs_enotsupp) 589 #define kernfs_mmap ((int (*) __P((struct vop_mmap_args *)))kernfs_enotsupp) 590 #define kernfs_fsync ((int (*) __P((struct vop_fsync_args *)))nullop) 591 #define kernfs_seek ((int (*) __P((struct vop_seek_args *)))nullop) 592 #define kernfs_remove ((int (*) __P((struct vop_remove_args *)))kernfs_enotsupp) 593 #define kernfs_link ((int (*) __P((struct vop_link_args *)))kernfs_enotsupp) 594 #define kernfs_rename ((int (*) __P((struct vop_rename_args *)))kernfs_enotsupp) 595 #define kernfs_mkdir ((int (*) __P((struct vop_mkdir_args *)))kernfs_enotsupp) 596 #define kernfs_rmdir ((int (*) __P((struct vop_rmdir_args *)))kernfs_enotsupp) 597 #define kernfs_symlink ((int (*) __P((struct vop_symlink_args *)))kernfs_enotsupp) 598 #define kernfs_readlink \ 599 ((int (*) __P((struct vop_readlink_args *)))kernfs_enotsupp) 600 #define kernfs_abortop ((int (*) __P((struct vop_abortop_args *)))nullop) 601 #define kernfs_lock ((int (*) __P((struct vop_lock_args *)))nullop) 602 #define kernfs_unlock ((int (*) __P((struct vop_unlock_args *)))nullop) 603 #define kernfs_bmap ((int (*) __P((struct vop_bmap_args *)))kernfs_badop) 604 #define kernfs_strategy ((int (*) __P((struct vop_strategy_args *)))kernfs_badop) 605 #define kernfs_islocked ((int (*) __P((struct vop_islocked_args *)))nullop) 606 #define kernfs_advlock ((int (*) __P((struct vop_advlock_args *)))kernfs_enotsupp) 607 #define kernfs_blkatoff \ 608 ((int (*) __P((struct vop_blkatoff_args *)))kernfs_enotsupp) 609 #define kernfs_valloc ((int(*) __P(( \ 610 struct vnode *pvp, \ 611 int mode, \ 612 struct ucred *cred, \ 613 struct vnode **vpp))) kernfs_enotsupp) 614 #define kernfs_truncate \ 615 ((int (*) __P((struct vop_truncate_args *)))kernfs_enotsupp) 616 #define kernfs_update ((int (*) __P((struct vop_update_args *)))kernfs_enotsupp) 617 #define kernfs_bwrite ((int (*) __P((struct vop_bwrite_args *)))kernfs_enotsupp) 618 619 int (**kernfs_vnodeop_p)(); 620 struct vnodeopv_entry_desc kernfs_vnodeop_entries[] = { 621 { &vop_default_desc, vn_default_error }, 622 { &vop_lookup_desc, kernfs_lookup }, /* lookup */ 623 { &vop_create_desc, kernfs_create }, /* create */ 624 { &vop_mknod_desc, kernfs_mknod }, /* mknod */ 625 { &vop_open_desc, kernfs_open }, /* open */ 626 { &vop_close_desc, kernfs_close }, /* close */ 627 { &vop_access_desc, kernfs_access }, /* access */ 628 { &vop_getattr_desc, kernfs_getattr }, /* getattr */ 629 { &vop_setattr_desc, kernfs_setattr }, /* setattr */ 630 { &vop_read_desc, kernfs_read }, /* read */ 631 { &vop_write_desc, kernfs_write }, /* write */ 632 { &vop_ioctl_desc, kernfs_ioctl }, /* ioctl */ 633 { &vop_select_desc, kernfs_select }, /* select */ 634 { &vop_mmap_desc, kernfs_mmap }, /* mmap */ 635 { &vop_fsync_desc, kernfs_fsync }, /* fsync */ 636 { &vop_seek_desc, kernfs_seek }, /* seek */ 637 { &vop_remove_desc, kernfs_remove }, /* remove */ 638 { &vop_link_desc, kernfs_link }, /* link */ 639 { &vop_rename_desc, kernfs_rename }, /* rename */ 640 { &vop_mkdir_desc, kernfs_mkdir }, /* mkdir */ 641 { &vop_rmdir_desc, kernfs_rmdir }, /* rmdir */ 642 { &vop_symlink_desc, kernfs_symlink }, /* symlink */ 643 { &vop_readdir_desc, kernfs_readdir }, /* readdir */ 644 { &vop_readlink_desc, kernfs_readlink }, /* readlink */ 645 { &vop_abortop_desc, kernfs_abortop }, /* abortop */ 646 { &vop_inactive_desc, kernfs_inactive }, /* inactive */ 647 { &vop_reclaim_desc, kernfs_reclaim }, /* reclaim */ 648 { &vop_lock_desc, kernfs_lock }, /* lock */ 649 { &vop_unlock_desc, kernfs_unlock }, /* unlock */ 650 { &vop_bmap_desc, kernfs_bmap }, /* bmap */ 651 { &vop_strategy_desc, kernfs_strategy }, /* strategy */ 652 { &vop_print_desc, kernfs_print }, /* print */ 653 { &vop_islocked_desc, kernfs_islocked }, /* islocked */ 654 { &vop_advlock_desc, kernfs_advlock }, /* advlock */ 655 { &vop_blkatoff_desc, kernfs_blkatoff }, /* blkatoff */ 656 { &vop_valloc_desc, kernfs_valloc }, /* valloc */ 657 { &vop_vfree_desc, kernfs_vfree }, /* vfree */ 658 { &vop_truncate_desc, kernfs_truncate }, /* truncate */ 659 { &vop_update_desc, kernfs_update }, /* update */ 660 { &vop_bwrite_desc, kernfs_bwrite }, /* bwrite */ 661 { (struct vnodeop_desc*)NULL, (int(*)())NULL } 662 }; 663 struct vnodeopv_desc kernfs_vnodeop_opv_desc = 664 { &kernfs_vnodeop_p, kernfs_vnodeop_entries }; 665