Annotation of src/sys/kern/tty_ptm.c, Revision 1.21.6.1
1.21.6.1! bouyer 1: /* $NetBSD$ */
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.21.6.1! bouyer 37: __KERNEL_RCSID(0, "$NetBSD$");
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/filedesc.h>
56: #include <sys/conf.h>
57: #include <sys/poll.h>
58: #include <sys/malloc.h>
59: #include <sys/pty.h>
1.9 elad 60: #include <sys/kauth.h>
1.1 christos 61:
62: #ifdef DEBUG_PTM
63: #define DPRINTF(a) printf a
64: #else
65: #define DPRINTF(a)
66: #endif
67:
68: #ifdef NO_DEV_PTM
69: const struct cdevsw ptm_cdevsw = {
70: noopen, noclose, noread, nowrite, noioctl,
71: nostop, notty, nopoll, nommap, nokqfilter, D_TTY
72: };
73: #else
74:
75: static struct ptm_pty *ptm;
76: int pts_major, ptc_major;
77:
78: static dev_t pty_getfree(void);
1.7 christos 79: static int pty_alloc_master(struct lwp *, int *, dev_t *);
80: static int pty_alloc_slave(struct lwp *, int *, dev_t);
1.1 christos 81:
82: void ptmattach(int);
83:
84: dev_t
85: pty_makedev(char ms, int minor)
86: {
87: return makedev(ms == 't' ? pts_major : ptc_major, minor);
88: }
89:
1.5 thorpej 90:
1.1 christos 91: static dev_t
92: pty_getfree(void)
93: {
1.18 ad 94: extern kmutex_t pt_softc_mutex;
1.1 christos 95: int i;
96:
1.18 ad 97: mutex_enter(&pt_softc_mutex);
1.1 christos 98: for (i = 0; i < npty; i++) {
99: if (pty_isfree(i, 0))
100: break;
101: }
1.18 ad 102: mutex_exit(&pt_softc_mutex);
1.1 christos 103: return pty_makedev('t', i);
104: }
105:
106: /*
107: * Hacked up version of vn_open. We _only_ handle ptys and only open
108: * them with FREAD|FWRITE and never deal with creat or stuff like that.
109: *
110: * We need it because we have to fake up root credentials to open the pty.
111: */
112: int
1.7 christos 113: pty_vn_open(struct vnode *vp, struct lwp *l)
1.1 christos 114: {
115: int error;
116:
117: if (vp->v_type != VCHR) {
118: vput(vp);
119: return EINVAL;
120: }
121:
1.21 pooka 122: error = VOP_OPEN(vp, FREAD|FWRITE, lwp0.l_cred);
1.1 christos 123:
124: if (error) {
125: vput(vp);
126: return error;
127: }
128:
129: vp->v_writecount++;
130:
131: return 0;
132: }
133:
134: static int
1.7 christos 135: pty_alloc_master(struct lwp *l, int *fd, dev_t *dev)
1.1 christos 136: {
137: int error;
138: struct file *fp;
139: struct vnode *vp;
140: int md;
141:
1.11 ad 142: if ((error = falloc(l, &fp, fd)) != 0) {
1.1 christos 143: DPRINTF(("falloc %d\n", error));
144: return error;
145: }
146: retry:
147: /* Find and open a free master pty. */
148: *dev = pty_getfree();
149: md = minor(*dev);
150: if ((error = pty_check(md)) != 0) {
151: DPRINTF(("pty_check %d\n", error));
152: goto bad;
153: }
154: if (ptm == NULL) {
1.13 christos 155: DPRINTF(("no ptm\n"));
1.1 christos 156: error = EOPNOTSUPP;
157: goto bad;
158: }
1.13 christos 159: if ((error = (*ptm->allocvp)(ptm, l, &vp, *dev, 'p')) != 0) {
160: DPRINTF(("pty_allocvp %d\n", error));
1.1 christos 161: goto bad;
1.13 christos 162: }
1.1 christos 163:
1.7 christos 164: if ((error = pty_vn_open(vp, l)) != 0) {
1.13 christos 165: DPRINTF(("pty_vn_open %d\n", error));
1.1 christos 166: /*
167: * Check if the master open failed because we lost
168: * the race to grab it.
169: */
170: if (error != EIO)
171: goto bad;
172: error = !pty_isfree(md, 1);
1.13 christos 173: DPRINTF(("pty_isfree %d\n", error));
1.1 christos 174: if (error)
175: goto retry;
176: else
177: goto bad;
178: }
179: fp->f_flag = FREAD|FWRITE;
180: fp->f_type = DTYPE_VNODE;
181: fp->f_ops = &vnops;
182: fp->f_data = vp;
183: VOP_UNLOCK(vp, 0);
184: FILE_SET_MATURE(fp);
1.7 christos 185: FILE_UNUSE(fp, l);
1.1 christos 186: return 0;
187: bad:
1.7 christos 188: FILE_UNUSE(fp, l);
1.11 ad 189: fdremove(l->l_proc->p_fd, *fd);
1.1 christos 190: ffree(fp);
191: return error;
192: }
193:
194: int
1.7 christos 195: pty_grant_slave(struct lwp *l, dev_t dev)
1.1 christos 196: {
197: int error;
1.20 ad 198: bool revoke;
1.1 christos 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.21 pooka 219: error = VOP_SETATTR(vp, &vattr, lwp0.l_cred);
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: }
1.21.6.1! bouyer 227: mutex_enter(&vp->v_interlock);
1.20 ad 228: revoke = (vp->v_usecount > 1 || (vp->v_iflag & VI_ALIASED) ||
229: (vp->v_iflag & VI_LAYER));
1.21.6.1! bouyer 230: mutex_exit(&vp->v_interlock);
1.1 christos 231: VOP_UNLOCK(vp, 0);
1.20 ad 232: if (revoke)
1.1 christos 233: VOP_REVOKE(vp, REVOKEALL);
234:
235: /*
236: * The vnode is useless after the revoke, we need to get it again.
237: */
238: vrele(vp);
239: return 0;
240: }
241:
242: static int
1.7 christos 243: pty_alloc_slave(struct lwp *l, int *fd, dev_t dev)
1.1 christos 244: {
245: int error;
246: struct file *fp;
247: struct vnode *vp;
248:
249: /* Grab a filedescriptor for the slave */
1.11 ad 250: if ((error = falloc(l, &fp, fd)) != 0) {
1.1 christos 251: DPRINTF(("falloc %d\n", error));
252: return error;
253: }
254:
255: if (ptm == NULL) {
256: error = EOPNOTSUPP;
257: goto bad;
258: }
259:
1.7 christos 260: if ((error = (*ptm->allocvp)(ptm, l, &vp, dev, 't')) != 0)
1.1 christos 261: goto bad;
1.7 christos 262: if ((error = pty_vn_open(vp, l)) != 0)
1.1 christos 263: goto bad;
264:
265: fp->f_flag = FREAD|FWRITE;
266: fp->f_type = DTYPE_VNODE;
267: fp->f_ops = &vnops;
268: fp->f_data = vp;
269: VOP_UNLOCK(vp, 0);
270: FILE_SET_MATURE(fp);
1.7 christos 271: FILE_UNUSE(fp, l);
1.1 christos 272: return 0;
273: bad:
1.7 christos 274: FILE_UNUSE(fp, l);
1.11 ad 275: fdremove(l->l_proc->p_fd, *fd);
1.1 christos 276: ffree(fp);
277: return error;
278: }
279:
280: struct ptm_pty *
281: pty_sethandler(struct ptm_pty *nptm)
282: {
283: struct ptm_pty *optm = ptm;
284: ptm = nptm;
285: return optm;
286: }
287:
288: int
1.8 christos 289: pty_fill_ptmget(struct lwp *l, dev_t dev, int cfd, int sfd, void *data)
1.1 christos 290: {
291: struct ptmget *ptmg = data;
292: int error;
293:
294: if (ptm == NULL)
295: return EOPNOTSUPP;
296:
1.2 christos 297: ptmg->cfd = cfd == -1 ? minor(dev) : cfd;
298: ptmg->sfd = sfd == -1 ? minor(dev) : sfd;
1.1 christos 299:
1.8 christos 300: error = (*ptm->makename)(ptm, l, ptmg->cn, sizeof(ptmg->cn), dev, 'p');
1.1 christos 301: if (error)
302: return error;
303:
1.8 christos 304: return (*ptm->makename)(ptm, l, ptmg->sn, sizeof(ptmg->sn), dev, 't');
1.1 christos 305: }
306:
307: void
308: /*ARGSUSED*/
1.15 yamt 309: ptmattach(int n)
1.1 christos 310: {
311: extern const struct cdevsw pts_cdevsw, ptc_cdevsw;
312: /* find the major and minor of the pty devices */
313: if ((pts_major = cdevsw_lookup_major(&pts_cdevsw)) == -1)
314: panic("ptmattach: Can't find pty slave in cdevsw");
315: if ((ptc_major = cdevsw_lookup_major(&ptc_cdevsw)) == -1)
316: panic("ptmattach: Can't find pty master in cdevsw");
317: #ifdef COMPAT_BSDPTY
318: ptm = &ptm_bsdpty;
319: #endif
320: }
321:
1.5 thorpej 322: static int
1.1 christos 323: /*ARGSUSED*/
1.15 yamt 324: ptmopen(dev_t dev, int flag, int mode, struct lwp *l)
1.1 christos 325: {
326: int error;
327: int fd;
1.13 christos 328: dev_t ttydev;
1.1 christos 329:
330: switch(minor(dev)) {
331: case 0: /* /dev/ptmx */
1.12 christos 332: case 2: /* /emul/linux/dev/ptmx */
1.13 christos 333: if ((error = pty_alloc_master(l, &fd, &ttydev)) != 0)
1.1 christos 334: return error;
1.12 christos 335: if (minor(dev) == 2) {
336: /*
337: * Linux ptyfs grants the pty right here.
338: * Handle this case here, instead of writing
339: * a new linux module.
340: */
1.13 christos 341: if ((error = pty_grant_slave(l, ttydev)) != 0) {
1.12 christos 342: struct file *fp =
343: fd_getfile(l->l_proc->p_fd, fd);
1.16 alc 344: if (fp != NULL) {
345: FILE_UNUSE(fp, l);
346: fdremove(l->l_proc->p_fd, fd);
347: ffree(fp);
348: }
1.12 christos 349: return error;
350: }
351: }
1.1 christos 352: curlwp->l_dupfd = fd;
1.4 christos 353: return EMOVEFD;
1.1 christos 354: case 1: /* /dev/ptm */
355: return 0;
356: default:
357: return ENODEV;
358: }
359: }
360:
1.5 thorpej 361: static int
1.1 christos 362: /*ARGSUSED*/
1.15 yamt 363: ptmclose(dev_t dev, int flag, int mode, struct lwp *l)
1.1 christos 364: {
1.15 yamt 365:
1.1 christos 366: return (0);
367: }
368:
1.5 thorpej 369: static int
1.1 christos 370: /*ARGSUSED*/
1.17 christos 371: ptmioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
1.1 christos 372: {
373: int error;
374: dev_t newdev;
375: int cfd, sfd;
376: struct file *fp;
1.7 christos 377: struct proc *p = l->l_proc;
1.1 christos 378:
379: error = 0;
380: switch (cmd) {
381: case TIOCPTMGET:
1.7 christos 382: if ((error = pty_alloc_master(l, &cfd, &newdev)) != 0)
1.1 christos 383: return error;
384:
1.7 christos 385: if ((error = pty_grant_slave(l, newdev)) != 0)
1.1 christos 386: goto bad;
387:
1.7 christos 388: if ((error = pty_alloc_slave(l, &sfd, newdev)) != 0)
1.1 christos 389: goto bad;
390:
391: /* now, put the indices and names into struct ptmget */
1.8 christos 392: return pty_fill_ptmget(l, newdev, cfd, sfd, data);
1.1 christos 393: default:
394: DPRINTF(("ptmioctl EINVAL\n"));
395: return EINVAL;
396: }
397: bad:
398: fp = fd_getfile(p->p_fd, cfd);
1.16 alc 399: if (fp != NULL) {
400: FILE_UNUSE(fp, l);
401: fdremove(p->p_fd, cfd);
402: ffree(fp);
403: }
1.1 christos 404: return error;
405: }
1.5 thorpej 406:
407: const struct cdevsw ptm_cdevsw = {
408: ptmopen, ptmclose, noread, nowrite, ptmioctl,
409: nullstop, notty, nopoll, nommap, nokqfilter, D_TTY
410: };
1.6 he 411: #endif
CVSweb <webmaster@jp.NetBSD.org>