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 * @(#)fdesc_vnops.c 7.3 (Berkeley) 03/11/93 12 * 13 * $Id: fdesc_vnops.c,v 1.7 1992/05/30 10:05:34 jsp Exp jsp $ 14 */ 15 16 /* 17 * /dev/fd Filesystem 18 */ 19 20 #include <sys/param.h> 21 #include <sys/systm.h> 22 #include <sys/types.h> 23 #include <sys/time.h> 24 #include <sys/proc.h> 25 #include <sys/resourcevar.h> 26 #include <sys/filedesc.h> 27 #include <sys/vnode.h> 28 #include <sys/malloc.h> 29 #include <sys/file.h> 30 #include <sys/stat.h> 31 #include <sys/mount.h> 32 #include <sys/namei.h> 33 #include <sys/buf.h> 34 #include <sys/dirent.h> 35 #include <miscfs/fdesc/fdesc.h> 36 37 /* 38 * vp is the current namei directory 39 * ndp is the name to locate in that directory... 40 */ 41 fdesc_lookup(ap) 42 struct vop_lookup_args /* { 43 struct vnode * a_dvp; 44 struct vnode ** a_vpp; 45 struct componentname * a_cnp; 46 } */ *ap; 47 { 48 struct vnode **vpp = ap->a_vpp; 49 struct vnode *dvp = ap->a_dvp; 50 char *pname; 51 struct proc *p; 52 int nfiles; 53 unsigned fd; 54 int error; 55 struct vnode *fvp; 56 57 #ifdef FDESC_DIAGNOSTIC 58 printf("fdesc_lookup(%x)\n", ap); 59 printf("fdesc_lookup(dp = %x, vpp = %x, cnp = %x)\n", dvp, vpp, ap->a_cnp); 60 #endif 61 pname = ap->a_cnp->cn_nameptr; 62 #ifdef FDESC_DIAGNOSTIC 63 printf("fdesc_lookup(%s)\n", pname); 64 #endif 65 if (ap->a_cnp->cn_namelen == 1 && *pname == '.') { 66 *vpp = dvp; 67 VREF(dvp); 68 /*VOP_LOCK(dvp);*/ 69 return (0); 70 } 71 72 p = ap->a_cnp->cn_proc; 73 nfiles = p->p_fd->fd_nfiles; 74 75 fd = 0; 76 while (*pname >= '0' && *pname <= '9') { 77 fd = 10 * fd + *pname++ - '0'; 78 if (fd >= nfiles) 79 break; 80 } 81 82 #ifdef FDESC_DIAGNOSTIC 83 printf("fdesc_lookup: fd = %d, *pname = %x\n", fd, *pname); 84 #endif 85 if (*pname != '\0') { 86 error = ENOENT; 87 goto bad; 88 } 89 90 if (fd >= nfiles || p->p_fd->fd_ofiles[fd] == NULL) { 91 error = EBADF; 92 goto bad; 93 } 94 95 #ifdef FDESC_DIAGNOSTIC 96 printf("fdesc_lookup: allocate new vnode\n"); 97 #endif 98 error = getnewvnode(VT_UFS, dvp->v_mount, fdesc_vnodeop_p, &fvp); 99 if (error) 100 goto bad; 101 MALLOC(fvp->v_data, void *, sizeof(struct fdescnode), M_TEMP, M_WAITOK); 102 VTOFDESC(fvp)->f_fd = fd; 103 *vpp = fvp; 104 #ifdef FDESC_DIAGNOSTIC 105 printf("fdesc_lookup: newvp = %x\n", fvp); 106 #endif 107 return (0); 108 109 bad:; 110 *vpp = NULL; 111 #ifdef FDESC_DIAGNOSTIC 112 printf("fdesc_lookup: error = %d\n", error); 113 #endif 114 return (error); 115 } 116 117 fdesc_open(ap) 118 struct vop_open_args /* { 119 struct vnode *a_vp; 120 int a_mode; 121 struct ucred *a_cred; 122 struct proc *a_p; 123 } */ *ap; 124 { 125 struct vnode *vp = ap->a_vp; 126 127 /* 128 * Can always open the root (modulo perms) 129 */ 130 if (vp->v_flag & VROOT) 131 return (0); 132 133 /* 134 * XXX Kludge: set ap->a_p->p_dupfd to contain the value of the 135 * the file descriptor being sought for duplication. The error 136 * return ensures that the vnode for this device will be released 137 * by vn_open. Open will detect this special error and take the 138 * actions in dupfdopen. Other callers of vn_open or VOP_OPEN 139 * will simply report the error. 140 */ 141 ap->a_p->p_dupfd = VTOFDESC(vp)->f_fd; /* XXX */ 142 return (ENODEV); 143 } 144 145 static int 146 fdesc_attr(fd, vap, cred, p) 147 int fd; 148 struct vattr *vap; 149 struct ucred *cred; 150 struct proc *p; 151 { 152 struct filedesc *fdp = p->p_fd; 153 struct file *fp; 154 int error; 155 156 #ifdef FDESC_DIAGNOSTIC 157 printf("fdesc_attr: fd = %d, nfiles = %d\n", fd, fdp->fd_nfiles); 158 #endif 159 if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) { 160 #ifdef FDESC_DIAGNOSTIC 161 printf("fdesc_attr: fp = %x (EBADF)\n", fp); 162 #endif 163 return (EBADF); 164 } 165 166 /* 167 * Can stat the underlying vnode, but not sockets because 168 * they don't use struct vattrs. Well, we could convert from 169 * a struct stat back to a struct vattr, later... 170 */ 171 switch (fp->f_type) { 172 case DTYPE_VNODE: 173 error = VOP_GETATTR((struct vnode *) fp->f_data, vap, cred, p); 174 break; 175 176 case DTYPE_SOCKET: 177 error = EOPNOTSUPP; 178 break; 179 180 default: 181 panic("fdesc attr"); 182 break; 183 } 184 185 #ifdef FDESC_DIAGNOSTIC 186 printf("fdesc_attr: returns error %d\n", error); 187 #endif 188 return (error); 189 } 190 191 fdesc_getattr(ap) 192 struct vop_getattr_args /* { 193 struct vnode *a_vp; 194 struct vattr *a_vap; 195 struct ucred *a_cred; 196 struct proc *a_p; 197 } */ *ap; 198 { 199 struct vnode *vp = ap->a_vp; 200 struct vattr *vap = ap->a_vap; 201 unsigned fd; 202 int error; 203 204 if (vp->v_flag & VROOT) { 205 #ifdef FDESC_DIAGNOSTIC 206 printf("fdesc_getattr: stat rootdir\n"); 207 #endif 208 bzero((caddr_t) vap, sizeof(*vap)); 209 vattr_null(vap); 210 vap->va_type = VDIR; 211 vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; 212 vap->va_nlink = 2; 213 vap->va_uid = 0; 214 vap->va_gid = 0; 215 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 216 vap->va_fileid = 2; 217 /* vap->va_qsize = 0; */ 218 vap->va_size = DEV_BSIZE; 219 vap->va_blocksize = DEV_BSIZE; 220 microtime(&vap->va_atime); 221 vap->va_mtime = vap->va_atime; 222 vap->va_ctime = vap->va_ctime; 223 vap->va_gen = 0; 224 vap->va_flags = 0; 225 vap->va_rdev = 0; 226 /* vap->va_qbytes = 0; */ 227 vap->va_bytes = 0; 228 return (0); 229 } 230 231 fd = VTOFDESC(vp)->f_fd; 232 error = fdesc_attr(fd, vap, ap->a_cred, ap->a_p); 233 if (error == 0) 234 vp->v_type = vap->va_type; 235 return (error); 236 } 237 238 fdesc_setattr(ap) 239 struct vop_setattr_args /* { 240 struct vnode *a_vp; 241 struct vattr *a_vap; 242 struct ucred *a_cred; 243 struct proc *a_p; 244 } */ *ap; 245 { 246 struct filedesc *fdp = ap->a_p->p_fd; 247 struct file *fp; 248 unsigned fd; 249 int error; 250 251 /* 252 * Can't mess with the root vnode 253 */ 254 if (ap->a_vp->v_flag & VROOT) 255 return (EACCES); 256 257 fd = VTOFDESC(ap->a_vp)->f_fd; 258 #ifdef FDESC_DIAGNOSTIC 259 printf("fdesc_setattr: fd = %d, nfiles = %d\n", fd, fdp->fd_nfiles); 260 #endif 261 if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) { 262 #ifdef FDESC_DIAGNOSTIC 263 printf("fdesc_setattr: fp = %x (EBADF)\n", fp); 264 #endif 265 return (EBADF); 266 } 267 268 /* 269 * Can setattr the underlying vnode, but not sockets! 270 */ 271 switch (fp->f_type) { 272 case DTYPE_VNODE: 273 error = VOP_SETATTR((struct vnode *) fp->f_data, ap->a_vap, ap->a_cred, ap->a_p); 274 break; 275 276 case DTYPE_SOCKET: 277 error = 0; 278 break; 279 280 default: 281 panic("fdesc setattr"); 282 break; 283 } 284 285 #ifdef FDESC_DIAGNOSTIC 286 printf("fdesc_setattr: returns error %d\n", error); 287 #endif 288 return (error); 289 } 290 291 fdesc_readdir(ap) 292 struct vop_readdir_args /* { 293 struct vnode *a_vp; 294 struct uio *a_uio; 295 struct ucred *a_cred; 296 } */ *ap; 297 { 298 struct uio *uio = ap->a_uio; 299 struct filedesc *fdp; 300 int i; 301 int error; 302 303 #define UIO_MX 16 304 305 fdp = uio->uio_procp->p_fd; 306 i = uio->uio_offset / UIO_MX; 307 error = 0; 308 while (uio->uio_resid > 0) { 309 if (i >= fdp->fd_nfiles) { 310 /* *ap->a_eofflagp = 1; */ 311 break; 312 } 313 if (fdp->fd_ofiles[i] != NULL) { 314 struct dirent d; 315 struct dirent *dp = &d; 316 char *cp = dp->d_name; 317 #ifdef FDESC_FILEID 318 struct vattr va; 319 #endif 320 bzero((caddr_t) dp, UIO_MX); 321 322 dp->d_namlen = sprintf(dp->d_name, "%d", i); 323 /* 324 * Fill in the remaining fields 325 */ 326 dp->d_reclen = UIO_MX; 327 dp->d_type = DT_UNKNOWN; 328 dp->d_fileno = i + 3; 329 #ifdef FDESC_FILEID 330 /* 331 * If we want the file ids to match the 332 * we must call getattr on the underlying file. 333 * fdesc_attr may return an error, in which case 334 * we ignore the returned file id. 335 */ 336 error = fdesc_attr(i, &va, ap->a_cred, p); 337 if (error == 0) 338 dp->d_ino = va.va_fileid; 339 #endif 340 /* 341 * And ship to userland 342 */ 343 error = uiomove((caddr_t) dp, UIO_MX, uio); 344 if (error) 345 break; 346 } 347 i++; 348 } 349 350 uio->uio_offset = i * UIO_MX; 351 return (error); 352 } 353 354 fdesc_inactive(ap) 355 struct vop_inactive_args /* { 356 struct vnode *a_vp; 357 } */ *ap; 358 { 359 struct vnode *vp = ap->a_vp; 360 361 /* 362 * Clear out the v_type field to avoid 363 * nasty things happening in vgone(). 364 */ 365 vp->v_type = VNON; 366 #ifdef FDESC_DIAGNOSTIC 367 printf("fdesc_inactive(%x)\n", vp); 368 #endif 369 return (0); 370 } 371 372 fdesc_reclaim(ap) 373 struct vop_reclaim_args /* { 374 struct vnode *a_vp; 375 } */ *ap; 376 { 377 struct vnode *vp = ap->a_vp; 378 printf("fdesc_reclaim(%x)\n", vp); 379 if (vp->v_data) { 380 FREE(vp->v_data, M_TEMP); 381 vp->v_data = 0; 382 } 383 return (0); 384 } 385 386 /* 387 * Print out the contents of a /dev/fd vnode. 388 */ 389 /* ARGSUSED */ 390 fdesc_print(ap) 391 struct vop_print_args /* { 392 struct vnode *a_vp; 393 } */ *ap; 394 { 395 396 printf("tag VT_NON, fdesc vnode\n"); 397 return (0); 398 } 399 400 /*void*/ 401 fdesc_vfree(ap) 402 struct vop_vfree_args /* { 403 struct vnode *a_pvp; 404 ino_t a_ino; 405 int a_mode; 406 } */ *ap; 407 { 408 409 return (0); 410 } 411 412 /* 413 * /dev/fd vnode unsupported operation 414 */ 415 fdesc_enotsupp() 416 { 417 418 return (EOPNOTSUPP); 419 } 420 421 /* 422 * /dev/fd "should never get here" operation 423 */ 424 fdesc_badop() 425 { 426 427 panic("fdesc: bad op"); 428 /* NOTREACHED */ 429 } 430 431 /* 432 * /dev/fd vnode null operation 433 */ 434 fdesc_nullop() 435 { 436 437 return (0); 438 } 439 440 #define fdesc_create ((int (*) __P((struct vop_create_args *)))fdesc_enotsupp) 441 #define fdesc_mknod ((int (*) __P((struct vop_mknod_args *)))fdesc_enotsupp) 442 #define fdesc_close ((int (*) __P((struct vop_close_args *)))nullop) 443 #define fdesc_access ((int (*) __P((struct vop_access_args *)))nullop) 444 #define fdesc_read ((int (*) __P((struct vop_read_args *)))fdesc_enotsupp) 445 #define fdesc_write ((int (*) __P((struct vop_write_args *)))fdesc_enotsupp) 446 #define fdesc_ioctl ((int (*) __P((struct vop_ioctl_args *)))fdesc_enotsupp) 447 #define fdesc_select ((int (*) __P((struct vop_select_args *)))fdesc_enotsupp) 448 #define fdesc_mmap ((int (*) __P((struct vop_mmap_args *)))fdesc_enotsupp) 449 #define fdesc_fsync ((int (*) __P((struct vop_fsync_args *)))nullop) 450 #define fdesc_seek ((int (*) __P((struct vop_seek_args *)))nullop) 451 #define fdesc_remove ((int (*) __P((struct vop_remove_args *)))fdesc_enotsupp) 452 #define fdesc_link ((int (*) __P((struct vop_link_args *)))fdesc_enotsupp) 453 #define fdesc_rename ((int (*) __P((struct vop_rename_args *)))fdesc_enotsupp) 454 #define fdesc_mkdir ((int (*) __P((struct vop_mkdir_args *)))fdesc_enotsupp) 455 #define fdesc_rmdir ((int (*) __P((struct vop_rmdir_args *)))fdesc_enotsupp) 456 #define fdesc_symlink ((int (*) __P((struct vop_symlink_args *)))fdesc_enotsupp) 457 #define fdesc_readlink \ 458 ((int (*) __P((struct vop_readlink_args *)))fdesc_enotsupp) 459 #define fdesc_abortop ((int (*) __P((struct vop_abortop_args *)))nullop) 460 #define fdesc_lock ((int (*) __P((struct vop_lock_args *)))nullop) 461 #define fdesc_unlock ((int (*) __P((struct vop_unlock_args *)))nullop) 462 #define fdesc_bmap ((int (*) __P((struct vop_bmap_args *)))fdesc_badop) 463 #define fdesc_strategy ((int (*) __P((struct vop_strategy_args *)))fdesc_badop) 464 #define fdesc_islocked ((int (*) __P((struct vop_islocked_args *)))nullop) 465 #define fdesc_advlock ((int (*) __P((struct vop_advlock_args *)))fdesc_enotsupp) 466 #define fdesc_blkatoff \ 467 ((int (*) __P((struct vop_blkatoff_args *)))fdesc_enotsupp) 468 #define fdesc_vget ((int (*) __P((struct vop_vget_args *)))fdesc_enotsupp) 469 #define fdesc_valloc ((int(*) __P(( \ 470 struct vnode *pvp, \ 471 int mode, \ 472 struct ucred *cred, \ 473 struct vnode **vpp))) fdesc_enotsupp) 474 #define fdesc_truncate \ 475 ((int (*) __P((struct vop_truncate_args *)))fdesc_enotsupp) 476 #define fdesc_update ((int (*) __P((struct vop_update_args *)))fdesc_enotsupp) 477 #define fdesc_bwrite ((int (*) __P((struct vop_bwrite_args *)))fdesc_enotsupp) 478 479 int (**fdesc_vnodeop_p)(); 480 struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = { 481 { &vop_default_desc, vn_default_error }, 482 { &vop_lookup_desc, fdesc_lookup }, /* lookup */ 483 { &vop_create_desc, fdesc_create }, /* create */ 484 { &vop_mknod_desc, fdesc_mknod }, /* mknod */ 485 { &vop_open_desc, fdesc_open }, /* open */ 486 { &vop_close_desc, fdesc_close }, /* close */ 487 { &vop_access_desc, fdesc_access }, /* access */ 488 { &vop_getattr_desc, fdesc_getattr }, /* getattr */ 489 { &vop_setattr_desc, fdesc_setattr }, /* setattr */ 490 { &vop_read_desc, fdesc_read }, /* read */ 491 { &vop_write_desc, fdesc_write }, /* write */ 492 { &vop_ioctl_desc, fdesc_ioctl }, /* ioctl */ 493 { &vop_select_desc, fdesc_select }, /* select */ 494 { &vop_mmap_desc, fdesc_mmap }, /* mmap */ 495 { &vop_fsync_desc, fdesc_fsync }, /* fsync */ 496 { &vop_seek_desc, fdesc_seek }, /* seek */ 497 { &vop_remove_desc, fdesc_remove }, /* remove */ 498 { &vop_link_desc, fdesc_link }, /* link */ 499 { &vop_rename_desc, fdesc_rename }, /* rename */ 500 { &vop_mkdir_desc, fdesc_mkdir }, /* mkdir */ 501 { &vop_rmdir_desc, fdesc_rmdir }, /* rmdir */ 502 { &vop_symlink_desc, fdesc_symlink }, /* symlink */ 503 { &vop_readdir_desc, fdesc_readdir }, /* readdir */ 504 { &vop_readlink_desc, fdesc_readlink }, /* readlink */ 505 { &vop_abortop_desc, fdesc_abortop }, /* abortop */ 506 { &vop_inactive_desc, fdesc_inactive }, /* inactive */ 507 { &vop_reclaim_desc, fdesc_reclaim }, /* reclaim */ 508 { &vop_lock_desc, fdesc_lock }, /* lock */ 509 { &vop_unlock_desc, fdesc_unlock }, /* unlock */ 510 { &vop_bmap_desc, fdesc_bmap }, /* bmap */ 511 { &vop_strategy_desc, fdesc_strategy }, /* strategy */ 512 { &vop_print_desc, fdesc_print }, /* print */ 513 { &vop_islocked_desc, fdesc_islocked }, /* islocked */ 514 { &vop_advlock_desc, fdesc_advlock }, /* advlock */ 515 { &vop_blkatoff_desc, fdesc_blkatoff }, /* blkatoff */ 516 { &vop_valloc_desc, fdesc_valloc }, /* valloc */ 517 { &vop_vfree_desc, fdesc_vfree }, /* vfree */ 518 { &vop_truncate_desc, fdesc_truncate }, /* truncate */ 519 { &vop_update_desc, fdesc_update }, /* update */ 520 { &vop_bwrite_desc, fdesc_bwrite }, /* bwrite */ 521 { (struct vnodeop_desc*)NULL, (int(*)())NULL } 522 }; 523 struct vnodeopv_desc fdesc_vnodeop_opv_desc = 524 { &fdesc_vnodeop_p, fdesc_vnodeop_entries }; 525