Back to index

lightning-sunbird  0.9+nobinonly
ptytest.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is lineterm.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Ramalingam Saravanan.
00018  * Portions created by the Initial Developer are Copyright (C) 1999
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 /* ptytest.c: Test driver for ptystream.c
00038  * CPP options:
00039  *   LINUX:   for Linux2.0/glibc
00040  *   SOLARIS: for Solaris2.6
00041  */
00042 
00043 #include <stdio.h>
00044 #include <termios.h>
00045 
00046 #include <signal.h>
00047 
00048 #include <sys/types.h>
00049 #include <fcntl.h>
00050 #include <unistd.h>
00051 
00052 #ifdef SOLARIS
00053 #include <stropts.h>
00054 #include <poll.h>
00055 #endif
00056 
00057 #if defined(LINUX) || defined(BSDFAMILY)
00058 #include <sys/ioctl.h>
00059 #include <sys/poll.h>
00060 #endif
00061 
00062 #include "ptystream.h"
00063 
00064 static struct termios tios;    /* TERMIOS structure */
00065 
00066 void pipeTest(int argc, char *argv[]);
00067 void ptyTest(int argc, char *argv[]);
00068 
00069 int echofd = -1;
00070 
00071 int main(int argc, char *argv[]) {
00072 
00073   if (argc < 4) {
00074     fprintf(stderr, "Usage: %s pty|pipe <echo-tty-name>|'' <shell-path> ...\n",
00075                     argv[0]);
00076     exit(-1);
00077   }
00078 
00079   /* Get terminal attributes */
00080   if (tcgetattr(0, &tios) == -1) {
00081     fprintf(stderr, "Failed to get TTY attributes\n");
00082     exit(-1);
00083   }
00084 
00085   /* Disable signals, canonical mode processing, and echo  */
00086   tios.c_lflag &= ~(ISIG | ICANON | ECHO );
00087 
00088   /* set MIN=1 and TIME=0 */
00089   tios.c_cc[VMIN] = 1;
00090   tios.c_cc[VTIME] = 0;
00091 
00092   /* Set terminal attributes */
00093   if (tcsetattr(0, TCSAFLUSH, &tios) == -1) {
00094     fprintf(stderr, "Failed to set TTY attributes\n");
00095     exit(-1);
00096   }
00097 
00098   if (*argv[2]) {
00099     /* Open TTY for echoing */
00100     if ( (echofd = open(argv[2], O_WRONLY)) == -1)
00101       perror("ptytest");
00102     fprintf(stderr, "Echoing %s output to %s\n", argv[1], argv[2]);
00103     write( echofd, "Echoing PTYTEST output ...\n", 27);
00104   }
00105 
00106   fprintf(stderr, "Type Control-] to terminate input\n");
00107 
00108   if (strcmp(argv[1],"pipe") == 0) {
00109     pipeTest(argc-3, argv+3);
00110   } else {
00111     ptyTest(argc-3, argv+3);
00112   }
00113 
00114   if (echofd >= 0) close(echofd);
00115   exit(0);
00116 
00117 }
00118 
00119 
00120 /* sends raw terminal input/output to a shell through a pseudo-TTY */
00121 void ptyTest(int argc, char *argv[])
00122 {
00123   struct pollfd pollFD[2];
00124   nfds_t nfds = 2;
00125   struct ptys ptyStruc;
00126 
00127   unsigned char ch;
00128   int ptyFD, pollCode;
00129   ssize_t n_read, n_written;
00130 
00131   char temstr[3] = "^@";
00132 
00133   /* Create a PTY */
00134   if (pty_create(&ptyStruc,argv,24,80,0,0,
00135                  -1,0,0,0,1) == -1) {
00136     fprintf(stderr, "PTY creation failed\n");
00137     exit(-1);
00138   }
00139 
00140   ptyFD = ptyStruc.ptyFD;
00141 
00142   /* fprintf(stderr, "Polling for input on fd=0 (%s) and fd=%d\n",
00143      ttyname(0), ptyFD ); */
00144 
00145   /* Set up polling to read from parent STDIN and child STDOUT */
00146   pollFD[0].fd = 0;
00147   pollFD[0].events = POLLIN;
00148   pollFD[1].fd = ptyFD;
00149   pollFD[1].events = POLLIN;
00150 
00151   while ( (pollCode=poll(pollFD,nfds,-1)) >= 0) {
00152     if (pollCode == 0) continue;
00153     pollCode = 0;
00154 
00155     if (pollFD[0].revents != 0) {
00156       /* Read character from parent STDIN and write to child STDIN */
00157       ch = getchar();
00158 
00159       /* Exit poll loop if a Control-] character is read */
00160       if (ch == 0x1D) {
00161         fprintf(stderr, "EXIT ptytest\n");
00162         break;
00163       }
00164 
00165       if (write(ptyFD, &ch, 1) != 1) {
00166         fprintf(stderr, "Error in writing to child STDIN\n");
00167         exit(-1);
00168       }
00169 
00170     }
00171 
00172     if (pollFD[1].revents != 0) {
00173       /* Read character from child STDOUT and write to parent STDOUT */
00174 
00175       if ( (n_read=read(ptyFD, &ch, 1)) < 0) {
00176         fprintf(stderr, "Error in reading from child STDOUT\n");
00177         if (echofd >= 0) close(echofd);
00178         exit(-1);
00179       }
00180 
00181       if (n_read == 0) { /* End of file */
00182         if (echofd >= 0) close(echofd);
00183         exit(0);
00184       }
00185 
00186       if (echofd >= 0) {
00187         /* Echo output to another TTY */
00188         if (ch == 0x7F) {
00189           write(echofd, "\\DEL", 4);
00190         } else if (ch == 0x1B) {
00191           write(echofd, "\\ESC", 4);
00192         } else if (ch < 0x20) {
00193           temstr[1]= ch+'@';
00194           write(echofd, temstr, 2);
00195         } else {
00196           write(echofd, &ch, 1);
00197         }
00198       }
00199 
00200       if (write(1, &ch, 1) != 1) {
00201         fprintf(stderr, "Error in writing to parent STDOUT\n");
00202         exit(-1);
00203       }
00204 
00205       /*
00206       if (ioctl(1, I_FLUSH, FLUSHRW) == -1) {
00207         fprintf(stderr, "Error return from ioctl\n");
00208         exit(-1);
00209       }
00210       */
00211 
00212     }
00213   }
00214 
00215   if (pollCode != 0) {
00216     fprintf(stderr, "Error return from poll\n");
00217     exit(-1);
00218   }
00219 
00220   /* Close PTY */
00221   pty_close(&ptyStruc);
00222 
00223 }
00224 
00225 
00226 /* sends raw terminal input/output to a shell through a pipe */
00227 void pipeTest(int argc, char *argv[])
00228 {
00229   struct pollfd pollFD[2];
00230   nfds_t nfds = 2;
00231   pid_t child_pid = -1;   /* child process id */
00232 
00233   unsigned char ch;
00234   int pipeFD[2], pipeIN, pipeOUT, procIN, procOUT;
00235   int pollCode;
00236   ssize_t n_read, n_written;
00237 
00238   char temstr[3] = "^@";
00239 
00240   /* Create process input pipe (assumed unidirectional) */
00241   if (pipe(pipeFD) == -1) {
00242     fprintf(stderr, "Input pipe creation failed\n");
00243     exit(-1);
00244   }
00245 #ifdef DEBUG
00246   fprintf(stderr,"Created input pipe: %d %d\n", pipeFD[0], pipeFD[1]);
00247 #endif
00248   procIN = pipeFD[0];
00249   pipeIN = pipeFD[1];
00250 
00251   /* Create process output pipe (assumed unidirectional) */
00252   if (pipe(pipeFD) == -1) {
00253     fprintf(stderr, "Output pipe creation failed\n");
00254     exit(-1);
00255   }
00256 #ifdef DEBUG
00257   fprintf(stderr,"Created output pipe: %d %d\n", pipeFD[0], pipeFD[1]);
00258 #endif
00259   pipeOUT = pipeFD[0];
00260   procOUT = pipeFD[1];
00261 
00262   /* Fork a child process */
00263   child_pid = fork();
00264   if (child_pid < 0) {
00265     fprintf(stderr, "Fork failed\n");
00266     exit(-1);
00267   }
00268 
00269 #ifdef DEBUG
00270   fprintf(stderr, "Fork child process %d\n", child_pid);
00271 #endif
00272 
00273   if (child_pid == 0) {
00274     /* Child process */
00275 
00276     if (dup2(procIN, 0) == -1) {
00277       fprintf(stderr, "Dup2 failed for stdin of child\n");
00278       exit(-1);
00279     }
00280 
00281     if (dup2(procOUT, 1) == -1) {
00282       fprintf(stderr, "Dup2 failed for stdout of child\n");
00283       exit(-1);
00284     }
00285 
00286     execvp(argv[0], argv);
00287     fprintf(stderr, "Exec failed for command %s\n", argv[0]);
00288     exit(-1);
00289   }
00290 
00291   /* Set up polling to read from parent STDIN and child STDOUT */
00292   pollFD[0].fd = 0;
00293   pollFD[0].events = POLLIN;
00294   pollFD[1].fd = pipeOUT;
00295   pollFD[1].events = POLLIN;
00296 
00297   while ( (pollCode=poll(pollFD,nfds,-1)) >= 0) {
00298 
00299     if (pollFD[0].revents != 0) {
00300       /* Read character from parent STDIN and write to child STDIN */
00301       ch = getchar();
00302 
00303       /* Exit poll loop if a Control-] is read */
00304       if (ch == 0x1D) break;
00305 
00306       if (write(pipeIN, &ch, 1) != 1) {
00307         fprintf(stderr, "Error in writing to child STDIN\n");
00308         exit(-1);
00309       }
00310 
00311     }
00312 
00313     if (pollFD[1].revents != 0) {
00314       /* Read character from child STDOUT and write to parent STDOUT */
00315 
00316       if ( (n_read=read(pipeOUT, &ch, 1)) < 0) {
00317         fprintf(stderr, "Error in reading from child STDOUT\n");
00318         if (echofd >= 0) close(echofd);
00319         exit(-1);
00320       }
00321 
00322       if (n_read == 0) { /* End of file */
00323         if (echofd >= 0) close(echofd);
00324         exit(0);
00325       }
00326 
00327       if (echofd >= 0) {
00328         /* Echo output to another TTY */
00329         if (ch == 0x7F) {
00330           write(echofd, "\\DEL", 4);
00331         } else if (ch == 0x1B) {
00332           write(echofd, "\\ESC", 4);
00333         } else if (ch < 0x20) {
00334           temstr[1]= ch+'@';
00335           write(echofd, temstr, 2);
00336         } else {
00337           write(echofd, &ch, 1);
00338         }
00339       }
00340 
00341       if (write(1, &ch, 1) != 1) {
00342         fprintf(stderr, "Error in writing to parent STDOUT\n");
00343         exit(-1);
00344       }
00345 
00346       /*
00347       if (ioctl(1, I_FLUSH, FLUSHRW) == -1) {
00348         fprintf(stderr, "Error return from ioctl\n");
00349         exit(-1);
00350       }
00351       */
00352 
00353     }
00354 
00355   }
00356 
00357   if (kill(child_pid, SIGKILL) == -1) {
00358     fprintf(stderr, "Error return from kill\n");
00359     exit(-1);
00360   }
00361 
00362   if (pollCode != 0) {
00363     fprintf(stderr, "Error return from poll\n");
00364     exit(-1);
00365   }
00366 
00367   /* Close pipes (assumed unidirectional) */
00368   close(pipeIN);
00369   close(pipeOUT);
00370   close(procIN);
00371   close(procOUT);
00372 
00373 }