[BACK]Return to tty_ptm.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

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>