1 /* 2 * Copyright (c) 1990, 1992 Jan-Simon Pendry 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Jan-Simon Pendry. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * $Id: kernfs_vnops.c,v 1.4 1993/03/27 00:37:11 cgd Exp $ 37 */ 38 39 /* 40 * Kernel parameter filesystem 41 */ 42 43 #include "param.h" 44 #include "systm.h" 45 #include "kernel.h" 46 #include "types.h" 47 #include "time.h" 48 #include "proc.h" 49 #include "file.h" 50 #include "vnode.h" 51 #include "stat.h" 52 #include "mount.h" 53 #include "namei.h" 54 #include "buf.h" 55 #include "miscfs/kernfs/kernfs.h" 56 57 #include "../ufs/dir.h" /* For readdir() XXX */ 58 59 #define KSTRING 256 /* Largest I/O available via this filesystem */ 60 #define UIO_MX 32 61 62 struct kern_target { 63 char *kt_name; 64 void *kt_data; 65 #define KTT_NULL 1 66 #define KTT_TIME 5 67 #define KTT_INT 17 68 #define KTT_STRING 31 69 #define KTT_HOSTNAME 47 70 #define KTT_AVENRUN 53 71 int kt_tag; 72 #define KTM_RO 0 73 #define KTM_RO_MODE (S_IRUSR|S_IRGRP|S_IROTH) 74 #define KTM_RW 43 75 #define KTM_RW_MODE (S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH) 76 #define KTM_DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 77 int kt_rw; 78 int kt_vtype; 79 } kern_targets[] = { 80 /* NOTE: The name must be less than UIO_MX-16 chars in length */ 81 /* name data tag ro/rw */ 82 { ".", 0, KTT_NULL, KTM_RO, VDIR }, 83 { "..", 0, KTT_NULL, KTM_RO, VDIR }, 84 { "copyright", copyright, KTT_STRING, KTM_RO, VREG }, 85 { "hostname", 0, KTT_HOSTNAME, KTM_RW, VREG }, 86 { "hz", &hz, KTT_INT, KTM_RO, VREG }, 87 { "loadavg", 0, KTT_AVENRUN, KTM_RO, VREG }, 88 { "physmem", &physmem, KTT_INT, KTM_RO, VREG }, 89 { "root", 0, KTT_NULL, KTM_RO, VDIR }, 90 { "rootdev", 0, KTT_NULL, KTM_RO, VBLK }, 91 { "rrootdev", 0, KTT_NULL, KTM_RO, VCHR }, 92 { "time", 0, KTT_TIME, KTM_RO, VREG }, 93 { "version", version, KTT_STRING, KTM_RO, VREG }, 94 }; 95 96 static int nkern_targets = sizeof(kern_targets) / sizeof(kern_targets[0]); 97 98 static int 99 kernfs_xread(kt, buf, len, lenp) 100 struct kern_target *kt; 101 char *buf; 102 int len; 103 int *lenp; 104 { 105 int xlen; 106 107 switch (kt->kt_tag) { 108 case KTT_TIME: { 109 struct timeval tv; 110 microtime(&tv); 111 sprintf(buf, "%d %d\n", tv.tv_sec, tv.tv_usec); 112 break; 113 } 114 115 case KTT_INT: { 116 int *ip = kt->kt_data; 117 sprintf(buf, "%d\n", *ip); 118 break; 119 } 120 121 case KTT_STRING: { 122 char *cp = kt->kt_data; 123 int xlen = strlen(cp) + 1; 124 125 if (xlen >= len) 126 return (EINVAL); 127 128 bcopy(cp, buf, xlen); 129 break; 130 } 131 132 case KTT_HOSTNAME: { 133 char *cp = hostname; 134 int xlen = hostnamelen; 135 136 if (xlen >= len) 137 return (EINVAL); 138 139 sprintf(buf, "%s\n", cp); 140 break; 141 } 142 143 case KTT_AVENRUN: 144 sprintf(buf, "%d %d %d %d\n", 145 averunnable[0], 146 averunnable[1], 147 averunnable[2], 148 FSCALE); 149 break; 150 151 default: 152 return (EINVAL); 153 } 154 155 *lenp = strlen(buf); 156 return (0); 157 } 158 159 static int 160 kernfs_xwrite(kt, buf, len) 161 struct kern_target *kt; 162 char *buf; 163 int len; 164 { 165 switch (kt->kt_tag) { 166 case KTT_HOSTNAME: { 167 if (buf[len-1] == '\n') 168 --len; 169 bcopy(buf, hostname, len); 170 hostnamelen = len - 1; 171 return (0); 172 } 173 174 default: 175 return (EIO); 176 } 177 } 178 179 /* 180 * vp is the current namei directory 181 * ndp is the name to locate in that directory... 182 */ 183 kernfs_lookup(dvp, ndp, p) 184 struct vnode *dvp; 185 struct nameidata *ndp; 186 struct proc *p; 187 { 188 char *pname = ndp->ni_ptr; 189 int error = ENOENT; 190 int i; 191 struct vnode *fvp; 192 193 #ifdef KERNFS_DIAGNOSTIC 194 printf("kernfs_lookup(%s)\n", pname); 195 #endif 196 if (ndp->ni_namelen == 1 && *pname == '.') { 197 ndp->ni_dvp = dvp; 198 ndp->ni_vp = dvp; 199 VREF(dvp); 200 /*VOP_LOCK(dvp);*/ 201 return (0); 202 } 203 204 if (ndp->ni_namelen == 4 && bcmp(pname, "root", 4) == 0) { 205 ndp->ni_dvp = dvp; 206 ndp->ni_vp = rootdir; 207 VREF(rootdir); 208 VOP_LOCK(rootdir); 209 return (0); 210 } 211 212 /* 213 * /kern/rootdev is the root device 214 */ 215 if (ndp->ni_namelen == 7 && bcmp(pname, "rootdev", 7) == 0) { 216 if (vfinddev(rootdev, VBLK, &fvp)) 217 return (ENXIO); 218 ndp->ni_dvp = dvp; 219 ndp->ni_vp = fvp; 220 VREF(fvp); 221 VOP_LOCK(fvp); 222 return (0); 223 } 224 225 /* 226 * /kern/rrootdev is the root device 227 */ 228 if (ndp->ni_namelen == 8 && bcmp(pname, "rrootdev", 7) == 0) { 229 ndp->ni_dvp = dvp; 230 ndp->ni_vp = rrootdevvp; 231 VREF(rrootdevvp); 232 VOP_LOCK(rrootdevvp); 233 return (0); 234 } 235 236 for (i = 0; i < nkern_targets; i++) { 237 struct kern_target *kt = &kern_targets[i]; 238 if (ndp->ni_namelen == strlen(kt->kt_name) && 239 bcmp(kt->kt_name, pname, ndp->ni_namelen) == 0) { 240 error = 0; 241 break; 242 } 243 } 244 245 #ifdef KERNFS_DIAGNOSTIC 246 printf("kernfs_lookup: i = %d, error = %d\n", i, error); 247 #endif 248 249 if (error) 250 goto bad; 251 252 #ifdef KERNFS_DIAGNOSTIC 253 printf("kernfs_lookup: allocate new vnode\n"); 254 #endif 255 error = getnewvnode(VT_UFS, dvp->v_mount, &kernfs_vnodeops, &fvp); 256 if (error) 257 goto bad; 258 VTOKERN(fvp)->kf_kt = &kern_targets[i]; 259 fvp->v_type = VTOKERN(fvp)->kf_kt->kt_vtype; 260 ndp->ni_dvp = dvp; 261 ndp->ni_vp = fvp; 262 #ifdef KERNFS_DIAGNOSTIC 263 printf("kernfs_lookup: newvp = %x\n", fvp); 264 #endif 265 return (0); 266 267 bad:; 268 ndp->ni_dvp = dvp; 269 ndp->ni_vp = NULL; 270 #ifdef KERNFS_DIAGNOSTIC 271 printf("kernfs_lookup: error = %d\n", error); 272 #endif 273 return (error); 274 } 275 276 kernfs_open(vp, mode, cred, p) 277 struct vnode *vp; 278 int mode; 279 struct ucred *cred; 280 struct proc *p; 281 { 282 int error; 283 struct filedesc *fdp; 284 struct file *fp; 285 int dfd; 286 int fd; 287 288 #ifdef KERNFS_DIAGNOSTIC 289 printf("kernfs_open\n"); 290 #endif 291 292 /* 293 * Can always open the root (modulo perms) 294 */ 295 if (vp->v_flag & VROOT) 296 return (0); 297 298 #ifdef KERNFS_DIAGNOSTIC 299 printf("kernfs_open, mode = %x, file = %s\n", 300 mode, VTOKERN(vp)->kf_kt->kt_name); 301 #endif 302 303 if ((mode & FWRITE) && VTOKERN(vp)->kf_kt->kt_rw != KTM_RW) 304 return (EBADF); 305 306 return (0); 307 } 308 309 kernfs_getattr(vp, vap, cred, p) 310 struct vnode *vp; 311 struct vattr *vap; 312 struct ucred *cred; 313 struct proc *p; 314 { 315 int error = 0; 316 char strbuf[KSTRING]; 317 struct kern_target *kt = VTOKERN(vp)->kf_kt; 318 319 bzero((caddr_t) vap, sizeof(*vap)); 320 vattr_null(vap); 321 vap->va_uid = 0; 322 vap->va_gid = 0; 323 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 324 /* vap->va_qsize = 0; */ 325 vap->va_blocksize = DEV_BSIZE; 326 microtime(&vap->va_atime); 327 vap->va_mtime = vap->va_atime; 328 vap->va_ctime = vap->va_ctime; 329 vap->va_gen = 0; 330 vap->va_flags = 0; 331 vap->va_rdev = 0; 332 /* vap->va_qbytes = 0; */ 333 vap->va_bytes = 0; 334 335 if (vp->v_flag & VROOT) { 336 #ifdef KERNFS_DIAGNOSTIC 337 printf("kernfs_getattr: stat rootdir\n"); 338 #endif 339 vap->va_type = VDIR; 340 vap->va_mode = KTM_DIR_MODE; 341 vap->va_nlink = 2; 342 vap->va_fileid = 2; 343 vap->va_size = DEV_BSIZE; 344 } else { 345 #ifdef KERNFS_DIAGNOSTIC 346 printf("kernfs_getattr: stat target %s\n", kt->kt_name); 347 #endif 348 vap->va_type = kt->kt_vtype; 349 vap->va_mode = (kt->kt_rw ? KTM_RW_MODE : KTM_RO_MODE); 350 vap->va_nlink = 1; 351 vap->va_fileid = 3 + (kt - kern_targets) / sizeof(*kt); 352 error = kernfs_xread(kt, strbuf, sizeof(strbuf), &vap->va_size); 353 } 354 355 vp->v_type = vap->va_type; 356 #ifdef KERNFS_DIAGNOSTIC 357 printf("kernfs_getattr: return error %d\n", error); 358 #endif 359 return (error); 360 } 361 362 kernfs_setattr(vp, vap, cred, p) 363 struct vnode *vp; 364 struct vattr *vap; 365 struct ucred *cred; 366 struct proc *p; 367 { 368 369 /* 370 * Silently ignore attribute changes. 371 * This allows for open with truncate to have no 372 * effect until some data is written. I want to 373 * do it this way because all writes are atomic. 374 */ 375 return (0); 376 } 377 378 static int 379 kernfs_read(vp, uio, ioflag, cred) 380 struct vnode *vp; 381 struct uio *uio; 382 int ioflag; 383 struct ucred *cred; 384 { 385 struct kern_target *kt = VTOKERN(vp)->kf_kt; 386 char strbuf[KSTRING]; 387 int off = uio->uio_offset; 388 int len = 0; 389 char *cp = strbuf; 390 int error; 391 #ifdef KERNFS_DIAGNOSTIC 392 printf("kern_read %s\n", kt->kt_name); 393 #endif 394 395 error = kernfs_xread(kt, strbuf, sizeof(strbuf), &len); 396 if (error) 397 return (error); 398 cp = strbuf + off; 399 len -= off; 400 return (uiomove(cp, len, uio)); 401 } 402 403 static int 404 kernfs_write(vp, uio, ioflag, cred) 405 struct vnode *vp; 406 struct uio *uio; 407 int ioflag; 408 struct ucred *cred; 409 { 410 struct kern_target *kt = VTOKERN(vp)->kf_kt; 411 char strbuf[KSTRING]; 412 int len = uio->uio_resid; 413 char *cp = strbuf; 414 int xlen; 415 int error; 416 417 if (uio->uio_offset != 0) 418 return (EINVAL); 419 420 xlen = min(uio->uio_resid, KSTRING-1); 421 error = uiomove(strbuf, xlen, uio); 422 if (error) 423 return (error); 424 425 if (uio->uio_resid != 0) 426 return (EIO); 427 428 strbuf[xlen] = '\0'; 429 return (kernfs_xwrite(kt, strbuf, xlen)); 430 } 431 432 kernfs_readdir(vp, uio, cred, eofflagp) 433 struct vnode *vp; 434 struct uio *uio; 435 struct ucred *cred; 436 int *eofflagp; 437 { 438 struct filedesc *fdp; 439 int i; 440 int error; 441 442 i = uio->uio_offset / UIO_MX; 443 error = 0; 444 while (uio->uio_resid > 0) { 445 #ifdef KERNFS_DIAGNOSTIC 446 printf("kernfs_readdir: i = %d\n", i); 447 #endif 448 if (i >= nkern_targets) { 449 *eofflagp = 1; 450 break; 451 } 452 { 453 struct direct d; 454 struct direct *dp = &d; 455 struct kern_target *kt = &kern_targets[i]; 456 457 bzero((caddr_t) dp, UIO_MX); 458 459 dp->d_namlen = strlen(kt->kt_name); 460 bcopy(kt->kt_name, dp->d_name, dp->d_namlen+1); 461 462 #ifdef KERNFS_DIAGNOSTIC 463 printf("kernfs_readdir: name = %s, len = %d\n", 464 dp->d_name, dp->d_namlen); 465 #endif 466 /* 467 * Fill in the remaining fields 468 */ 469 dp->d_reclen = UIO_MX; 470 dp->d_ino = i + 3; 471 /* 472 * And ship to userland 473 */ 474 error = uiomove((caddr_t) dp, UIO_MX, uio); 475 if (error) 476 break; 477 } 478 i++; 479 } 480 481 uio->uio_offset = i * UIO_MX; 482 483 return (error); 484 } 485 486 kernfs_inactive(vp, p) 487 struct vnode *vp; 488 struct proc *p; 489 { 490 /* 491 * Clear out the v_type field to avoid 492 * nasty things happening in vgone(). 493 */ 494 vp->v_type = VNON; 495 #ifdef KERNFS_DIAGNOSTIC 496 printf("kernfs_inactive(%x)\n", vp); 497 #endif 498 return (0); 499 } 500 501 /* 502 * Print out the contents of a kernfs vnode. 503 */ 504 /* ARGSUSED */ 505 kernfs_print(vp) 506 struct vnode *vp; 507 { 508 printf("tag VT_NON, kernfs vnode\n"); 509 } 510 511 /* 512 * kernfs vnode unsupported operation 513 */ 514 kernfs_enotsupp() 515 { 516 return (EOPNOTSUPP); 517 } 518 519 /* 520 * kernfs "should never get here" operation 521 */ 522 kernfs_badop() 523 { 524 panic("kernfs: bad op"); 525 /* NOTREACHED */ 526 } 527 528 /* 529 * kernfs vnode null operation 530 */ 531 kernfs_nullop() 532 { 533 return (0); 534 } 535 536 #define kernfs_create ((int (*) __P(( \ 537 struct nameidata *ndp, \ 538 struct vattr *vap, \ 539 struct proc *p))) kernfs_enotsupp) 540 #define kernfs_mknod ((int (*) __P(( \ 541 struct nameidata *ndp, \ 542 struct vattr *vap, \ 543 struct ucred *cred, \ 544 struct proc *p))) kernfs_enotsupp) 545 #define kernfs_close ((int (*) __P(( \ 546 struct vnode *vp, \ 547 int fflag, \ 548 struct ucred *cred, \ 549 struct proc *p))) nullop) 550 #define kernfs_access ((int (*) __P(( \ 551 struct vnode *vp, \ 552 int mode, \ 553 struct ucred *cred, \ 554 struct proc *p))) nullop) 555 #define kernfs_ioctl ((int (*) __P(( \ 556 struct vnode *vp, \ 557 int command, \ 558 caddr_t data, \ 559 int fflag, \ 560 struct ucred *cred, \ 561 struct proc *p))) kernfs_enotsupp) 562 #define kernfs_select ((int (*) __P(( \ 563 struct vnode *vp, \ 564 int which, \ 565 int fflags, \ 566 struct ucred *cred, \ 567 struct proc *p))) kernfs_enotsupp) 568 #define kernfs_mmap ((int (*) __P(( \ 569 struct vnode *vp, \ 570 int fflags, \ 571 struct ucred *cred, \ 572 struct proc *p))) kernfs_enotsupp) 573 #define kernfs_fsync ((int (*) __P(( \ 574 struct vnode *vp, \ 575 int fflags, \ 576 struct ucred *cred, \ 577 int waitfor, \ 578 struct proc *p))) nullop) 579 #define kernfs_seek ((int (*) __P(( \ 580 struct vnode *vp, \ 581 off_t oldoff, \ 582 off_t newoff, \ 583 struct ucred *cred))) nullop) 584 #define kernfs_remove ((int (*) __P(( \ 585 struct nameidata *ndp, \ 586 struct proc *p))) kernfs_enotsupp) 587 #define kernfs_link ((int (*) __P(( \ 588 struct vnode *vp, \ 589 struct nameidata *ndp, \ 590 struct proc *p))) kernfs_enotsupp) 591 #define kernfs_rename ((int (*) __P(( \ 592 struct nameidata *fndp, \ 593 struct nameidata *tdnp, \ 594 struct proc *p))) kernfs_enotsupp) 595 #define kernfs_mkdir ((int (*) __P(( \ 596 struct nameidata *ndp, \ 597 struct vattr *vap, \ 598 struct proc *p))) kernfs_enotsupp) 599 #define kernfs_rmdir ((int (*) __P(( \ 600 struct nameidata *ndp, \ 601 struct proc *p))) kernfs_enotsupp) 602 #define kernfs_symlink ((int (*) __P(( \ 603 struct nameidata *ndp, \ 604 struct vattr *vap, \ 605 char *target, \ 606 struct proc *p))) kernfs_enotsupp) 607 #define kernfs_readlink ((int (*) __P(( \ 608 struct vnode *vp, \ 609 struct uio *uio, \ 610 struct ucred *cred))) kernfs_enotsupp) 611 #define kernfs_abortop ((int (*) __P(( \ 612 struct nameidata *ndp))) nullop) 613 #ifdef KERNFS_DIAGNOSTIC 614 int kernfs_reclaim(vp) 615 struct vnode *vp; 616 { 617 printf("kernfs_reclaim(%x)\n", vp); 618 return (0); 619 } 620 #else 621 #define kernfs_reclaim ((int (*) __P(( \ 622 struct vnode *vp))) nullop) 623 #endif 624 #define kernfs_lock ((int (*) __P(( \ 625 struct vnode *vp))) nullop) 626 #define kernfs_unlock ((int (*) __P(( \ 627 struct vnode *vp))) nullop) 628 #define kernfs_bmap ((int (*) __P(( \ 629 struct vnode *vp, \ 630 daddr_t bn, \ 631 struct vnode **vpp, \ 632 daddr_t *bnp))) kernfs_badop) 633 #define kernfs_strategy ((int (*) __P(( \ 634 struct buf *bp))) kernfs_badop) 635 #define kernfs_islocked ((int (*) __P(( \ 636 struct vnode *vp))) nullop) 637 #define kernfs_advlock ((int (*) __P(( \ 638 struct vnode *vp, \ 639 caddr_t id, \ 640 int op, \ 641 struct flock *fl, \ 642 int flags))) kernfs_enotsupp) 643 644 struct vnodeops kernfs_vnodeops = { 645 kernfs_lookup, /* lookup */ 646 kernfs_create, /* create */ 647 kernfs_mknod, /* mknod */ 648 kernfs_open, /* open */ 649 kernfs_close, /* close */ 650 kernfs_access, /* access */ 651 kernfs_getattr, /* getattr */ 652 kernfs_setattr, /* setattr */ 653 kernfs_read, /* read */ 654 kernfs_write, /* write */ 655 kernfs_ioctl, /* ioctl */ 656 kernfs_select, /* select */ 657 kernfs_mmap, /* mmap */ 658 kernfs_fsync, /* fsync */ 659 kernfs_seek, /* seek */ 660 kernfs_remove, /* remove */ 661 kernfs_link, /* link */ 662 kernfs_rename, /* rename */ 663 kernfs_mkdir, /* mkdir */ 664 kernfs_rmdir, /* rmdir */ 665 kernfs_symlink, /* symlink */ 666 kernfs_readdir, /* readdir */ 667 kernfs_readlink, /* readlink */ 668 kernfs_abortop, /* abortop */ 669 kernfs_inactive, /* inactive */ 670 kernfs_reclaim, /* reclaim */ 671 kernfs_lock, /* lock */ 672 kernfs_unlock, /* unlock */ 673 kernfs_bmap, /* bmap */ 674 kernfs_strategy, /* strategy */ 675 kernfs_print, /* print */ 676 kernfs_islocked, /* islocked */ 677 kernfs_advlock, /* advlock */ 678 }; 679