Diff for /libaitio/src/pty.c between versions 1.1 and 1.2

version 1.1, 2011/09/19 21:59:58 version 1.2, 2011/10/31 13:53:51
Line 0 Line 1
   /*************************************************************************
   * (C) 2011 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
   *  by Michael Pounov <misho@openbsd-bg.org>
   *
   * $Author$
   * $Id$
   *
   **************************************************************************
   The ELWIX and AITNET software is distributed under the following
   terms:
   
   All of the documentation and software included in the ELWIX and AITNET
   Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
   
   Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
           by Michael Pounov <misho@elwix.org>.  All rights reserved.
   
   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:
   1. Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
   2. Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
   3. All advertising materials mentioning features or use of this software
      must display the following acknowledgement:
   This product includes software developed by Michael Pounov <misho@elwix.org>
   ELWIX - Embedded LightWeight unIX and its contributors.
   4. Neither the name of AITNET nor the names of its contributors
      may be used to endorse or promote products derived from this software
      without specific prior written permission.
   
   THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   SUCH DAMAGE.
   */
   #include "global.h"
   
   
   /*
    * ioAllocPTY() Allocate new PTY and TTY
    * @ptyfd = master fd, pty
    * @ttyfd = slave fd, tty
    * @name = tty device name if not null
    * @namesiz = name length, must be above 63 bytes.
    * @term = termios for terminal
    * @winz = winsize for terminal
    * return: -1 error or 0 ok
    */
   inline int
   ioAllocPTY(int *ptyfd, int *ttyfd, char * __restrict name, int namesiz, 
                   struct termios * __restrict term, struct winsize * __restrict winz)
   {
           assert(ptyfd && ttyfd);
           if (!ptyfd || !ttyfd || (name && namesiz < 64)) {
                   io_SetErr(EINVAL, "Error:: invalid arguments ...");
                   return -1;
           }
   
           memset(name, 0, namesiz);
           if (openpty(ptyfd, ttyfd, name, term, winz) == -1) {
                   LOGERR;
                   return -1;
           }
   
           return 0;
   }
   
   /*
    * ioFreePTY() Release PTY and TTY device
    * @ptyfd = master fd, pty (==-1 skip closing pty)
    * @ttyname = tty filename
    * return: none
    */
   inline void
   ioFreePTY(int ptyfd, const char *ttyname)
   {
           assert(ttyname);
           if (!ttyname)
                   return;
   
           if (ptyfd != -1)
                   close(ptyfd);
           if (ttyname) {
                   chown(ttyname, (uid_t) 0, (gid_t) 0);
                   chmod(ttyname, (mode_t) 0666);
           }
   }
   
   /*
    * ioChgWinPTY() Change window size of PTY
    * @ptyfd = master fd, pty
    * @row = row
    * @col = col
    * @xpxl = x pixels
    * @ypxl = y pixels
    * return: -1 error or 0 ok
    */
   inline int
   ioChgWinPTY(int ptyfd, u_short row, u_short col, u_short xpxl, u_short ypxl)
   {
           struct winsize w;
   
           w.ws_row = row;
           w.ws_col = col;
           w.ws_xpixel = xpxl;
           w.ws_ypixel = ypxl;
   
           if (ioctl(ptyfd, TIOCSWINSZ, &w) == -1) {
                   LOGERR;
                   return -1;
           }
   
           return 0;
   }
   
   /*
    * ioSetOwnerTTY() Set owner to TTY
    * @ttyname = tty filename
    * @UID = uid
    * @GID = gid
    * return: -1 error or 0 ok
    */
   int
   ioSetOwnerTTY(const char *ttyname, uid_t UID, gid_t GID)
   {
           struct group *grp;
           gid_t gid;
           mode_t mode;
           struct stat st;
   
           assert(ttyname);
           if (!ttyname) {
                   io_SetErr(EINVAL, "Error:: invalid arguments ...");
                   return -1;
           }
   
           grp = getgrnam("tty");
           if (!grp) {
                   gid = GID;
                   mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
           } else {
                   gid = grp->gr_gid;
                   mode = S_IRUSR | S_IWUSR | S_IWGRP;
           }
   
           if (stat(ttyname, &st) == -1) {
                   LOGERR;
                   return -1;
           }
   
           if (st.st_uid != UID || st.st_gid != gid)
                   if (chown(ttyname, UID, gid) == -1) {
                           LOGERR;
                           return -1;
                   }
           if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode)
                   if (chmod(ttyname, mode) == -1) {
                           LOGERR;
                           return -1;
                   }
   
           return 0;
   }
   
   /*
    * ioSetSidTTY() Makes the process's controlling TTY and sets it to sane modes.
    * @ttyfd = slave fd, tty
    * @ttyname = tty filename
    * return: -1 error or 0 ok
    */
   int
   ioSetSidTTY(int *ttyfd, const char *ttyname)
   {
           int fd;
   
           /* First disconnect from the old controlling tty. */
   #ifdef TIOCNOTTY
           fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
           if (fd >= 0) {
                   ioctl(fd, TIOCNOTTY, NULL);
                   close(fd);
           }
   #endif
           setsid();
   
           /* Verify that we are successfully disconnected from the controlling tty. */
           fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
           if (fd >= 0) {
                   io_SetErr(ENXIO, "Error:: Failed to disconnect from controlling tty.");
                   close(fd);
                   return -1;
           }
           /* Make it our controlling tty. */
   #ifdef TIOCSCTTY
           if (ioctl(*ttyfd, TIOCSCTTY, NULL) == -1) {
                   LOGERR;
                   return -1;
           }
   #endif
           fd = open(ttyname, O_RDWR);
           if (fd == -1) {
                   LOGERR;
                   return -1;
           } else
                   close(fd);
   
           /* Verify that we now have a controlling tty. */
           fd = open(_PATH_TTY, O_WRONLY);
           if (fd == -1) {
                   LOGERR;
                   return -1;
           } else
                   close(fd);
   
           /* redirect standart handles to tty */
           dup2(*ttyfd, STDIN_FILENO);
           dup2(*ttyfd, STDOUT_FILENO);
           dup2(*ttyfd, STDERR_FILENO);
           if (*ttyfd > 2)
                   close(*ttyfd);
   
           /* NOW TTY IS READY! */
           return 0;
   }
   
   /*
    * ioSetRAWMode() Enter into RAW mode
    * @fd = tty fd
    * @otio = saved old termios for later restore if !=NULL
    * return: -1 error or 0 ok
    */
   inline int
   ioSetRAWMode(int fd, struct termios *otio)
   {
           struct termios tio;
   
           if (tcgetattr(fd, &tio) == -1) {
                   LOGERR;
                   return -1;
           }
           if (otio)
                   *otio = tio;
   
           tio.c_iflag |= IGNPAR;
           tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
   #ifdef IUCLC
           tio.c_iflag &= ~IUCLC;
   #endif
           tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
   #ifdef IEXTEN
           tio.c_lflag &= ~IEXTEN;
   #endif
           tio.c_oflag &= ~OPOST;
           tio.c_cc[VMIN] = 1;
           tio.c_cc[VTIME] = 0;
   
           if (tcsetattr(fd, TCSADRAIN, &tio) == -1) {
                   LOGERR;
                   return -1;
           }
   
           return 0;
   }
   
   /*
    * ioRestoreMode() Restore termios to tty fd
    * @fd = tty fd
    * @tio = termios structure for restore
    * return: -1 error or 0 ok
    */
   inline int
   ioRestoreMode(int fd, struct termios tio)
   {
           if (tcsetattr(fd, TCSADRAIN, &tio) == -1) {
                   LOGERR;
                   return -1;
           }
   
           return 0;
   }
   
   /*
    * ioForkPTY() Fork new process with session leader and new TTY
    * @ptyfd = master fd, pty
    * @name = tty device name if not null
    * @namesiz = name length, must be above 63 bytes.
    * @term = termios for terminal
    * @winz = winsize for terminal
    * @otio = old termios structure for restore
    * return: -1 error, 0 child process or >0 parent: pid of child
    */
   pid_t
   ioForkPTY(int *ptyfd, char * __restrict name, int namesiz, struct termios * __restrict term, 
                   struct winsize * __restrict winz, struct termios * __restrict otio)
   {
           int ttyfd;
           pid_t pid;
   
           if (ioAllocPTY(ptyfd, &ttyfd, name, namesiz, term, winz))
                   return -1;
   
           switch ((pid = fork())) {
                   case -1:
                           LOGERR;
                           return -1;
                   case 0:
                           if (ioSetOwnerTTY(name, getuid(), getgid()) == -1) {
                                   ioFreePTY(*ptyfd, name);
                                   return -1;
                           }
                           if (ioSetSidTTY(&ttyfd, name) == -1) {
                                   ioFreePTY(*ptyfd, name);
                                   return -1;
                           }
                           close(*ptyfd);
   
                           /* CHILD */
                           break;
                   default:
                           close(ttyfd);
   
                           /* PARENT */
                           break;
           }
   
           return pid;
   }

Removed from v.1.1  
changed lines
  Added in v.1.2


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>