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