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

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/kern/tty_ptm.c between version 1.4 and 1.4.12.8

version 1.4, 2004/11/30 04:25:44 version 1.4.12.8, 2008/03/24 09:39:02
Line 52  __KERNEL_RCSID(0, "$NetBSD$");
Line 52  __KERNEL_RCSID(0, "$NetBSD$");
 #include <sys/vnode.h>  #include <sys/vnode.h>
 #include <sys/namei.h>  #include <sys/namei.h>
 #include <sys/signalvar.h>  #include <sys/signalvar.h>
 #include <sys/uio.h>  
 #include <sys/filedesc.h>  #include <sys/filedesc.h>
 #include <sys/conf.h>  #include <sys/conf.h>
 #include <sys/poll.h>  #include <sys/poll.h>
 #include <sys/malloc.h>  #include <sys/malloc.h>
 #include <sys/pty.h>  #include <sys/pty.h>
   #include <sys/kauth.h>
   
   #include <miscfs/specfs/specdev.h>
   
 #ifdef DEBUG_PTM  #ifdef DEBUG_PTM
 #define DPRINTF(a)      printf a  #define DPRINTF(a)      printf a
Line 76  static struct ptm_pty *ptm;
Line 78  static struct ptm_pty *ptm;
 int pts_major, ptc_major;  int pts_major, ptc_major;
   
 static dev_t pty_getfree(void);  static dev_t pty_getfree(void);
 static int pty_alloc_master(struct proc *, int *, dev_t *);  static int pty_alloc_master(struct lwp *, int *, dev_t *);
 static int pty_alloc_slave(struct proc *, int *, dev_t);  static int pty_alloc_slave(struct lwp *, int *, dev_t);
   
 void ptmattach(int);  void ptmattach(int);
   
 dev_type_open(ptmopen);  
 dev_type_close(ptmclose);  
 dev_type_ioctl(ptmioctl);  
   
 const struct cdevsw ptm_cdevsw = {  
         ptmopen, ptmclose, noread, nowrite, ptmioctl,  
         nullstop, notty, nopoll, nommap, nokqfilter, D_TTY  
 };  
   
 dev_t  dev_t
 pty_makedev(char ms, int minor)  pty_makedev(char ms, int minor)
 {  {
         return makedev(ms == 't' ? pts_major : ptc_major, minor);          return makedev(ms == 't' ? pts_major : ptc_major, minor);
 }  }
   
   
 static dev_t  static dev_t
 pty_getfree(void)  pty_getfree(void)
 {  {
         extern struct simplelock pt_softc_mutex;          extern kmutex_t pt_softc_mutex;
         int i;          int i;
   
         simple_lock(&pt_softc_mutex);          mutex_enter(&pt_softc_mutex);
         for (i = 0; i < npty; i++) {          for (i = 0; i < npty; i++) {
                 if (pty_isfree(i, 0))                  if (pty_isfree(i, 0))
                         break;                          break;
         }          }
         simple_unlock(&pt_softc_mutex);          mutex_exit(&pt_softc_mutex);
         return pty_makedev('t', i);          return pty_makedev('t', i);
 }  }
   
Line 118  pty_getfree(void)
Line 112  pty_getfree(void)
  * We need it because we have to fake up root credentials to open the pty.   * We need it because we have to fake up root credentials to open the pty.
  */   */
 int  int
 pty_vn_open(struct vnode *vp, struct proc *p)  pty_vn_open(struct vnode *vp, struct lwp *l)
 {  {
         struct ucred *cred;  
         int error;          int error;
   
         if (vp->v_type != VCHR) {          if (vp->v_type != VCHR) {
Line 128  pty_vn_open(struct vnode *vp, struct pro
Line 121  pty_vn_open(struct vnode *vp, struct pro
                 return EINVAL;                  return EINVAL;
         }          }
   
         /*          error = VOP_OPEN(vp, FREAD|FWRITE, lwp0.l_cred);
          * Get us a fresh cred with root privileges.  
          */  
         cred = crget();  
         error = VOP_OPEN(vp, FREAD|FWRITE, cred, p);  
         crfree(cred);  
   
         if (error) {          if (error) {
                 vput(vp);                  vput(vp);
Line 146  pty_vn_open(struct vnode *vp, struct pro
Line 134  pty_vn_open(struct vnode *vp, struct pro
 }  }
   
 static int  static int
 pty_alloc_master(struct proc *p, int *fd, dev_t *dev)  pty_alloc_master(struct lwp *l, int *fd, dev_t *dev)
 {  {
         int error;          int error;
         struct file *fp;          struct file *fp;
         struct vnode *vp;          struct vnode *vp;
         int md;          int md;
   
         if ((error = falloc(p, &fp, fd)) != 0) {          if ((error = fd_allocfile(&fp, fd)) != 0) {
                 DPRINTF(("falloc %d\n", error));                  DPRINTF(("fd_allocfile %d\n", error));
                 return error;                  return error;
         }          }
 retry:  retry:
Line 166  retry:
Line 154  retry:
                 goto bad;                  goto bad;
         }          }
         if (ptm == NULL) {          if (ptm == NULL) {
                   DPRINTF(("no ptm\n"));
                 error = EOPNOTSUPP;                  error = EOPNOTSUPP;
                 goto bad;                  goto bad;
         }          }
         if ((error = (*ptm->allocvp)(ptm, p, &vp, *dev, 'p')) != 0)          if ((error = (*ptm->allocvp)(ptm, l, &vp, *dev, 'p')) != 0) {
                   DPRINTF(("pty_allocvp %d\n", error));
                 goto bad;                  goto bad;
           }
   
         if ((error = pty_vn_open(vp, p)) != 0) {          if ((error = pty_vn_open(vp, l)) != 0) {
                   DPRINTF(("pty_vn_open %d\n", error));
                 /*                  /*
                  * Check if the master open failed because we lost                   * Check if the master open failed because we lost
                  * the race to grab it.                   * the race to grab it.
Line 180  retry:
Line 172  retry:
                 if (error != EIO)                  if (error != EIO)
                         goto bad;                          goto bad;
                 error = !pty_isfree(md, 1);                  error = !pty_isfree(md, 1);
                   DPRINTF(("pty_isfree %d\n", error));
                 if (error)                  if (error)
                         goto retry;                          goto retry;
                 else                  else
Line 190  retry:
Line 183  retry:
         fp->f_ops = &vnops;          fp->f_ops = &vnops;
         fp->f_data = vp;          fp->f_data = vp;
         VOP_UNLOCK(vp, 0);          VOP_UNLOCK(vp, 0);
         FILE_SET_MATURE(fp);          fd_affix(curproc, fp, *fd);
         FILE_UNUSE(fp, p);  
         return 0;          return 0;
 bad:  bad:
         FILE_UNUSE(fp, p);          fd_abort(curproc, fp, *fd);
         fdremove(p->p_fd, *fd);  
         ffree(fp);  
         return error;          return error;
 }  }
   
 int  int
 pty_grant_slave(struct proc *p, dev_t dev)  pty_grant_slave(struct lwp *l, dev_t dev)
 {  {
         int error;          int error;
         struct vnode *vp;          struct vnode *vp;
Line 217  pty_grant_slave(struct proc *p, dev_t de
Line 207  pty_grant_slave(struct proc *p, dev_t de
          */           */
         if (ptm == NULL)          if (ptm == NULL)
                 return EOPNOTSUPP;                  return EOPNOTSUPP;
           if ((error = (*ptm->allocvp)(ptm, l, &vp, dev, 't')) != 0)
         if ((error = (*ptm->allocvp)(ptm, p, &vp, dev, 't')) != 0)  
                 return error;                  return error;
   
         if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {          if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
                 struct vattr vattr;                  struct vattr vattr;
                 struct ucred *cred;                  (*ptm->getvattr)(ptm, l, &vattr);
                 (*ptm->getvattr)(ptm, p, &vattr);                  /* Do the VOP_SETATTR() as root. */
                 /* Get a fake cred to pretend we're root. */                  error = VOP_SETATTR(vp, &vattr, lwp0.l_cred);
                 cred = crget();  
                 error = VOP_SETATTR(vp, &vattr, cred, p);  
                 crfree(cred);  
                 if (error) {                  if (error) {
                         DPRINTF(("setattr %d\n", error));                          DPRINTF(("setattr %d\n", error));
                         VOP_UNLOCK(vp, 0);                          VOP_UNLOCK(vp, 0);
Line 237  pty_grant_slave(struct proc *p, dev_t de
Line 223  pty_grant_slave(struct proc *p, dev_t de
                 }                  }
         }          }
         VOP_UNLOCK(vp, 0);          VOP_UNLOCK(vp, 0);
         if (vp->v_usecount > 1 ||          VOP_REVOKE(vp, REVOKEALL);
             (vp->v_flag & (VALIASED | VLAYER)))  
                 VOP_REVOKE(vp, REVOKEALL);  
   
         /*          /*
          * The vnode is useless after the revoke, we need to get it again.           * The vnode is useless after the revoke, we need to get it again.
Line 249  pty_grant_slave(struct proc *p, dev_t de
Line 233  pty_grant_slave(struct proc *p, dev_t de
 }  }
   
 static int  static int
 pty_alloc_slave(struct proc *p, int *fd, dev_t dev)  pty_alloc_slave(struct lwp *l, int *fd, dev_t dev)
 {  {
         int error;          int error;
         struct file *fp;          struct file *fp;
         struct vnode *vp;          struct vnode *vp;
   
         /* Grab a filedescriptor for the slave */          /* Grab a filedescriptor for the slave */
         if ((error = falloc(p, &fp, fd)) != 0) {          if ((error = fd_allocfile(&fp, fd)) != 0) {
                 DPRINTF(("falloc %d\n", error));                  DPRINTF(("fd_allocfile %d\n", error));
                 return error;                  return error;
         }          }
   
Line 266  pty_alloc_slave(struct proc *p, int *fd,
Line 250  pty_alloc_slave(struct proc *p, int *fd,
                 goto bad;                  goto bad;
         }          }
   
         if ((error = (*ptm->allocvp)(ptm, p, &vp, dev, 't')) != 0)          if ((error = (*ptm->allocvp)(ptm, l, &vp, dev, 't')) != 0)
                 goto bad;                  goto bad;
         if ((error = pty_vn_open(vp, p)) != 0)          if ((error = pty_vn_open(vp, l)) != 0)
                 goto bad;                  goto bad;
   
         fp->f_flag = FREAD|FWRITE;          fp->f_flag = FREAD|FWRITE;
Line 276  pty_alloc_slave(struct proc *p, int *fd,
Line 260  pty_alloc_slave(struct proc *p, int *fd,
         fp->f_ops = &vnops;          fp->f_ops = &vnops;
         fp->f_data = vp;          fp->f_data = vp;
         VOP_UNLOCK(vp, 0);          VOP_UNLOCK(vp, 0);
         FILE_SET_MATURE(fp);          fd_affix(curproc, fp, *fd);
         FILE_UNUSE(fp, p);  
         return 0;          return 0;
 bad:  bad:
         FILE_UNUSE(fp, p);          fd_abort(curproc, fp, *fd);
         fdremove(p->p_fd, *fd);  
         ffree(fp);  
         return error;          return error;
 }  }
   
Line 295  pty_sethandler(struct ptm_pty *nptm)
Line 276  pty_sethandler(struct ptm_pty *nptm)
 }  }
   
 int  int
 pty_fill_ptmget(dev_t dev, int cfd, int sfd, void *data)  pty_fill_ptmget(struct lwp *l, dev_t dev, int cfd, int sfd, void *data)
 {  {
         struct ptmget *ptmg = data;          struct ptmget *ptmg = data;
         int error;          int error;
Line 306  pty_fill_ptmget(dev_t dev, int cfd, int 
Line 287  pty_fill_ptmget(dev_t dev, int cfd, int 
         ptmg->cfd = cfd == -1 ? minor(dev) : cfd;          ptmg->cfd = cfd == -1 ? minor(dev) : cfd;
         ptmg->sfd = sfd == -1 ? minor(dev) : sfd;          ptmg->sfd = sfd == -1 ? minor(dev) : sfd;
   
         error = (*ptm->makename)(ptm, ptmg->cn, sizeof(ptmg->cn), dev, 'p');          error = (*ptm->makename)(ptm, l, ptmg->cn, sizeof(ptmg->cn), dev, 'p');
         if (error)          if (error)
                 return error;                  return error;
   
         return (*ptm->makename)(ptm, ptmg->sn, sizeof(ptmg->sn), dev, 't');          return (*ptm->makename)(ptm, l, ptmg->sn, sizeof(ptmg->sn), dev, 't');
 }  }
   
 void  void
Line 328  ptmattach(int n)
Line 309  ptmattach(int n)
 #endif  #endif
 }  }
   
 int  static int
 /*ARGSUSED*/  /*ARGSUSED*/
 ptmopen(dev_t dev, int flag, int mode, struct proc *p)  ptmopen(dev_t dev, int flag, int mode, struct lwp *l)
 {  {
         int error;          int error;
         int fd;          int fd;
           dev_t ttydev;
   
         switch(minor(dev)) {          switch(minor(dev)) {
         case 0:         /* /dev/ptmx */          case 0:         /* /dev/ptmx */
                 if ((error = pty_alloc_master(p, &fd, &dev)) != 0)          case 2:         /* /emul/linux/dev/ptmx */
                   if ((error = pty_alloc_master(l, &fd, &ttydev)) != 0)
                         return error;                          return error;
                   if (minor(dev) == 2) {
                           /*
                            * Linux ptyfs grants the pty right here.
                            * Handle this case here, instead of writing
                            * a new linux module.
                            */
                           if ((error = pty_grant_slave(l, ttydev)) != 0) {
                                   file_t *fp = fd_getfile(fd);
                                   if (fp != NULL) {
                                           fd_close(fd);
                                   }
                                   return error;
                           }
                   }
                 curlwp->l_dupfd = fd;                  curlwp->l_dupfd = fd;
                 return EMOVEFD;                  return EMOVEFD;
         case 1:         /* /dev/ptm */          case 1:         /* /dev/ptm */
Line 348  ptmopen(dev_t dev, int flag, int mode, s
Line 345  ptmopen(dev_t dev, int flag, int mode, s
         }          }
 }  }
   
 int  static int
 /*ARGSUSED*/  /*ARGSUSED*/
 ptmclose(dev_t dev, int flag, int mode, struct proc *p)  ptmclose(dev_t dev, int flag, int mode, struct lwp *l)
 {  {
   
         return (0);          return (0);
 }  }
   
 int  static int
 /*ARGSUSED*/  /*ARGSUSED*/
 ptmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)  ptmioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
 {  {
         int error;          int error;
         dev_t newdev;          dev_t newdev;
         int cfd, sfd;          int cfd, sfd;
         struct file *fp;          file_t *fp;
   
         error = 0;          error = 0;
         switch (cmd) {          switch (cmd) {
         case TIOCPTMGET:          case TIOCPTMGET:
                 if ((error = pty_alloc_master(p, &cfd, &newdev)) != 0)                  if ((error = pty_alloc_master(l, &cfd, &newdev)) != 0)
                         return error;                          return error;
   
                 if ((error = pty_grant_slave(p, newdev)) != 0)                  if ((error = pty_grant_slave(l, newdev)) != 0)
                         goto bad;                          goto bad;
   
                 if ((error = pty_alloc_slave(p, &sfd, newdev)) != 0)                  if ((error = pty_alloc_slave(l, &sfd, newdev)) != 0)
                         goto bad;                          goto bad;
   
                 /* now, put the indices and names into struct ptmget */                  /* now, put the indices and names into struct ptmget */
                 return pty_fill_ptmget(newdev, cfd, sfd, data);                  return pty_fill_ptmget(l, newdev, cfd, sfd, data);
         default:          default:
                 DPRINTF(("ptmioctl EINVAL\n"));                  DPRINTF(("ptmioctl EINVAL\n"));
                 return EINVAL;                  return EINVAL;
         }          }
 bad:   bad:
         fp = fd_getfile(p->p_fd, cfd);          fp = fd_getfile(cfd);
         fdremove(p->p_fd, cfd);          if (fp != NULL) {
         ffree(fp);                  fd_close(cfd);
           }
         return error;          return error;
 }  }
   
   const struct cdevsw ptm_cdevsw = {
           ptmopen, ptmclose, noread, nowrite, ptmioctl,
           nullstop, notty, nopoll, nommap, nokqfilter, D_TTY
   };
 #endif  #endif

Legend:
Removed from v.1.4  
changed lines
  Added in v.1.4.12.8

CVSweb <webmaster@jp.NetBSD.org>