xref: /netbsd-src/sys/miscfs/fdesc/fdesc_vnops.c (revision 5f7096188587a2c7c95fa3c69b78e1ec9c7923d0)
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.6 1993/09/07 15:41:18 ws 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, cookies, ncookies)
306 	struct vnode *vp;
307 	struct uio *uio;
308 	struct ucred *cred;
309 	int *eofflagp;
310 	u_int *cookies;
311 	int ncookies;
312 {
313 	struct filedesc *fdp;
314 	int ind, i;
315 	int error;
316 
317 #define UIO_MX 16
318 
319 	fdp = uio->uio_procp->p_fd;
320 	ind = uio->uio_offset / UIO_MX;
321 	error = 0;
322 	while (uio->uio_resid > 0 && (!cookies || ncookies > 0)) {
323 		struct direct d;
324 		struct direct *dp = &d;
325 
326 	        if (ind < 2) { /* . or .. */
327 		  bzero((caddr_t) dp, UIO_MX);
328 		  if (ind == 0) {
329 		    strcpy(dp->d_name, ".");
330 		    dp->d_namlen = 1;
331 		  } else if (ind == 1) {
332 		    strcpy(dp->d_name, "..");
333 		    dp->d_namlen = 2;
334 		  } else
335 		    panic("fdesc: ind is negative!");
336 
337 		  dp->d_reclen = UIO_MX;
338 		  dp->d_ino = 2;
339 
340 		  /*
341 		   * And ship to userland
342 		   */
343 		  error = uiomove((caddr_t) dp, UIO_MX, uio);
344 		  if (error)
345 		    break;
346 
347 		  ind++;
348 		  if (cookies) {
349 			  *cookies++ = ind * UIO_MX;
350 			  ncookies--;
351 		  }
352 		  continue;
353 		}
354 	        i = ind - 2;
355 		if (i >= fdp->fd_nfiles) {
356 			*eofflagp = 1;
357 			break;
358 		}
359 		if (fdp->fd_ofiles[i] != NULL) {
360 			struct direct d;
361 			struct direct *dp = &d;
362 			char *cp = dp->d_name;
363 #ifdef FDESC_FILEID
364 			struct vattr va;
365 #endif
366 			int j;
367 
368 			bzero((caddr_t) dp, UIO_MX);
369 
370 			/*
371 			 * Generate an ASCII representation of the name.
372 			 * This can cope with fds in the range 0..99999
373 			 */
374 			cp++;
375 			if (i > 10) cp++;
376 			if (i > 100) cp++;
377 			if (i > 1000) cp++;
378 			if (i > 10000) cp++;
379 			if (i > 100000) panic("fdesc_readdir");
380 			dp->d_namlen = cp - dp->d_name;
381 			*cp = '\0';
382 			j = i;
383 			do {
384 				*--cp = j % 10 + '0';
385 				j /= 10;
386 			} while (j > 0);
387 			/*
388 			 * Fill in the remaining fields
389 			 */
390 			dp->d_reclen = UIO_MX;
391 			dp->d_ino = i + 3;
392 #ifdef FDESC_FILEID
393 			/*
394 			 * If we want the file ids to match the
395 			 * we must call getattr on the underlying file.
396 			 * fdesc_attr may return an error, in which case
397 			 * we ignore the returned file id.
398 			 */
399 			error = fdesc_attr(i, &va, cred, p);
400 			if (error == 0)
401 				dp->d_ino = va.va_fileid;
402 #endif
403 			/*
404 			 * And ship to userland
405 			 */
406 			error = uiomove((caddr_t) dp, UIO_MX, uio);
407 			if (error)
408 				break;
409 			if (cookies) {
410 				*cookies++ = (ind + 1) * UIO_MX;
411 				ncookies--;
412 			}
413 		}
414 		ind++;
415 	}
416 
417 	uio->uio_offset = ind * UIO_MX;
418 	return (error);
419 }
420 
421 fdesc_inactive(vp, p)
422 	struct vnode *vp;
423 	struct proc *p;
424 {
425 	/*
426 	 * Clear out the v_type field to avoid
427 	 * nasty things happening in vgone().
428 	 */
429 	vp->v_type = VNON;
430 #ifdef FDESC_DIAGNOSTIC
431 	printf("fdesc_inactive(%x)\n", vp);
432 #endif
433 	return (0);
434 }
435 
436 /*
437  * Print out the contents of a /dev/fd vnode.
438  */
439 /* ARGSUSED */
440 void
441 fdesc_print(vp)
442 	struct vnode *vp;
443 {
444 	printf("tag VT_FDESC, fdesc vnode\n");
445 }
446 
447 /*
448  * /dev/fd vnode unsupported operation
449  */
450 fdesc_enotsupp()
451 {
452 	return (EOPNOTSUPP);
453 }
454 
455 /*
456  * /dev/fd "should never get here" operation
457  */
458 fdesc_badop()
459 {
460 	panic("fdesc: bad op");
461 	/* NOTREACHED */
462 }
463 
464 /*
465  * /dev/fd vnode null operation
466  */
467 fdesc_nullop()
468 {
469 	return (0);
470 }
471 
472 #define fdesc_create ((int (*) __P(( \
473 		struct nameidata *ndp, \
474 		struct vattr *vap, \
475 		struct proc *p))) fdesc_enotsupp)
476 #define fdesc_mknod ((int (*) __P(( \
477 		struct nameidata *ndp, \
478 		struct vattr *vap, \
479 		struct ucred *cred, \
480 		struct proc *p))) fdesc_enotsupp)
481 #define fdesc_close ((int (*) __P(( \
482 		struct vnode *vp, \
483 		int fflag, \
484 		struct ucred *cred, \
485 		struct proc *p))) nullop)
486 #define fdesc_access ((int (*) __P(( \
487 		struct vnode *vp, \
488 		int mode, \
489 		struct ucred *cred, \
490 		struct proc *p))) nullop)
491 #define	fdesc_read ((int (*) __P(( \
492 		struct vnode *vp, \
493 		struct uio *uio, \
494 		int ioflag, \
495 		struct ucred *cred))) fdesc_enotsupp)
496 #define	fdesc_write ((int (*) __P(( \
497 		struct vnode *vp, \
498 		struct uio *uio, \
499 		int ioflag, \
500 		struct ucred *cred))) fdesc_enotsupp)
501 #define	fdesc_ioctl ((int (*) __P(( \
502 		struct vnode *vp, \
503 		int command, \
504 		caddr_t data, \
505 		int fflag, \
506 		struct ucred *cred, \
507 		struct proc *p))) fdesc_enotsupp)
508 #define	fdesc_select ((int (*) __P(( \
509 		struct vnode *vp, \
510 		int which, \
511 		int fflags, \
512 		struct ucred *cred, \
513 		struct proc *p))) fdesc_enotsupp)
514 #define fdesc_mmap ((int (*) __P(( \
515 		struct vnode *vp, \
516 		int fflags, \
517 		struct ucred *cred, \
518 		struct proc *p))) fdesc_enotsupp)
519 #define fdesc_fsync ((int (*) __P(( \
520 		struct vnode *vp, \
521 		int fflags, \
522 		struct ucred *cred, \
523 		int waitfor, \
524 		struct proc *p))) nullop)
525 #define fdesc_seek ((int (*) __P(( \
526 		struct vnode *vp, \
527 		off_t oldoff, \
528 		off_t newoff, \
529 		struct ucred *cred))) nullop)
530 #define fdesc_remove ((int (*) __P(( \
531 		struct nameidata *ndp, \
532 		struct proc *p))) fdesc_enotsupp)
533 #define fdesc_link ((int (*) __P(( \
534 		struct vnode *vp, \
535 		struct nameidata *ndp, \
536 		struct proc *p))) fdesc_enotsupp)
537 #define fdesc_rename ((int (*) __P(( \
538 		struct nameidata *fndp, \
539 		struct nameidata *tdnp, \
540 		struct proc *p))) fdesc_enotsupp)
541 #define fdesc_mkdir ((int (*) __P(( \
542 		struct nameidata *ndp, \
543 		struct vattr *vap, \
544 		struct proc *p))) fdesc_enotsupp)
545 #define fdesc_rmdir ((int (*) __P(( \
546 		struct nameidata *ndp, \
547 		struct proc *p))) fdesc_enotsupp)
548 #define fdesc_symlink ((int (*) __P(( \
549 		struct nameidata *ndp, \
550 		struct vattr *vap, \
551 		char *target, \
552 		struct proc *p))) fdesc_enotsupp)
553 #define fdesc_readlink ((int (*) __P(( \
554 		struct vnode *vp, \
555 		struct uio *uio, \
556 		struct ucred *cred))) fdesc_enotsupp)
557 #define fdesc_abortop ((int (*) __P(( \
558 		struct nameidata *ndp))) nullop)
559 #ifdef FDESC_DIAGNOSTIC
560 int fdesc_reclaim(vp)
561 struct vnode *vp;
562 {
563 	printf("fdesc_reclaim(%x)\n", vp);
564 	return (0);
565 }
566 #else
567 #define fdesc_reclaim ((int (*) __P(( \
568 		struct vnode *vp))) nullop)
569 #endif
570 #define	fdesc_lock ((int (*) __P(( \
571 		struct vnode *vp))) nullop)
572 #define fdesc_unlock ((int (*) __P(( \
573 		struct vnode *vp))) nullop)
574 #define	fdesc_bmap ((int (*) __P(( \
575 		struct vnode *vp, \
576 		daddr_t bn, \
577 		struct vnode **vpp, \
578 		daddr_t *bnp))) fdesc_badop)
579 #define	fdesc_strategy ((int (*) __P(( \
580 		struct buf *bp))) fdesc_badop)
581 #define fdesc_islocked ((int (*) __P(( \
582 		struct vnode *vp))) nullop)
583 #define fdesc_advlock ((int (*) __P(( \
584 		struct vnode *vp, \
585 		caddr_t id, \
586 		int op, \
587 		struct flock *fl, \
588 		int flags))) fdesc_enotsupp)
589 
590 struct vnodeops fdesc_vnodeops = {
591 	fdesc_lookup,	/* lookup */
592 	fdesc_create,	/* create */
593 	fdesc_mknod,	/* mknod */
594 	fdesc_open,	/* open */
595 	fdesc_close,	/* close */
596 	fdesc_access,	/* access */
597 	fdesc_getattr,	/* getattr */
598 	fdesc_setattr,	/* setattr */
599 	fdesc_read,	/* read */
600 	fdesc_write,	/* write */
601 	fdesc_ioctl,	/* ioctl */
602 	fdesc_select,	/* select */
603 	fdesc_mmap,	/* mmap */
604 	fdesc_fsync,	/* fsync */
605 	fdesc_seek,	/* seek */
606 	fdesc_remove,	/* remove */
607 	fdesc_link,	/* link */
608 	fdesc_rename,	/* rename */
609 	fdesc_mkdir,	/* mkdir */
610 	fdesc_rmdir,	/* rmdir */
611 	fdesc_symlink,	/* symlink */
612 	fdesc_readdir,	/* readdir */
613 	fdesc_readlink,	/* readlink */
614 	fdesc_abortop,	/* abortop */
615 	fdesc_inactive,	/* inactive */
616 	fdesc_reclaim,	/* reclaim */
617 	fdesc_lock,	/* lock */
618 	fdesc_unlock,	/* unlock */
619 	fdesc_bmap,	/* bmap */
620 	fdesc_strategy,	/* strategy */
621 	fdesc_print,	/* print */
622 	fdesc_islocked,	/* islocked */
623 	fdesc_advlock,	/* advlock */
624 };
625