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.1 (Berkeley) 07/18/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 for (i = 0; i < nkern_targets; i++) { 208 struct kern_target *kt = &kern_targets[i]; 209 if (cnp->cn_namelen == strlen(kt->kt_name) && 210 bcmp(kt->kt_name, pname, cnp->cn_namelen) == 0) { 211 error = 0; 212 break; 213 } 214 } 215 216 #ifdef KERNFS_DIAGNOSTIC 217 printf("kernfs_lookup: i = %d, error = %d\n", i, error); 218 #endif 219 220 if (error) 221 goto bad; 222 223 #ifdef KERNFS_DIAGNOSTIC 224 printf("kernfs_lookup: allocate new vnode\n"); 225 #endif 226 error = getnewvnode(VT_UFS, dvp->v_mount, kernfs_vnodeop_p, &fvp); 227 if (error) 228 goto bad; 229 MALLOC(fvp->v_data, void *, sizeof(struct kernfs_node), M_TEMP, M_WAITOK); 230 VTOKERN(fvp)->kf_kt = &kern_targets[i]; 231 fvp->v_type = VTOKERN(fvp)->kf_kt->kt_vtype; 232 *vpp = fvp; 233 #ifdef KERNFS_DIAGNOSTIC 234 printf("kernfs_lookup: newvp = %x\n", fvp); 235 #endif 236 return (0); 237 238 bad:; 239 *vpp = NULL; 240 #ifdef KERNFS_DIAGNOSTIC 241 printf("kernfs_lookup: error = %d\n", error); 242 #endif 243 return (error); 244 } 245 246 kernfs_open(ap) 247 struct vop_open_args /* { 248 struct vnode *a_vp; 249 int a_mode; 250 struct ucred *a_cred; 251 struct proc *a_p; 252 } */ *ap; 253 { 254 struct vnode *vp = ap->a_vp; 255 256 /* 257 * Can always open the root (modulo perms) 258 */ 259 if (vp->v_flag & VROOT) 260 return (0); 261 262 #ifdef KERNFS_DIAGNOSTIC 263 printf("kernfs_open, mode = %x, file = %s\n", 264 ap->a_mode, VTOKERN(vp)->kf_kt->kt_name); 265 #endif 266 267 if ((ap->a_mode & FWRITE) && VTOKERN(vp)->kf_kt->kt_rw != KTM_RW) 268 return (EBADF); 269 270 return (0); 271 } 272 273 static int 274 kernfs_access(ap) 275 struct vop_access_args /* { 276 struct vnode *a_vp; 277 int a_mode; 278 struct ucred *a_cred; 279 struct proc *a_p; 280 } */ *ap; 281 { 282 struct vnode *vp = ap->a_vp; 283 struct ucred *cred = ap->a_cred; 284 struct kern_target *kt = VTOKERN(vp)->kf_kt; 285 mode_t mode = ap->a_mode; 286 287 if (mode & VEXEC) { 288 if (vp->v_flag & VROOT) 289 return (0); 290 return (EACCES); 291 } 292 293 if (cred->cr_uid == 0) { 294 if ((mode & VWRITE) && (kt->kt_rw != KTM_RW)) 295 return (EROFS); 296 return (0); 297 } 298 299 if (mode & VWRITE) 300 return (EACCES); 301 302 return (0); 303 } 304 305 306 kernfs_getattr(ap) 307 struct vop_getattr_args /* { 308 struct vnode *a_vp; 309 struct vattr *a_vap; 310 struct ucred *a_cred; 311 struct proc *a_p; 312 } */ *ap; 313 { 314 struct vnode *vp = ap->a_vp; 315 struct vattr *vap = ap->a_vap; 316 int error = 0; 317 char strbuf[KSTRING]; 318 struct kern_target *kt = VTOKERN(vp)->kf_kt; 319 320 bzero((caddr_t) vap, sizeof(*vap)); 321 vattr_null(vap); 322 vap->va_uid = 0; 323 vap->va_gid = 0; 324 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 325 /* vap->va_qsize = 0; */ 326 vap->va_blocksize = DEV_BSIZE; 327 microtime(&vap->va_atime); 328 vap->va_mtime = vap->va_atime; 329 vap->va_ctime = vap->va_ctime; 330 vap->va_gen = 0; 331 vap->va_flags = 0; 332 vap->va_rdev = 0; 333 /* vap->va_qbytes = 0; */ 334 vap->va_bytes = 0; 335 336 if (vp->v_flag & VROOT) { 337 #ifdef KERNFS_DIAGNOSTIC 338 printf("kernfs_getattr: stat rootdir\n"); 339 #endif 340 vap->va_type = VDIR; 341 vap->va_mode = KTM_DIR_MODE; 342 vap->va_nlink = 2; 343 vap->va_fileid = 2; 344 vap->va_size = DEV_BSIZE; 345 } else { 346 int nbytes; 347 #ifdef KERNFS_DIAGNOSTIC 348 printf("kernfs_getattr: stat target %s\n", kt->kt_name); 349 #endif 350 vap->va_type = kt->kt_vtype; 351 vap->va_mode = (kt->kt_rw ? KTM_RW_MODE : KTM_RO_MODE); 352 vap->va_nlink = 1; 353 vap->va_fileid = 3 + (kt - kern_targets) / sizeof(*kt); 354 error = kernfs_xread(kt, strbuf, sizeof(strbuf), &nbytes); 355 vap->va_size = nbytes; 356 } 357 358 vp->v_type = vap->va_type; 359 #ifdef KERNFS_DIAGNOSTIC 360 printf("kernfs_getattr: return error %d\n", error); 361 #endif 362 return (error); 363 } 364 365 kernfs_setattr(ap) 366 struct vop_setattr_args /* { 367 struct vnode *a_vp; 368 struct vattr *a_vap; 369 struct ucred *a_cred; 370 struct proc *a_p; 371 } */ *ap; 372 { 373 374 /* 375 * Silently ignore attribute changes. 376 * This allows for open with truncate to have no 377 * effect until some data is written. I want to 378 * do it this way because all writes are atomic. 379 */ 380 return (0); 381 } 382 383 static int 384 kernfs_read(ap) 385 struct vop_read_args /* { 386 struct vnode *a_vp; 387 struct uio *a_uio; 388 int a_ioflag; 389 struct ucred *a_cred; 390 } */ *ap; 391 { 392 struct vnode *vp = ap->a_vp; 393 struct uio *uio = ap->a_uio; 394 struct kern_target *kt = VTOKERN(vp)->kf_kt; 395 char strbuf[KSTRING]; 396 int off = uio->uio_offset; 397 int len = 0; 398 char *cp = strbuf; 399 int error; 400 #ifdef KERNFS_DIAGNOSTIC 401 printf("kern_read %s\n", kt->kt_name); 402 #endif 403 404 error = kernfs_xread(kt, strbuf, sizeof(strbuf), &len); 405 if (error) 406 return (error); 407 cp = strbuf + off; 408 len -= off; 409 return (uiomove(cp, len, uio)); 410 } 411 412 static int 413 kernfs_write(ap) 414 struct vop_write_args /* { 415 struct vnode *a_vp; 416 struct uio *a_uio; 417 int a_ioflag; 418 struct ucred *a_cred; 419 } */ *ap; 420 { 421 struct vnode *vp = ap->a_vp; 422 struct uio *uio = ap->a_uio; 423 struct kern_target *kt = VTOKERN(vp)->kf_kt; 424 char strbuf[KSTRING]; 425 int len = uio->uio_resid; 426 char *cp = strbuf; 427 int xlen; 428 int error; 429 430 if (uio->uio_offset != 0) 431 return (EINVAL); 432 433 xlen = min(uio->uio_resid, KSTRING-1); 434 error = uiomove(strbuf, xlen, uio); 435 if (error) 436 return (error); 437 438 if (uio->uio_resid != 0) 439 return (EIO); 440 441 strbuf[xlen] = '\0'; 442 return (kernfs_xwrite(kt, strbuf, xlen)); 443 } 444 445 446 kernfs_readdir(ap) 447 struct vop_readdir_args /* { 448 struct vnode *a_vp; 449 struct uio *a_uio; 450 struct ucred *a_cred; 451 } */ *ap; 452 { 453 struct uio *uio = ap->a_uio; 454 int i; 455 int error; 456 457 i = uio->uio_offset / UIO_MX; 458 error = 0; 459 while (uio->uio_resid > 0 && i < nkern_targets) { 460 struct dirent d; 461 struct dirent *dp = &d; 462 struct kern_target *kt = &kern_targets[i]; 463 #ifdef KERNFS_DIAGNOSTIC 464 printf("kernfs_readdir: i = %d\n", i); 465 #endif 466 467 bzero((caddr_t) dp, UIO_MX); 468 469 dp->d_namlen = strlen(kt->kt_name); 470 bcopy(kt->kt_name, dp->d_name, dp->d_namlen+1); 471 472 #ifdef KERNFS_DIAGNOSTIC 473 printf("kernfs_readdir: name = %s, len = %d\n", 474 dp->d_name, dp->d_namlen); 475 #endif 476 /* 477 * Fill in the remaining fields 478 */ 479 dp->d_reclen = UIO_MX; 480 dp->d_fileno = i + 3; 481 dp->d_type = DT_UNKNOWN; /* XXX */ 482 /* 483 * And ship to userland 484 */ 485 error = uiomove((caddr_t) dp, UIO_MX, uio); 486 if (error) 487 break; 488 i++; 489 } 490 491 uio->uio_offset = i * UIO_MX; 492 493 return (error); 494 } 495 496 kernfs_inactive(ap) 497 struct vop_inactive_args /* { 498 struct vnode *a_vp; 499 } */ *ap; 500 { 501 struct vnode *vp = ap->a_vp; 502 503 /* 504 * Clear out the v_type field to avoid 505 * nasty things happening in vgone(). 506 */ 507 vp->v_type = VNON; 508 #ifdef KERNFS_DIAGNOSTIC 509 printf("kernfs_inactive(%x)\n", vp); 510 #endif 511 return (0); 512 } 513 514 kernfs_reclaim(ap) 515 struct vop_reclaim_args /* { 516 struct vnode *a_vp; 517 } */ *ap; 518 { 519 struct vnode *vp = ap->a_vp; 520 printf("kernfs_reclaim(%x)\n", vp); 521 if (vp->v_data) { 522 FREE(vp->v_data, M_TEMP); 523 vp->v_data = 0; 524 } 525 return (0); 526 } 527 528 /* 529 * Print out the contents of a /dev/fd vnode. 530 */ 531 /* ARGSUSED */ 532 kernfs_print(ap) 533 struct vop_print_args /* { 534 struct vnode *a_vp; 535 } */ *ap; 536 { 537 538 printf("tag VT_NON, kernfs vnode\n"); 539 return (0); 540 } 541 542 /*void*/ 543 kernfs_vfree(ap) 544 struct vop_vfree_args /* { 545 struct vnode *a_pvp; 546 ino_t a_ino; 547 int a_mode; 548 } */ *ap; 549 { 550 551 return (0); 552 } 553 554 /* 555 * /dev/fd vnode unsupported operation 556 */ 557 kernfs_enotsupp() 558 { 559 560 return (EOPNOTSUPP); 561 } 562 563 /* 564 * /dev/fd "should never get here" operation 565 */ 566 kernfs_badop() 567 { 568 569 panic("kernfs: bad op"); 570 /* NOTREACHED */ 571 } 572 573 /* 574 * /dev/fd vnode null operation 575 */ 576 kernfs_nullop() 577 { 578 579 return (0); 580 } 581 582 #define kernfs_create ((int (*) __P((struct vop_create_args *)))kernfs_enotsupp) 583 #define kernfs_mknod ((int (*) __P((struct vop_mknod_args *)))kernfs_enotsupp) 584 #define kernfs_close ((int (*) __P((struct vop_close_args *)))nullop) 585 #define kernfs_ioctl ((int (*) __P((struct vop_ioctl_args *)))kernfs_enotsupp) 586 #define kernfs_select ((int (*) __P((struct vop_select_args *)))kernfs_enotsupp) 587 #define kernfs_mmap ((int (*) __P((struct vop_mmap_args *)))kernfs_enotsupp) 588 #define kernfs_fsync ((int (*) __P((struct vop_fsync_args *)))nullop) 589 #define kernfs_seek ((int (*) __P((struct vop_seek_args *)))nullop) 590 #define kernfs_remove ((int (*) __P((struct vop_remove_args *)))kernfs_enotsupp) 591 #define kernfs_link ((int (*) __P((struct vop_link_args *)))kernfs_enotsupp) 592 #define kernfs_rename ((int (*) __P((struct vop_rename_args *)))kernfs_enotsupp) 593 #define kernfs_mkdir ((int (*) __P((struct vop_mkdir_args *)))kernfs_enotsupp) 594 #define kernfs_rmdir ((int (*) __P((struct vop_rmdir_args *)))kernfs_enotsupp) 595 #define kernfs_symlink ((int (*) __P((struct vop_symlink_args *)))kernfs_enotsupp) 596 #define kernfs_readlink \ 597 ((int (*) __P((struct vop_readlink_args *)))kernfs_enotsupp) 598 #define kernfs_abortop ((int (*) __P((struct vop_abortop_args *)))nullop) 599 #define kernfs_lock ((int (*) __P((struct vop_lock_args *)))nullop) 600 #define kernfs_unlock ((int (*) __P((struct vop_unlock_args *)))nullop) 601 #define kernfs_bmap ((int (*) __P((struct vop_bmap_args *)))kernfs_badop) 602 #define kernfs_strategy ((int (*) __P((struct vop_strategy_args *)))kernfs_badop) 603 #define kernfs_islocked ((int (*) __P((struct vop_islocked_args *)))nullop) 604 #define kernfs_advlock ((int (*) __P((struct vop_advlock_args *)))kernfs_enotsupp) 605 #define kernfs_blkatoff \ 606 ((int (*) __P((struct vop_blkatoff_args *)))kernfs_enotsupp) 607 #define kernfs_valloc ((int(*) __P(( \ 608 struct vnode *pvp, \ 609 int mode, \ 610 struct ucred *cred, \ 611 struct vnode **vpp))) kernfs_enotsupp) 612 #define kernfs_truncate \ 613 ((int (*) __P((struct vop_truncate_args *)))kernfs_enotsupp) 614 #define kernfs_update ((int (*) __P((struct vop_update_args *)))kernfs_enotsupp) 615 #define kernfs_bwrite ((int (*) __P((struct vop_bwrite_args *)))kernfs_enotsupp) 616 617 int (**kernfs_vnodeop_p)(); 618 struct vnodeopv_entry_desc kernfs_vnodeop_entries[] = { 619 { &vop_default_desc, vn_default_error }, 620 { &vop_lookup_desc, kernfs_lookup }, /* lookup */ 621 { &vop_create_desc, kernfs_create }, /* create */ 622 { &vop_mknod_desc, kernfs_mknod }, /* mknod */ 623 { &vop_open_desc, kernfs_open }, /* open */ 624 { &vop_close_desc, kernfs_close }, /* close */ 625 { &vop_access_desc, kernfs_access }, /* access */ 626 { &vop_getattr_desc, kernfs_getattr }, /* getattr */ 627 { &vop_setattr_desc, kernfs_setattr }, /* setattr */ 628 { &vop_read_desc, kernfs_read }, /* read */ 629 { &vop_write_desc, kernfs_write }, /* write */ 630 { &vop_ioctl_desc, kernfs_ioctl }, /* ioctl */ 631 { &vop_select_desc, kernfs_select }, /* select */ 632 { &vop_mmap_desc, kernfs_mmap }, /* mmap */ 633 { &vop_fsync_desc, kernfs_fsync }, /* fsync */ 634 { &vop_seek_desc, kernfs_seek }, /* seek */ 635 { &vop_remove_desc, kernfs_remove }, /* remove */ 636 { &vop_link_desc, kernfs_link }, /* link */ 637 { &vop_rename_desc, kernfs_rename }, /* rename */ 638 { &vop_mkdir_desc, kernfs_mkdir }, /* mkdir */ 639 { &vop_rmdir_desc, kernfs_rmdir }, /* rmdir */ 640 { &vop_symlink_desc, kernfs_symlink }, /* symlink */ 641 { &vop_readdir_desc, kernfs_readdir }, /* readdir */ 642 { &vop_readlink_desc, kernfs_readlink }, /* readlink */ 643 { &vop_abortop_desc, kernfs_abortop }, /* abortop */ 644 { &vop_inactive_desc, kernfs_inactive }, /* inactive */ 645 { &vop_reclaim_desc, kernfs_reclaim }, /* reclaim */ 646 { &vop_lock_desc, kernfs_lock }, /* lock */ 647 { &vop_unlock_desc, kernfs_unlock }, /* unlock */ 648 { &vop_bmap_desc, kernfs_bmap }, /* bmap */ 649 { &vop_strategy_desc, kernfs_strategy }, /* strategy */ 650 { &vop_print_desc, kernfs_print }, /* print */ 651 { &vop_islocked_desc, kernfs_islocked }, /* islocked */ 652 { &vop_advlock_desc, kernfs_advlock }, /* advlock */ 653 { &vop_blkatoff_desc, kernfs_blkatoff }, /* blkatoff */ 654 { &vop_valloc_desc, kernfs_valloc }, /* valloc */ 655 { &vop_vfree_desc, kernfs_vfree }, /* vfree */ 656 { &vop_truncate_desc, kernfs_truncate }, /* truncate */ 657 { &vop_update_desc, kernfs_update }, /* update */ 658 { &vop_bwrite_desc, kernfs_bwrite }, /* bwrite */ 659 { (struct vnodeop_desc*)NULL, (int(*)())NULL } 660 }; 661 struct vnodeopv_desc kernfs_vnodeop_opv_desc = 662 { &kernfs_vnodeop_p, kernfs_vnodeop_entries }; 663