1 /* $NetBSD: ptyfs_vfsops.c,v 1.41 2009/11/30 10:59:19 pooka Exp $ */
4 * Copyright (c) 1992, 1993, 1995
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software donated to Berkeley by
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * Pseudo-tty Filesystem
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: ptyfs_vfsops.c,v 1.41 2009/11/30 10:59:19 pooka Exp $");
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/sysctl.h>
48 #include <sys/vnode.h>
49 #include <sys/mount.h>
50 #include <sys/namei.h>
52 #include <sys/dirent.h>
53 #include <sys/malloc.h>
54 #include <sys/syslog.h>
55 #include <sys/select.h>
56 #include <sys/filedesc.h>
59 #include <sys/kauth.h>
60 #include <sys/module.h>
62 #include <fs/ptyfs/ptyfs.h>
63 #include <miscfs/genfs/genfs.h>
64 #include <miscfs/specfs/specdev.h>
66 MODULE(MODULE_CLASS_VFS
, ptyfs
, NULL
);
68 MALLOC_JUSTDEFINE(M_PTYFSMNT
, "ptyfs mount", "ptyfs mount structures");
69 MALLOC_JUSTDEFINE(M_PTYFSTMP
, "ptyfs temp", "ptyfs temporary structures");
73 static struct sysctllog
*ptyfs_sysctl_log
;
75 static int ptyfs__allocvp(struct ptm_pty
*, struct lwp
*, struct vnode
**,
77 static int ptyfs__makename(struct ptm_pty
*, struct lwp
*, char *, size_t,
79 static void ptyfs__getvattr(struct ptm_pty
*, struct lwp
*, struct vattr
*);
82 * ptm glue: When we mount, we make ptm point to us.
84 struct ptm_pty
*ptyfs_save_ptm
;
85 static int ptyfs_count
;
87 struct ptm_pty ptm_ptyfspty
= {
95 ptyfs__getpath(struct lwp
*l
, const struct mount
*mp
)
97 #define MAXBUF (sizeof(mp->mnt_stat.f_mntonname) + 32)
98 struct cwdinfo
*cwdi
= l
->l_proc
->p_cwdi
;
104 struct ptyfsmount
*pmnt
= mp
->mnt_data
;
106 rv
= mp
->mnt_stat
.f_mntonname
;
107 if (cwdi
->cwdi_rdir
== NULL
||
108 (pmnt
->pmnt_flags
& PTYFSMNT_CHROOT
) == 0)
111 buf
= malloc(MAXBUF
, M_TEMP
, M_WAITOK
);
114 error
= getcwd_common(cwdi
->cwdi_rdir
, rootvnode
, &bp
,
115 buf
, MAXBUF
/ 2, 0, l
);
120 if (len
< sizeof(mp
->mnt_stat
.f_mntonname
)) /* XXX */
128 ptyfs__makename(struct ptm_pty
*pt
, struct lwp
*l
, char *tbuf
, size_t bufsiz
,
131 struct mount
*mp
= pt
->arg
;
136 /* We don't provide access to the master, should we? */
137 len
= snprintf(tbuf
, bufsiz
, "/dev/null");
140 len
= snprintf(tbuf
, bufsiz
, "%s/%llu", ptyfs__getpath(l
, mp
),
141 (unsigned long long)minor(dev
));
147 return len
>= bufsiz
? ENOSPC
: 0;
153 ptyfs__allocvp(struct ptm_pty
*pt
, struct lwp
*l
, struct vnode
**vpp
,
156 struct mount
*mp
= pt
->arg
;
170 return ptyfs_allocvp(mp
, vpp
, type
, minor(dev
), l
);
175 ptyfs__getvattr(struct ptm_pty
*pt
, struct lwp
*l
, struct vattr
*vattr
)
177 struct mount
*mp
= pt
->arg
;
178 struct ptyfsmount
*pmnt
= VFSTOPTY(mp
);
181 vattr
->va_uid
= kauth_cred_getuid(l
->l_cred
);
182 vattr
->va_gid
= pmnt
->pmnt_gid
;
183 vattr
->va_mode
= pmnt
->pmnt_mode
;
191 malloc_type_attach(M_PTYFSMNT
);
192 malloc_type_attach(M_PTYFSTMP
);
207 malloc_type_detach(M_PTYFSTMP
);
208 malloc_type_detach(M_PTYFSMNT
);
211 #define OSIZE sizeof(struct { int f; gid_t g; mode_t m; })
213 * Mount the Pseudo tty params filesystem
216 ptyfs_mount(struct mount
*mp
, const char *path
, void *data
, size_t *data_len
)
218 struct lwp
*l
= curlwp
;
220 struct ptyfsmount
*pmnt
;
221 struct ptyfs_args
*args
= data
;
223 if (*data_len
!= sizeof *args
&& *data_len
!= OSIZE
)
226 if (UIO_MX
& (UIO_MX
- 1)) {
227 log(LOG_ERR
, "ptyfs: invalid directory entry size");
231 if (mp
->mnt_flag
& MNT_GETARGS
) {
235 args
->mode
= pmnt
->pmnt_mode
;
236 args
->gid
= pmnt
->pmnt_gid
;
237 if (args
->version
>= PTYFS_ARGSVERSION
) {
238 args
->flags
= pmnt
->pmnt_flags
;
239 *data_len
= sizeof *args
;
246 /* Don't allow more than one mount */
250 if (mp
->mnt_flag
& MNT_UPDATE
)
253 if (args
->version
> PTYFS_ARGSVERSION
)
256 pmnt
= malloc(sizeof(struct ptyfsmount
), M_PTYFSMNT
, M_WAITOK
);
259 pmnt
->pmnt_gid
= args
->gid
;
260 pmnt
->pmnt_mode
= args
->mode
;
261 if (args
->version
>= PTYFS_ARGSVERSION
)
262 pmnt
->pmnt_flags
= args
->flags
;
264 pmnt
->pmnt_flags
= 0;
265 mp
->mnt_flag
|= MNT_LOCAL
;
268 if ((error
= set_statvfs_info(path
, UIO_USERSPACE
, "ptyfs",
269 UIO_SYSSPACE
, mp
->mnt_op
->vfs_name
, mp
, l
)) != 0) {
270 free(pmnt
, M_PTYFSMNT
);
274 /* Point pty access to us */
276 ptm_ptyfspty
.arg
= mp
;
277 ptyfs_save_ptm
= pty_sethandler(&ptm_ptyfspty
);
284 ptyfs_start(struct mount
*mp
, int flags
)
291 ptyfs_unmount(struct mount
*mp
, int mntflags
)
296 if (mntflags
& MNT_FORCE
)
299 if ((error
= vflush(mp
, 0, flags
)) != 0)
302 /* Restore where pty access was pointing */
303 (void)pty_sethandler(ptyfs_save_ptm
);
304 ptyfs_save_ptm
= NULL
;
305 ptm_ptyfspty
.arg
= NULL
;
308 * Finally, throw away the ptyfsmount structure
310 free(mp
->mnt_data
, M_PTYFSMNT
);
318 ptyfs_root(struct mount
*mp
, struct vnode
**vpp
)
321 return ptyfs_allocvp(mp
, vpp
, PTYFSroot
, 0, NULL
);
326 ptyfs_sync(struct mount
*mp
, int waitfor
,
333 * Kernfs flat namespace lookup.
334 * Currently unsupported.
338 ptyfs_vget(struct mount
*mp
, ino_t ino
,
344 extern const struct vnodeopv_desc ptyfs_vnodeop_opv_desc
;
346 const struct vnodeopv_desc
* const ptyfs_vnodeopv_descs
[] = {
347 &ptyfs_vnodeop_opv_desc
,
351 struct vfsops ptyfs_vfsops
= {
353 sizeof (struct ptyfs_args
),
358 (void *)eopnotsupp
, /* vfs_quotactl */
362 (void *)eopnotsupp
, /* vfs_fhtovp */
363 (void *)eopnotsupp
, /* vfs_vptofp */
367 NULL
, /* vfs_mountroot */
370 (void *)eopnotsupp
, /* vfs_suspendctl */
371 genfs_renamelock_enter
,
372 genfs_renamelock_exit
,
374 ptyfs_vnodeopv_descs
,
380 ptyfs_modcmd(modcmd_t cmd
, void *arg
)
385 case MODULE_CMD_INIT
:
386 error
= vfs_attach(&ptyfs_vfsops
);
389 sysctl_createv(&ptyfs_sysctl_log
, 0, NULL
, NULL
,
391 CTLTYPE_NODE
, "vfs", NULL
,
394 sysctl_createv(&ptyfs_sysctl_log
, 0, NULL
, NULL
,
396 CTLTYPE_NODE
, "ptyfs",
397 SYSCTL_DESCR("Pty file system"),
399 CTL_VFS
, 23, CTL_EOL
);
401 * XXX the "23" above could be dynamic, thereby eliminating
402 * one more instance of the "number to vfs" mapping problem,
403 * but "23" is the order as taken from sys/mount.h
406 case MODULE_CMD_FINI
:
407 error
= vfs_detach(&ptyfs_vfsops
);
410 sysctl_teardown(&ptyfs_sysctl_log
);