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: fdesc_vnops.c,v 1.4 1993/06/07 05:25:22 cgd Exp $ 37 */ 38 39 /* 40 * /dev/fd Filesystem 41 */ 42 43 #include "param.h" 44 #include "systm.h" 45 #include "types.h" 46 #include "time.h" 47 #include "proc.h" 48 #include "resourcevar.h" 49 #include "filedesc.h" 50 #include "vnode.h" 51 #include "file.h" 52 #include "stat.h" 53 #include "mount.h" 54 #include "namei.h" 55 #include "buf.h" 56 #include "miscfs/fdesc/fdesc.h" 57 58 #include "../ufs/dir.h" /* For readdir() XXX */ 59 60 /* 61 * vp is the current namei directory 62 * ndp is the name to locate in that directory... 63 */ 64 fdesc_lookup(dvp, ndp, p) 65 struct vnode *dvp; 66 struct nameidata *ndp; 67 struct proc *p; 68 { 69 char *pname = ndp->ni_ptr; 70 int nfiles = p->p_fd->fd_nfiles; 71 unsigned fd; 72 int error; 73 struct vnode *fvp; 74 75 #ifdef FDESC_DIAGNOSTIC 76 printf("fdesc_lookup(%s)\n", pname); 77 #endif 78 if (ndp->ni_namelen == 1 && *pname == '.') { 79 ndp->ni_dvp = dvp; 80 ndp->ni_vp = dvp; 81 VREF(dvp); 82 /*VOP_LOCK(dvp);*/ 83 return (0); 84 } 85 86 fd = 0; 87 while (*pname >= '0' && *pname <= '9') { 88 fd = 10 * fd + *pname++ - '0'; 89 if (fd >= nfiles) 90 break; 91 } 92 93 #ifdef FDESC_DIAGNOSTIC 94 printf("fdesc_lookup: fd = %d, *pname = %x\n", fd, *pname); 95 #endif 96 if (*pname == '/') { 97 error = ENOTDIR; 98 goto bad; 99 } 100 101 if (*pname != '\0') { 102 error = ENOENT; 103 goto bad; 104 } 105 106 if (fd >= nfiles || p->p_fd->fd_ofiles[fd] == NULL) { 107 error = EBADF; 108 goto bad; 109 } 110 111 #ifdef FDESC_DIAGNOSTIC 112 printf("fdesc_lookup: allocate new vnode\n"); 113 #endif 114 error = getnewvnode(VT_FDESC, dvp->v_mount, &fdesc_vnodeops, &fvp); 115 if (error) 116 goto bad; 117 VTOFDESC(fvp)->f_fd = fd; 118 /*VTOFDESC(fvp)->f_isroot = 0;*/ 119 ndp->ni_dvp = dvp; 120 ndp->ni_vp = fvp; 121 #ifdef FDESC_DIAGNOSTIC 122 printf("fdesc_lookup: newvp = %x\n", fvp); 123 #endif 124 return (0); 125 126 bad:; 127 ndp->ni_dvp = dvp; 128 ndp->ni_vp = NULL; 129 #ifdef FDESC_DIAGNOSTIC 130 printf("fdesc_lookup: error = %d\n", error); 131 #endif 132 return (error); 133 } 134 135 fdesc_open(vp, mode, cred, p) 136 struct vnode *vp; 137 int mode; 138 struct ucred *cred; 139 struct proc *p; 140 { 141 int error; 142 struct filedesc *fdp; 143 struct file *fp; 144 int dfd; 145 int fd; 146 147 /* 148 * Can always open the root (modulo perms) 149 */ 150 if (vp->v_flag & VROOT) 151 return (0); 152 153 /* 154 * XXX Kludge: set p->p_dupfd to contain the value of the 155 * the file descriptor being sought for duplication. The error 156 * return ensures that the vnode for this device will be released 157 * by vn_open. Open will detect this special error and take the 158 * actions in dupfdopen. Other callers of vn_open or VOP_OPEN 159 * will simply report the error. 160 */ 161 p->p_dupfd = VTOFDESC(vp)->f_fd; /* XXX */ 162 return (ENODEV); 163 } 164 165 static int 166 fdesc_attr(fd, vap, cred, p) 167 int fd; 168 struct vattr *vap; 169 struct ucred *cred; 170 struct proc *p; 171 { 172 struct filedesc *fdp = p->p_fd; 173 struct file *fp; 174 int error; 175 176 #ifdef FDESC_DIAGNOSTIC 177 printf("fdesc_attr: fd = %d, nfiles = %d\n", fd, fdp->fd_nfiles); 178 #endif 179 if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) { 180 #ifdef FDESC_DIAGNOSTIC 181 printf("fdesc_attr: fp = %x (EBADF)\n", fp); 182 #endif 183 return (EBADF); 184 } 185 186 /* 187 * Can stat the underlying vnode, but not sockets because 188 * they don't use struct vattrs. Well, we could convert from 189 * a struct stat back to a struct vattr, later... 190 */ 191 switch (fp->f_type) { 192 case DTYPE_VNODE: 193 error = VOP_GETATTR((struct vnode *) fp->f_data, vap, cred, p); 194 break; 195 196 case DTYPE_SOCKET: 197 error = EOPNOTSUPP; 198 break; 199 200 default: 201 panic("fdesc attr"); 202 break; 203 } 204 205 #ifdef FDESC_DIAGNOSTIC 206 printf("fdesc_attr: returns error %d\n", error); 207 #endif 208 return (error); 209 } 210 211 fdesc_getattr(vp, vap, cred, p) 212 struct vnode *vp; 213 struct vattr *vap; 214 struct ucred *cred; 215 struct proc *p; 216 { 217 unsigned fd; 218 int error; 219 220 if (vp->v_flag & VROOT) { 221 #ifdef FDESC_DIAGNOSTIC 222 printf("fdesc_getattr: stat rootdir\n"); 223 #endif 224 bzero((caddr_t) vap, sizeof(*vap)); 225 vattr_null(vap); 226 vap->va_type = VDIR; 227 vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; 228 vap->va_nlink = 2; 229 vap->va_uid = 0; 230 vap->va_gid = 0; 231 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 232 vap->va_fileid = 2; 233 /* vap->va_qsize = 0; */ 234 vap->va_size = DEV_BSIZE; 235 vap->va_blocksize = DEV_BSIZE; 236 microtime(&vap->va_atime); 237 vap->va_mtime = vap->va_atime; 238 vap->va_ctime = vap->va_ctime; 239 vap->va_gen = 0; 240 vap->va_flags = 0; 241 vap->va_rdev = 0; 242 /* vap->va_qbytes = 0; */ 243 vap->va_bytes = 0; 244 return (0); 245 } 246 247 fd = VTOFDESC(vp)->f_fd; 248 error = fdesc_attr(fd, vap, cred, p); 249 if (error == 0) 250 vp->v_type = vap->va_type; 251 return (error); 252 } 253 254 fdesc_setattr(vp, vap, cred, p) 255 struct vnode *vp; 256 struct vattr *vap; 257 struct ucred *cred; 258 struct proc *p; 259 { 260 struct filedesc *fdp = p->p_fd; 261 struct file *fp; 262 unsigned fd; 263 int error; 264 265 /* 266 * Can't mess with the root vnode 267 */ 268 if (vp->v_flag & VROOT) 269 return (EACCES); 270 271 fd = VTOFDESC(vp)->f_fd; 272 #ifdef FDESC_DIAGNOSTIC 273 printf("fdesc_setattr: fd = %d, nfiles = %d\n", fd, fdp->fd_nfiles); 274 #endif 275 if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) { 276 #ifdef FDESC_DIAGNOSTIC 277 printf("fdesc_setattr: fp = %x (EBADF)\n", fp); 278 #endif 279 return (EBADF); 280 } 281 282 /* 283 * Can setattr the underlying vnode, but not sockets! 284 */ 285 switch (fp->f_type) { 286 case DTYPE_VNODE: 287 error = VOP_SETATTR((struct vnode *) fp->f_data, vap, cred, p); 288 break; 289 290 case DTYPE_SOCKET: 291 error = EOPNOTSUPP; 292 break; 293 294 default: 295 panic("fdesc setattr"); 296 break; 297 } 298 299 #ifdef FDESC_DIAGNOSTIC 300 printf("fdesc_setattr: returns error %d\n", error); 301 #endif 302 return (error); 303 } 304 305 fdesc_readdir(vp, uio, cred, eofflagp) 306 struct vnode *vp; 307 struct uio *uio; 308 struct ucred *cred; 309 int *eofflagp; 310 { 311 struct filedesc *fdp; 312 int ind, i; 313 int error; 314 315 #define UIO_MX 16 316 317 fdp = uio->uio_procp->p_fd; 318 ind = uio->uio_offset / UIO_MX; 319 error = 0; 320 while (uio->uio_resid > 0) { 321 struct direct d; 322 struct direct *dp = &d; 323 324 if (ind < 2) { /* . or .. */ 325 bzero((caddr_t) dp, UIO_MX); 326 if (ind == 0) { 327 strcpy(dp->d_name, "."); 328 dp->d_namlen = 1; 329 } else if (ind == 1) { 330 strcpy(dp->d_name, ".."); 331 dp->d_namlen = 2; 332 } else 333 panic("fdesc: ind is negative!"); 334 335 dp->d_reclen = UIO_MX; 336 dp->d_ino = 2; 337 338 /* 339 * And ship to userland 340 */ 341 error = uiomove((caddr_t) dp, UIO_MX, uio); 342 if (error) 343 break; 344 345 ind++; 346 continue; 347 } 348 i = ind - 2; 349 if (i >= fdp->fd_nfiles) { 350 *eofflagp = 1; 351 break; 352 } 353 if (fdp->fd_ofiles[i] != NULL) { 354 struct direct d; 355 struct direct *dp = &d; 356 char *cp = dp->d_name; 357 #ifdef FDESC_FILEID 358 struct vattr va; 359 #endif 360 int j; 361 362 bzero((caddr_t) dp, UIO_MX); 363 364 /* 365 * Generate an ASCII representation of the name. 366 * This can cope with fds in the range 0..99999 367 */ 368 cp++; 369 if (i > 10) cp++; 370 if (i > 100) cp++; 371 if (i > 1000) cp++; 372 if (i > 10000) cp++; 373 if (i > 100000) panic("fdesc_readdir"); 374 dp->d_namlen = cp - dp->d_name; 375 *cp = '\0'; 376 j = i; 377 do { 378 *--cp = j % 10 + '0'; 379 j /= 10; 380 } while (j > 0); 381 /* 382 * Fill in the remaining fields 383 */ 384 dp->d_reclen = UIO_MX; 385 dp->d_ino = i + 3; 386 #ifdef FDESC_FILEID 387 /* 388 * If we want the file ids to match the 389 * we must call getattr on the underlying file. 390 * fdesc_attr may return an error, in which case 391 * we ignore the returned file id. 392 */ 393 error = fdesc_attr(i, &va, cred, p); 394 if (error == 0) 395 dp->d_ino = va.va_fileid; 396 #endif 397 /* 398 * And ship to userland 399 */ 400 error = uiomove((caddr_t) dp, UIO_MX, uio); 401 if (error) 402 break; 403 } 404 ind++; 405 } 406 407 uio->uio_offset = ind * UIO_MX; 408 return (error); 409 } 410 411 fdesc_inactive(vp, p) 412 struct vnode *vp; 413 struct proc *p; 414 { 415 /* 416 * Clear out the v_type field to avoid 417 * nasty things happening in vgone(). 418 */ 419 vp->v_type = VNON; 420 #ifdef FDESC_DIAGNOSTIC 421 printf("fdesc_inactive(%x)\n", vp); 422 #endif 423 return (0); 424 } 425 426 /* 427 * Print out the contents of a /dev/fd vnode. 428 */ 429 /* ARGSUSED */ 430 fdesc_print(vp) 431 struct vnode *vp; 432 { 433 printf("tag VT_FDESC, fdesc vnode\n"); 434 } 435 436 /* 437 * /dev/fd vnode unsupported operation 438 */ 439 fdesc_enotsupp() 440 { 441 return (EOPNOTSUPP); 442 } 443 444 /* 445 * /dev/fd "should never get here" operation 446 */ 447 fdesc_badop() 448 { 449 panic("fdesc: bad op"); 450 /* NOTREACHED */ 451 } 452 453 /* 454 * /dev/fd vnode null operation 455 */ 456 fdesc_nullop() 457 { 458 return (0); 459 } 460 461 #define fdesc_create ((int (*) __P(( \ 462 struct nameidata *ndp, \ 463 struct vattr *vap, \ 464 struct proc *p))) fdesc_enotsupp) 465 #define fdesc_mknod ((int (*) __P(( \ 466 struct nameidata *ndp, \ 467 struct vattr *vap, \ 468 struct ucred *cred, \ 469 struct proc *p))) fdesc_enotsupp) 470 #define fdesc_close ((int (*) __P(( \ 471 struct vnode *vp, \ 472 int fflag, \ 473 struct ucred *cred, \ 474 struct proc *p))) nullop) 475 #define fdesc_access ((int (*) __P(( \ 476 struct vnode *vp, \ 477 int mode, \ 478 struct ucred *cred, \ 479 struct proc *p))) nullop) 480 #define fdesc_read ((int (*) __P(( \ 481 struct vnode *vp, \ 482 struct uio *uio, \ 483 int ioflag, \ 484 struct ucred *cred))) fdesc_enotsupp) 485 #define fdesc_write ((int (*) __P(( \ 486 struct vnode *vp, \ 487 struct uio *uio, \ 488 int ioflag, \ 489 struct ucred *cred))) fdesc_enotsupp) 490 #define fdesc_ioctl ((int (*) __P(( \ 491 struct vnode *vp, \ 492 int command, \ 493 caddr_t data, \ 494 int fflag, \ 495 struct ucred *cred, \ 496 struct proc *p))) fdesc_enotsupp) 497 #define fdesc_select ((int (*) __P(( \ 498 struct vnode *vp, \ 499 int which, \ 500 int fflags, \ 501 struct ucred *cred, \ 502 struct proc *p))) fdesc_enotsupp) 503 #define fdesc_mmap ((int (*) __P(( \ 504 struct vnode *vp, \ 505 int fflags, \ 506 struct ucred *cred, \ 507 struct proc *p))) fdesc_enotsupp) 508 #define fdesc_fsync ((int (*) __P(( \ 509 struct vnode *vp, \ 510 int fflags, \ 511 struct ucred *cred, \ 512 int waitfor, \ 513 struct proc *p))) nullop) 514 #define fdesc_seek ((int (*) __P(( \ 515 struct vnode *vp, \ 516 off_t oldoff, \ 517 off_t newoff, \ 518 struct ucred *cred))) nullop) 519 #define fdesc_remove ((int (*) __P(( \ 520 struct nameidata *ndp, \ 521 struct proc *p))) fdesc_enotsupp) 522 #define fdesc_link ((int (*) __P(( \ 523 struct vnode *vp, \ 524 struct nameidata *ndp, \ 525 struct proc *p))) fdesc_enotsupp) 526 #define fdesc_rename ((int (*) __P(( \ 527 struct nameidata *fndp, \ 528 struct nameidata *tdnp, \ 529 struct proc *p))) fdesc_enotsupp) 530 #define fdesc_mkdir ((int (*) __P(( \ 531 struct nameidata *ndp, \ 532 struct vattr *vap, \ 533 struct proc *p))) fdesc_enotsupp) 534 #define fdesc_rmdir ((int (*) __P(( \ 535 struct nameidata *ndp, \ 536 struct proc *p))) fdesc_enotsupp) 537 #define fdesc_symlink ((int (*) __P(( \ 538 struct nameidata *ndp, \ 539 struct vattr *vap, \ 540 char *target, \ 541 struct proc *p))) fdesc_enotsupp) 542 #define fdesc_readlink ((int (*) __P(( \ 543 struct vnode *vp, \ 544 struct uio *uio, \ 545 struct ucred *cred))) fdesc_enotsupp) 546 #define fdesc_abortop ((int (*) __P(( \ 547 struct nameidata *ndp))) nullop) 548 #ifdef FDESC_DIAGNOSTIC 549 int fdesc_reclaim(vp) 550 struct vnode *vp; 551 { 552 printf("fdesc_reclaim(%x)\n", vp); 553 return (0); 554 } 555 #else 556 #define fdesc_reclaim ((int (*) __P(( \ 557 struct vnode *vp))) nullop) 558 #endif 559 #define fdesc_lock ((int (*) __P(( \ 560 struct vnode *vp))) nullop) 561 #define fdesc_unlock ((int (*) __P(( \ 562 struct vnode *vp))) nullop) 563 #define fdesc_bmap ((int (*) __P(( \ 564 struct vnode *vp, \ 565 daddr_t bn, \ 566 struct vnode **vpp, \ 567 daddr_t *bnp))) fdesc_badop) 568 #define fdesc_strategy ((int (*) __P(( \ 569 struct buf *bp))) fdesc_badop) 570 #define fdesc_islocked ((int (*) __P(( \ 571 struct vnode *vp))) nullop) 572 #define fdesc_advlock ((int (*) __P(( \ 573 struct vnode *vp, \ 574 caddr_t id, \ 575 int op, \ 576 struct flock *fl, \ 577 int flags))) fdesc_enotsupp) 578 579 struct vnodeops fdesc_vnodeops = { 580 fdesc_lookup, /* lookup */ 581 fdesc_create, /* create */ 582 fdesc_mknod, /* mknod */ 583 fdesc_open, /* open */ 584 fdesc_close, /* close */ 585 fdesc_access, /* access */ 586 fdesc_getattr, /* getattr */ 587 fdesc_setattr, /* setattr */ 588 fdesc_read, /* read */ 589 fdesc_write, /* write */ 590 fdesc_ioctl, /* ioctl */ 591 fdesc_select, /* select */ 592 fdesc_mmap, /* mmap */ 593 fdesc_fsync, /* fsync */ 594 fdesc_seek, /* seek */ 595 fdesc_remove, /* remove */ 596 fdesc_link, /* link */ 597 fdesc_rename, /* rename */ 598 fdesc_mkdir, /* mkdir */ 599 fdesc_rmdir, /* rmdir */ 600 fdesc_symlink, /* symlink */ 601 fdesc_readdir, /* readdir */ 602 fdesc_readlink, /* readlink */ 603 fdesc_abortop, /* abortop */ 604 fdesc_inactive, /* inactive */ 605 fdesc_reclaim, /* reclaim */ 606 fdesc_lock, /* lock */ 607 fdesc_unlock, /* unlock */ 608 fdesc_bmap, /* bmap */ 609 fdesc_strategy, /* strategy */ 610 fdesc_print, /* print */ 611 fdesc_islocked, /* islocked */ 612 fdesc_advlock, /* advlock */ 613 }; 614