xref: /original-bsd/sys/miscfs/fdesc/fdesc_vnops.c (revision d75a44f9)
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.2 (Berkeley) 07/13/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 <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 = EOPNOTSUPP;
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