Annotation of src/sys/kern/tty_ptm.c, Revision 1.11.4.2
1.11.4.2! ad 1: /* $NetBSD: tty_ptm.c,v 1.16 2006/12/27 18:45:30 alc Exp $ */
1.1 christos 2:
3: /*-
4: * Copyright (c) 2004 The NetBSD Foundation, Inc.
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by the NetBSD
18: * Foundation, Inc. and its contributors.
19: * 4. Neither the name of The NetBSD Foundation nor the names of its
20: * contributors may be used to endorse or promote products derived
21: * from this software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
24: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
27: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33: * POSSIBILITY OF SUCH DAMAGE.
34: */
35:
36: #include <sys/cdefs.h>
1.11.4.2! ad 37: __KERNEL_RCSID(0, "$NetBSD: tty_ptm.c,v 1.16 2006/12/27 18:45:30 alc Exp $");
1.1 christos 38:
39: #include "opt_ptm.h"
40:
41: /* pty multiplexor driver /dev/ptm{,x} */
42:
43: #include <sys/param.h>
44: #include <sys/systm.h>
45: #include <sys/ioctl.h>
46: #include <sys/proc.h>
47: #include <sys/tty.h>
48: #include <sys/stat.h>
49: #include <sys/file.h>
50: #include <sys/uio.h>
51: #include <sys/kernel.h>
52: #include <sys/vnode.h>
53: #include <sys/namei.h>
54: #include <sys/signalvar.h>
55: #include <sys/uio.h>
56: #include <sys/filedesc.h>
57: #include <sys/conf.h>
58: #include <sys/poll.h>
59: #include <sys/malloc.h>
60: #include <sys/pty.h>
1.9 elad 61: #include <sys/kauth.h>
1.1 christos 62:
63: #ifdef DEBUG_PTM
64: #define DPRINTF(a) printf a
65: #else
66: #define DPRINTF(a)
67: #endif
68:
69: #ifdef NO_DEV_PTM
70: const struct cdevsw ptm_cdevsw = {
71: noopen, noclose, noread, nowrite, noioctl,
72: nostop, notty, nopoll, nommap, nokqfilter, D_TTY
73: };
74: #else
75:
76: static struct ptm_pty *ptm;
77: int pts_major, ptc_major;
78:
79: static dev_t pty_getfree(void);
1.7 christos 80: static int pty_alloc_master(struct lwp *, int *, dev_t *);
81: static int pty_alloc_slave(struct lwp *, int *, dev_t);
1.1 christos 82:
83: void ptmattach(int);
84:
85: dev_t
86: pty_makedev(char ms, int minor)
87: {
88: return makedev(ms == 't' ? pts_major : ptc_major, minor);
89: }
90:
1.5 thorpej 91:
1.1 christos 92: static dev_t
93: pty_getfree(void)
94: {
95: extern struct simplelock pt_softc_mutex;
96: int i;
97:
98: simple_lock(&pt_softc_mutex);
99: for (i = 0; i < npty; i++) {
100: if (pty_isfree(i, 0))
101: break;
102: }
103: simple_unlock(&pt_softc_mutex);
104: return pty_makedev('t', i);
105: }
106:
107: /*
108: * Hacked up version of vn_open. We _only_ handle ptys and only open
109: * them with FREAD|FWRITE and never deal with creat or stuff like that.
110: *
111: * We need it because we have to fake up root credentials to open the pty.
112: */
113: int
1.7 christos 114: pty_vn_open(struct vnode *vp, struct lwp *l)
1.1 christos 115: {
116: int error;
117:
118: if (vp->v_type != VCHR) {
119: vput(vp);
120: return EINVAL;
121: }
122:
1.11 ad 123: error = VOP_OPEN(vp, FREAD|FWRITE, lwp0.l_cred, l);
1.1 christos 124:
125: if (error) {
126: vput(vp);
127: return error;
128: }
129:
130: vp->v_writecount++;
131:
132: return 0;
133: }
134:
135: static int
1.7 christos 136: pty_alloc_master(struct lwp *l, int *fd, dev_t *dev)
1.1 christos 137: {
138: int error;
139: struct file *fp;
140: struct vnode *vp;
141: int md;
142:
1.11 ad 143: if ((error = falloc(l, &fp, fd)) != 0) {
1.1 christos 144: DPRINTF(("falloc %d\n", error));
145: return error;
146: }
147: retry:
148: /* Find and open a free master pty. */
149: *dev = pty_getfree();
150: md = minor(*dev);
151: if ((error = pty_check(md)) != 0) {
152: DPRINTF(("pty_check %d\n", error));
153: goto bad;
154: }
155: if (ptm == NULL) {
1.11.4.1 ad 156: DPRINTF(("no ptm\n"));
1.1 christos 157: error = EOPNOTSUPP;
158: goto bad;
159: }
1.11.4.1 ad 160: if ((error = (*ptm->allocvp)(ptm, l, &vp, *dev, 'p')) != 0) {
161: DPRINTF(("pty_allocvp %d\n", error));
1.1 christos 162: goto bad;
1.11.4.1 ad 163: }
1.1 christos 164:
1.7 christos 165: if ((error = pty_vn_open(vp, l)) != 0) {
1.11.4.1 ad 166: DPRINTF(("pty_vn_open %d\n", error));
1.1 christos 167: /*
168: * Check if the master open failed because we lost
169: * the race to grab it.
170: */
171: if (error != EIO)
172: goto bad;
173: error = !pty_isfree(md, 1);
1.11.4.1 ad 174: DPRINTF(("pty_isfree %d\n", error));
1.1 christos 175: if (error)
176: goto retry;
177: else
178: goto bad;
179: }
180: fp->f_flag = FREAD|FWRITE;
181: fp->f_type = DTYPE_VNODE;
182: fp->f_ops = &vnops;
183: fp->f_data = vp;
184: VOP_UNLOCK(vp, 0);
185: FILE_SET_MATURE(fp);
1.7 christos 186: FILE_UNUSE(fp, l);
1.1 christos 187: return 0;
188: bad:
1.7 christos 189: FILE_UNUSE(fp, l);
1.11 ad 190: fdremove(l->l_proc->p_fd, *fd);
1.1 christos 191: ffree(fp);
192: return error;
193: }
194:
195: int
1.7 christos 196: pty_grant_slave(struct lwp *l, dev_t dev)
1.1 christos 197: {
198: int error;
199: struct vnode *vp;
200:
201: /*
202: * Open the slave.
203: * namei -> setattr -> unlock -> revoke -> vrele ->
204: * namei -> open -> unlock
205: * Three stage rocket:
206: * 1. Change the owner and permissions on the slave.
207: * 2. Revoke all the users of the slave.
208: * 3. open the slave.
209: */
210: if (ptm == NULL)
211: return EOPNOTSUPP;
1.7 christos 212: if ((error = (*ptm->allocvp)(ptm, l, &vp, dev, 't')) != 0)
1.1 christos 213: return error;
214:
215: if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
216: struct vattr vattr;
1.11 ad 217: (*ptm->getvattr)(ptm, l, &vattr);
1.10 ad 218: /* Do the VOP_SETATTR() as root. */
1.11 ad 219: error = VOP_SETATTR(vp, &vattr, lwp0.l_cred, l);
1.1 christos 220: if (error) {
221: DPRINTF(("setattr %d\n", error));
222: VOP_UNLOCK(vp, 0);
223: vrele(vp);
224: return error;
225: }
226: }
227: VOP_UNLOCK(vp, 0);
228: if (vp->v_usecount > 1 ||
229: (vp->v_flag & (VALIASED | VLAYER)))
230: VOP_REVOKE(vp, REVOKEALL);
231:
232: /*
233: * The vnode is useless after the revoke, we need to get it again.
234: */
235: vrele(vp);
236: return 0;
237: }
238:
239: static int
1.7 christos 240: pty_alloc_slave(struct lwp *l, int *fd, dev_t dev)
1.1 christos 241: {
242: int error;
243: struct file *fp;
244: struct vnode *vp;
245:
246: /* Grab a filedescriptor for the slave */
1.11 ad 247: if ((error = falloc(l, &fp, fd)) != 0) {
1.1 christos 248: DPRINTF(("falloc %d\n", error));
249: return error;
250: }
251:
252: if (ptm == NULL) {
253: error = EOPNOTSUPP;
254: goto bad;
255: }
256:
1.7 christos 257: if ((error = (*ptm->allocvp)(ptm, l, &vp, dev, 't')) != 0)
1.1 christos 258: goto bad;
1.7 christos 259: if ((error = pty_vn_open(vp, l)) != 0)
1.1 christos 260: goto bad;
261:
262: fp->f_flag = FREAD|FWRITE;
263: fp->f_type = DTYPE_VNODE;
264: fp->f_ops = &vnops;
265: fp->f_data = vp;
266: VOP_UNLOCK(vp, 0);
267: FILE_SET_MATURE(fp);
1.7 christos 268: FILE_UNUSE(fp, l);
1.1 christos 269: return 0;
270: bad:
1.7 christos 271: FILE_UNUSE(fp, l);
1.11 ad 272: fdremove(l->l_proc->p_fd, *fd);
1.1 christos 273: ffree(fp);
274: return error;
275: }
276:
277: struct ptm_pty *
278: pty_sethandler(struct ptm_pty *nptm)
279: {
280: struct ptm_pty *optm = ptm;
281: ptm = nptm;
282: return optm;
283: }
284:
285: int
1.8 christos 286: pty_fill_ptmget(struct lwp *l, dev_t dev, int cfd, int sfd, void *data)
1.1 christos 287: {
288: struct ptmget *ptmg = data;
289: int error;
290:
291: if (ptm == NULL)
292: return EOPNOTSUPP;
293:
1.2 christos 294: ptmg->cfd = cfd == -1 ? minor(dev) : cfd;
295: ptmg->sfd = sfd == -1 ? minor(dev) : sfd;
1.1 christos 296:
1.8 christos 297: error = (*ptm->makename)(ptm, l, ptmg->cn, sizeof(ptmg->cn), dev, 'p');
1.1 christos 298: if (error)
299: return error;
300:
1.8 christos 301: return (*ptm->makename)(ptm, l, ptmg->sn, sizeof(ptmg->sn), dev, 't');
1.1 christos 302: }
303:
304: void
305: /*ARGSUSED*/
306: ptmattach(int n)
307: {
308: extern const struct cdevsw pts_cdevsw, ptc_cdevsw;
309: /* find the major and minor of the pty devices */
310: if ((pts_major = cdevsw_lookup_major(&pts_cdevsw)) == -1)
311: panic("ptmattach: Can't find pty slave in cdevsw");
312: if ((ptc_major = cdevsw_lookup_major(&ptc_cdevsw)) == -1)
313: panic("ptmattach: Can't find pty master in cdevsw");
314: #ifdef COMPAT_BSDPTY
315: ptm = &ptm_bsdpty;
316: #endif
317: }
318:
1.5 thorpej 319: static int
1.1 christos 320: /*ARGSUSED*/
1.7 christos 321: ptmopen(dev_t dev, int flag, int mode, struct lwp *l)
1.1 christos 322: {
323: int error;
324: int fd;
1.11.4.1 ad 325: dev_t ttydev;
1.1 christos 326:
327: switch(minor(dev)) {
328: case 0: /* /dev/ptmx */
1.11.4.1 ad 329: case 2: /* /emul/linux/dev/ptmx */
330: if ((error = pty_alloc_master(l, &fd, &ttydev)) != 0)
1.1 christos 331: return error;
1.11.4.1 ad 332: if (minor(dev) == 2) {
333: /*
334: * Linux ptyfs grants the pty right here.
335: * Handle this case here, instead of writing
336: * a new linux module.
337: */
338: if ((error = pty_grant_slave(l, ttydev)) != 0) {
339: struct file *fp =
340: fd_getfile(l->l_proc->p_fd, fd);
1.11.4.2! ad 341: if (fp != NULL) {
! 342: FILE_UNUSE(fp, l);
! 343: fdremove(l->l_proc->p_fd, fd);
! 344: ffree(fp);
! 345: }
1.11.4.1 ad 346: return error;
347: }
348: }
1.1 christos 349: curlwp->l_dupfd = fd;
1.4 christos 350: return EMOVEFD;
1.1 christos 351: case 1: /* /dev/ptm */
352: return 0;
353: default:
354: return ENODEV;
355: }
356: }
357:
1.5 thorpej 358: static int
1.1 christos 359: /*ARGSUSED*/
1.7 christos 360: ptmclose(dev_t dev, int flag, int mode, struct lwp *l)
1.1 christos 361: {
1.11.4.1 ad 362:
1.1 christos 363: return (0);
364: }
365:
1.5 thorpej 366: static int
1.1 christos 367: /*ARGSUSED*/
1.7 christos 368: ptmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct lwp *l)
1.1 christos 369: {
370: int error;
371: dev_t newdev;
372: int cfd, sfd;
373: struct file *fp;
1.7 christos 374: struct proc *p = l->l_proc;
1.1 christos 375:
376: error = 0;
377: switch (cmd) {
378: case TIOCPTMGET:
1.7 christos 379: if ((error = pty_alloc_master(l, &cfd, &newdev)) != 0)
1.1 christos 380: return error;
381:
1.7 christos 382: if ((error = pty_grant_slave(l, newdev)) != 0)
1.1 christos 383: goto bad;
384:
1.7 christos 385: if ((error = pty_alloc_slave(l, &sfd, newdev)) != 0)
1.1 christos 386: goto bad;
387:
388: /* now, put the indices and names into struct ptmget */
1.8 christos 389: return pty_fill_ptmget(l, newdev, cfd, sfd, data);
1.1 christos 390: default:
391: DPRINTF(("ptmioctl EINVAL\n"));
392: return EINVAL;
393: }
394: bad:
395: fp = fd_getfile(p->p_fd, cfd);
1.11.4.2! ad 396: if (fp != NULL) {
! 397: FILE_UNUSE(fp, l);
! 398: fdremove(p->p_fd, cfd);
! 399: ffree(fp);
! 400: }
1.1 christos 401: return error;
402: }
1.5 thorpej 403:
404: const struct cdevsw ptm_cdevsw = {
405: ptmopen, ptmclose, noread, nowrite, ptmioctl,
406: nullstop, notty, nopoll, nommap, nokqfilter, D_TTY
407: };
1.6 he 408: #endif
CVSweb <webmaster@jp.NetBSD.org>