⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 enhance.c

📁 xorp源码hg
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <signal.h>#include <locale.h>#include <unistd.h>#include <termios.h>#include <fcntl.h>#include <sys/termios.h>#include <sys/time.h>#include <sys/types.h>#include <sys/wait.h>#include <dirent.h>#if HAVE_SYSV_PTY#include <stropts.h>    /* System-V stream I/O */char *ptsname(int fd);int grantpt(int fd);int unlockpt(int fd);#endif#include "libtecla.h"/* * Pseudo-terminal devices are found in the following directory. */#define PTY_DEV_DIR "/dev/"/* * Pseudo-terminal controller device file names start with the following * prefix. */#define PTY_CNTRL "pty"/* * Pseudo-terminal slave device file names start with the following * prefix. */#define PTY_SLAVE "tty"/* * Specify the maximum suffix length for the control and slave device * names. */#define PTY_MAX_SUFFIX 10/* * Set the maximum length of the master and slave terminal device filenames, * including space for a terminating '\0'. */#define PTY_MAX_NAME (sizeof(PTY_DEV_DIR)-1 + \		      (sizeof(PTY_SLAVE) > sizeof(PTY_CNTRL) ? \		       sizeof(PTY_SLAVE) : sizeof(PTY_CNTRL))-1 \		      + PTY_MAX_SUFFIX + 1)/* * Set the maximum length of an input line. */#define PTY_MAX_LINE 4096/* * Set the size of the buffer used for accumulating bytes written by the * user's terminal to its stdout. */#define PTY_MAX_READ 1000/* * Set the amount of memory used to record history. */#define PTY_HIST_SIZE 10000/* * Set the timeout delay used to check for quickly arriving * sequential output from the application. */#define PTY_READ_TIMEOUT 100000    /* micro-seconds */static int pty_open_master(const char *prog, int *cntrl, char *slave_name);static int pty_open_slave(const char *prog, char *slave_name);static int pty_child(const char *prog, int slave, char *argv[]);static int pty_parent(const char *prog, int cntrl);static int pty_stop_parent(int waserr, int cntrl, GetLine *gl, char *rbuff);static GL_FD_EVENT_FN(pty_read_from_program);static int pty_write_to_fd(int fd, const char *string, int n);static void pty_child_exited(int sig);static int pty_master_readable(int fd, long usec);/*....................................................................... * Run a program with enhanced terminal editing facilities. * * Usage: *  enhance program [args...] */int main(int argc, char *argv[]){  int cntrl = -1;  /* The fd of the pseudo-terminal controller device */  int slave = -1;  /* The fd of the pseudo-terminal slave device */  pid_t pid;       /* The return value of fork() */  int status;      /* The return statuses of the parent and child functions */  char slave_name[PTY_MAX_NAME]; /* The filename of the slave end of the */                                 /*  pseudo-terminal. */  char *prog;      /* The name of the program (ie. argv[0]) *//* * Check the arguments. */  if(argc < 2) {    fprintf(stderr, "Usage: %s <program> [arguments...]\n", argv[0]);    return 1;  };/* * Get the name of the program. */  prog = argv[0];/* * If the user has the LC_CTYPE or LC_ALL environment variables set, * enable display of characters corresponding to the specified locale. */  (void) setlocale(LC_CTYPE, "");/* * If the program is taking its input from a pipe or a file, or * sending its output to something other than a terminal, run the * program without tecla. */  if(!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO)) {    if(execvp(argv[1], argv + 1) < 0) {      fprintf(stderr, "%s: Unable to execute %s (%s).\n", prog, argv[1],	      strerror(errno));      fflush(stderr);      _exit(1);    };  };/* * Open the master side of a pseudo-terminal pair, and return * the corresponding file descriptor and the filename of the * slave end of the pseudo-terminal. */  if(pty_open_master(prog, &cntrl, slave_name))    return 1;/* * Set up a signal handler to watch for the child process exiting. */  signal(SIGCHLD, pty_child_exited);/* * The above signal handler sends the parent process a SIGINT signal. * This signal is caught by gl_get_line(), which resets the terminal * settings, and if the application signal handler for this signal * doesn't abort the process, gl_get_line() returns NULL with errno * set to EINTR. Arrange to ignore the signal, so that gl_get_line() * returns and we have a chance to cleanup. */  signal(SIGINT, SIG_IGN);/* * We will read user input in one process, and run the user's program * in a child process. */  pid = fork();  if(pid < 0) {    fprintf(stderr, "%s: Unable to fork child process (%s).\n", prog,	    strerror(errno));    return 1;  };/* * Are we the parent? */  if(pid!=0) {    status = pty_parent(prog, cntrl);    close(cntrl);  } else {    close(cntrl); /* The child doesn't use the slave device */    signal(SIGCHLD, pty_child_exited);    if((slave = pty_open_slave(prog, slave_name)) >= 0) {      status = pty_child(prog, slave, argv + 1);      close(slave);    } else {      status = 1;    };  };  return status;}/*....................................................................... * Open the master side of a pseudo-terminal pair, and return * the corresponding file descriptor and the filename of the * slave end of the pseudo-terminal. * * Input/Output: *  prog  const char *  The name of this program. *  cntrl        int *  The file descriptor of the pseudo-terminal *                      controller device will be assigned tp *cntrl. *  slave_name  char *  The file-name of the pseudo-terminal slave device *                      will be recorded in slave_name[], which must have *                      at least PTY_MAX_NAME elements. * Output: *  return       int    0 - OK. *                      1 - Error. */static int pty_open_master(const char *prog, int *cntrl, char *slave_name){  char master_name[PTY_MAX_NAME]; /* The filename of the master device */  DIR *dir;                       /* The directory iterator */  struct dirent *file;            /* A file in "/dev" *//* * Mark the controller device as not opened yet. */  *cntrl = -1;/* * On systems with the Sys-V pseudo-terminal interface, we don't * have to search for a free master terminal. We just open /dev/ptmx, * and if there is a free master terminal device, we are given a file * descriptor connected to it. */#if HAVE_SYSV_PTY  *cntrl = open("/dev/ptmx", O_RDWR);  if(*cntrl >= 0) {/* * Get the filename of the slave side of the pseudo-terminal. */    char *name = ptsname(*cntrl);    if(name) {      if(strlen(name)+1 > PTY_MAX_NAME) {	fprintf(stderr, "%s: Slave pty filename too long.\n", prog);	return 1;      };      strcpy(slave_name, name);/* * If unable to get the slave name, discard the controller file descriptor, * ready to try a search instead. */    } else {      close(*cntrl);      *cntrl = -1;    };  } else {#endif/* * On systems without /dev/ptmx, or if opening /dev/ptmx failed, * we open one master terminal after another, until one that isn't * in use by another program is found. * * Open the devices directory. */    dir = opendir(PTY_DEV_DIR);    if(!dir) {      fprintf(stderr, "%s: Couldn't open %s (%s)\n", prog, PTY_DEV_DIR,	      strerror(errno));      return 1;    };/* * Look for pseudo-terminal controller device files in the devices * directory. */    while(*cntrl < 0 && (file = readdir(dir))) {      if(strncmp(file->d_name, PTY_CNTRL, sizeof(PTY_CNTRL)-1) == 0) {/* * Get the common extension of the control and slave filenames. */	const char *ext = file->d_name + sizeof(PTY_CNTRL)-1;	if(strlen(ext) > PTY_MAX_SUFFIX)	  continue;/* * Attempt to open the control file. */	strcpy(master_name, PTY_DEV_DIR);	strcat(master_name, PTY_CNTRL);	strcat(master_name, ext);	*cntrl = open(master_name, O_RDWR);	if(*cntrl < 0)	  continue;/* * Attempt to open the matching slave file. */	strcpy(slave_name, PTY_DEV_DIR);	strcat(slave_name, PTY_SLAVE);	strcat(slave_name, ext);      };    };    closedir(dir);#if HAVE_SYSV_PTY  };#endif/* * Did we fail to find a pseudo-terminal pair that we could open? */  if(*cntrl < 0) {    fprintf(stderr, "%s: Unable to find a free pseudo-terminal.\n", prog);    return 1;  };/* * System V systems require the program that opens the master to * grant access to the slave side of the pseudo-terminal. */#ifdef HAVE_SYSV_PTY  if(grantpt(*cntrl) < 0 ||     unlockpt(*cntrl) < 0) {    fprintf(stderr, "%s: Unable to unlock terminal (%s).\n", prog,	    strerror(errno));    return 1;  };#endif/* * Success. */  return 0;}/*....................................................................... * Open the slave end of a pseudo-terminal. * * Input: *  prog   const char *  The name of this program. *  slave_name   char *  The filename of the slave device. * Output: *  return        int    The file descriptor of the successfully opened *                       slave device, or < 0 on error. */static int pty_open_slave(const char *prog, char *slave_name){  int fd;  /* The file descriptor of the slave device *//* * Place the process in its own process group. In system-V based * OS's, this ensures that when the pseudo-terminal is opened, it * becomes the controlling terminal of the process. */  if(setsid() < 0) {    fprintf(stderr, "%s: Unable to form new process group (%s).\n", prog,	    strerror(errno));    return -1;  };/* * Attempt to open the specified device. */  fd = open(slave_name, O_RDWR);  if(fd < 0) {    fprintf(stderr, "%s: Unable to open pseudo-terminal slave device (%s).\n",	    prog, strerror(errno));    return -1;  };/* * On system-V streams based systems, we need to push the stream modules * that implement pseudo-terminal and termio interfaces. At least on * Solaris, which pushes these automatically when a slave is opened, * this is redundant, so ignore errors when pushing the modules. */#if HAVE_SYSV_PTY

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -