[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.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>