1/* $NetBSD: ptyfs_subr.c,v 1.33 2014/10/15 15:00:03 christos Exp $ */
2
3/*
4 * Copyright (c) 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Jan-Simon Pendry.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
21 *
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
32 * SUCH DAMAGE.
33 *
34 * @(#)ptyfs_subr.c 8.6 (Berkeley) 5/14/95
35 */
36
37/*
38 * Copyright (c) 1994 Christopher G. Demetriou. All rights reserved.
39 * Copyright (c) 1993 Jan-Simon Pendry
40 *
41 * This code is derived from software contributed to Berkeley by
42 * Jan-Simon Pendry.
43 *
44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions
46 * are met:
47 * 1. Redistributions of source code must retain the above copyright
48 * notice, this list of conditions and the following disclaimer.
49 * 2. Redistributions in binary form must reproduce the above copyright
50 * notice, this list of conditions and the following disclaimer in the
51 * documentation and/or other materials provided with the distribution.
52 * 3. All advertising materials mentioning features or use of this software
53 * must display the following acknowledgement:
54 * This product includes software developed by the University of
55 * California, Berkeley and its contributors.
56 * 4. Neither the name of the University nor the names of its contributors
57 * may be used to endorse or promote products derived from this software
58 * without specific prior written permission.
59 *
60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70 * SUCH DAMAGE.
71 *
72 * @(#)procfs_subr.c 8.6 (Berkeley) 5/14/95
73 */
74
75#include <sys/cdefs.h>
76__KERNEL_RCSID(0, "$NetBSD: ptyfs_subr.c,v 1.33 2014/10/15 15:00:03 christos Exp $");
77
78#include <sys/param.h>
79#include <sys/systm.h>
80#include <sys/time.h>
81#include <sys/kernel.h>
82#include <sys/vnode.h>
83#include <sys/stat.h>
84#include <sys/malloc.h>
85#include <sys/file.h>
86#include <sys/namei.h>
87#include <sys/filedesc.h>
88#include <sys/select.h>
89#include <sys/tty.h>
90#include <sys/pty.h>
91#include <sys/kauth.h>
92#include <sys/lwp.h>
93
94#include <fs/ptyfs/ptyfs.h>
95
96static kmutex_t ptyfs_hashlock;
97
98static SLIST_HEAD(ptyfs_hashhead, ptyfsnode) *ptyfs_node_tbl;
99static u_long ptyfs_node_mask; /* size of hash table - 1 */
100
101/*
102 * allocate a ptyfsnode/vnode pair. the vnode is referenced.
103 *
104 * the pty, ptyfs_type, and mount point uniquely
105 * identify a ptyfsnode. the mount point is needed
106 * because someone might mount this filesystem
107 * twice.
108 */
109int
110ptyfs_allocvp(struct mount *mp, struct vnode **vpp, ptyfstype type, int pty)
111{
112 struct ptyfskey key;
113
114 memset(&key, 0, sizeof(key));
115 key.ptk_pty = pty;
116 key.ptk_type = type;
117 return vcache_get(mp, &key, sizeof(key), vpp);
118}
119
120/*
121 * Initialize ptyfsnode hash table.
122 */
123void
124ptyfs_hashinit(void)
125{
126
127 ptyfs_node_tbl = hashinit(16, HASH_SLIST, true, &ptyfs_node_mask);
128 mutex_init(&ptyfs_hashlock, MUTEX_DEFAULT, IPL_NONE);
129}
130
131/*
132 * Free ptyfsnode hash table.
133 */
134void
135ptyfs_hashdone(void)
136{
137
138 mutex_destroy(&ptyfs_hashlock);
139 hashdone(ptyfs_node_tbl, HASH_SLIST, ptyfs_node_mask);
140}
141
142/*
143 * Get a ptyfsnode from the hash table, or allocate one.
144 */
145struct ptyfsnode *
146ptyfs_get_node(ptyfstype type, int pty)
147{
148 struct ptyfs_hashhead *ppp;
149 struct ptyfsnode *pp;
150
151 ppp = &ptyfs_node_tbl[PTYFS_FILENO(type, pty) & ptyfs_node_mask];
152
153 mutex_enter(&ptyfs_hashlock);
154 SLIST_FOREACH(pp, ppp, ptyfs_hash) {
155 if (pty == pp->ptyfs_pty && pp->ptyfs_type == type) {
156 mutex_exit(&ptyfs_hashlock);
157 return pp;
158 }
159 }
160 mutex_exit(&ptyfs_hashlock);
161
162 pp = malloc(sizeof(struct ptyfsnode), M_TEMP, M_WAITOK);
163 pp->ptyfs_pty = pty;
164 pp->ptyfs_type = type;
165 pp->ptyfs_fileno = PTYFS_FILENO(pty, type);
166 if (pp->ptyfs_type == PTYFSroot)
167 pp->ptyfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|
168 S_IROTH|S_IXOTH;
169 else
170 pp->ptyfs_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|
171 S_IROTH|S_IWOTH;
172
173 pp->ptyfs_uid = pp->ptyfs_gid = 0;
174 pp->ptyfs_status = PTYFS_CHANGE;
175 PTYFS_ITIMES(pp, NULL, NULL, NULL);
176 pp->ptyfs_birthtime = pp->ptyfs_mtime =
177 pp->ptyfs_atime = pp->ptyfs_ctime;
178 pp->ptyfs_flags = 0;
179 mutex_enter(&ptyfs_hashlock);
180 /*
181 * XXX We have minimum race condition when opening master side
182 * first time, if other threads through other mount points, trying
183 * opening the same device. As follow we have little chance have
184 * unused list entries.
185 */
186 SLIST_INSERT_HEAD(ppp, pp, ptyfs_hash);
187 mutex_exit(&ptyfs_hashlock);
188 return pp;
189}
190
191/*
192 * Mark this controlling pty as active.
193 */
194void
195ptyfs_set_active(struct mount *mp, int pty)
196{
197 struct ptyfsmount *pmnt = VFSTOPTY(mp);
198
199 KASSERT(pty >= 0);
200 /* Reallocate map if needed. */
201 if (pty >= pmnt->pmnt_bitmap_size * NBBY) {
202 int osize, nsize;
203 uint8_t *obitmap, *nbitmap;
204
205 nsize = roundup(howmany(pty + 1, NBBY), 64);
206 nbitmap = kmem_alloc(nsize, KM_SLEEP);
207 mutex_enter(&pmnt->pmnt_lock);
208 if (pty < pmnt->pmnt_bitmap_size * NBBY) {
209 mutex_exit(&pmnt->pmnt_lock);
210 kmem_free(nbitmap, nsize);
211 } else {
212 osize = pmnt->pmnt_bitmap_size;
213 obitmap = pmnt->pmnt_bitmap;
214 pmnt->pmnt_bitmap_size = nsize;
215 pmnt->pmnt_bitmap = nbitmap;
216 if (osize > 0)
217 memcpy(pmnt->pmnt_bitmap, obitmap, osize);
218 memset(pmnt->pmnt_bitmap + osize, 0, nsize - osize);
219 mutex_exit(&pmnt->pmnt_lock);
220 if (osize > 0)
221 kmem_free(obitmap, osize);
222 }
223 }
224
225 mutex_enter(&pmnt->pmnt_lock);
226 setbit(pmnt->pmnt_bitmap, pty);
227 mutex_exit(&pmnt->pmnt_lock);
228}
229
230/*
231 * Mark this controlling pty as inactive.
232 */
233void
234ptyfs_clr_active(struct mount *mp, int pty)
235{
236 struct ptyfsmount *pmnt = VFSTOPTY(mp);
237
238 KASSERT(pty >= 0);
239 mutex_enter(&pmnt->pmnt_lock);
240 if (pty >= 0 && pty < pmnt->pmnt_bitmap_size * NBBY)
241 clrbit(pmnt->pmnt_bitmap, pty);
242 mutex_exit(&pmnt->pmnt_lock);
243}
244
245/*
246 * Lookup the next active controlling pty greater or equal "pty".
247 * Return -1 if not found.
248 */
249int
250ptyfs_next_active(struct mount *mp, int pty)
251{
252 struct ptyfsmount *pmnt = VFSTOPTY(mp);
253
254 KASSERT(pty >= 0);
255 mutex_enter(&pmnt->pmnt_lock);
256 while (pty < pmnt->pmnt_bitmap_size * NBBY) {
257 if (isset(pmnt->pmnt_bitmap, pty)) {
258 mutex_exit(&pmnt->pmnt_lock);
259 return pty;
260 }
261 pty++;
262 }
263 mutex_exit(&pmnt->pmnt_lock);
264 return -1;
265}
266