xref: /netbsd-src/sys/miscfs/fdesc/fdesc_vnops.c (revision cda4f8f6ee55684e8d311b86c99ea59191e6b74f)
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