📄 main.c
字号:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <netdb.h>
#include <fcntl.h>
#include <time.h>
#include <grp.h>
#include <ctype.h>
#include <dirent.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <termios.h>
#include <sys/ioctl.h> /* 44BSD requires this too */
#include <errno.h> /* for definition of errno */
#include <stdarg.h> /* ANSI C header file */
#ifndef TIOCGWINSZ
#include <sys/ioctl.h> /* 44BSD requires this too */
#endif
#define BUFFSIZE 4096*10
#define MAXLINE 4096
static void sig_term(int);
static volatile sig_atomic_t sigcaught; /* set by signal handler */
static void set_noecho(int); /* at the end of this file */
void do_driver(char *); /* in the file driver.c */
void loop(int, int); /* in the file loop.c */
void err_sys(const char *fmt, ...);
void tty_atexit(void);
void err_quit(const char *fmt, ...);
int tty_raw(int fd);
int s_pipe(int fd[2]);
int ptys_open(int fdm, char *pts_name);
int ptym_open(char *pts_name);
int tty_reset(int fd) ;
ssize_t writen(int fd, const void *vptr, size_t n);
typedef void Sigfunc(int); /* for signal handlers */
void signal_intr(int signo, Sigfunc *func);
#if defined(SIG_IGN) && !defined(SIG_ERR)
#define SIG_ERR ((Sigfunc *)-1)
#endif
static int ttysavefd = -1;
static struct termios save_termios;
static enum { RESET, RAW, CBREAK } ttystate = RESET;
char passwd[1024]={0};
int main(int argc, char *argv[])
{
int fdm, c, ignoreeof, interactive, noecho, verbose;
pid_t pid;
char *driver, slave_name[20];
struct termios orig_termios;
struct winsize size;
interactive = isatty(STDIN_FILENO);
ignoreeof = 0;
noecho = 0;
verbose = 0;
driver = NULL;
opterr = 0; /* don't want getopt() writing to stderr */
while ( (c = getopt(argc, argv, "d:einvp:")) != EOF) {
switch (c) {
case 'd': /* driver for stdin/stdout */
driver = optarg;
break;
case 'e': /* noecho for slave pty's line discipline */
noecho = 1;
break;
case 'i': /* ignore EOF on standard input */
ignoreeof = 1;
break;
case 'n': /* not interactive */
interactive = 0;
break;
case 'v': /* verbose */
verbose = 1;
break;
case 'p': /* verbose */
strncpy(passwd,optarg,1023);
break;
case '?':
err_quit("unrecognized option: -%c", optopt);
}
}
if (optind >= argc)
err_quit("usage: pty [ -d driver -einv -p passwd] program [ arg ... ]");
if (interactive) { /* fetch current termios and window size */
if (tcgetattr(STDIN_FILENO, &orig_termios) < 0)
err_sys("tcgetattr error on stdin");
if (ioctl(STDIN_FILENO, TIOCGWINSZ, (char *) &size) < 0)
err_sys("TIOCGWINSZ error");
pid = pty_fork(&fdm, slave_name, &orig_termios, &size);
} else
pid = pty_fork(&fdm, slave_name, NULL, NULL);
if (pid < 0)
err_sys("fork error");
else if (pid == 0) { /* child */
if (noecho)
set_noecho(STDIN_FILENO); /* stdin is slave pty */
if (execvp(argv[optind], &argv[optind]) < 0)
err_sys("can't execute: %s", argv[optind]);
}
if (verbose) {
fprintf(stderr, "slave name = %s\n", slave_name);
if (driver != NULL)
fprintf(stderr, "driver = %s\n", driver);
}
if (interactive && driver == NULL) {
if (tty_raw(STDIN_FILENO) < 0) /* user's tty to raw mode */
err_sys("tty_raw error");
if (atexit(tty_atexit) < 0) /* reset user's tty on exit */
err_sys("atexit error");
}
if (driver)
do_driver(driver); /* changes our stdin/stdout */
loop(fdm, ignoreeof); /* copies stdin -> ptym, ptym -> stdout */
exit(0);
}
static void set_noecho(int fd) /* turn off echo (for slave pty) */
{
struct termios stermios;
if (tcgetattr(fd, &stermios) < 0)
err_sys("tcgetattr error");
stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
stermios.c_oflag &= ~(ONLCR);
/* also turn off NL to CR/NL mapping on output */
if (tcsetattr(fd, TCSANOW, &stermios) < 0)
err_sys("tcsetattr error");
}
void do_driver(char *driver)
{
pid_t child;
int pipe[2];
/* create a stream pipe to communicate with the driver */
if (s_pipe(pipe) < 0)
err_sys("can't create stream pipe");
if ( (child = fork()) < 0)
err_sys("fork error");
else if (child == 0) { /* child */
close(pipe[1]);
/* stdin for driver */
if (dup2(pipe[0], STDIN_FILENO) != STDIN_FILENO)
err_sys("dup2 error to stdin");
/* stdout for driver */
if (dup2(pipe[0], STDOUT_FILENO) != STDOUT_FILENO)
err_sys("dup2 error to stdout");
close(pipe[0]);
/* leave stderr for driver alone */
execlp(driver, driver, (char *) 0);
err_sys("execlp error for: %s", driver);
}
close(pipe[0]); /* parent */
if (dup2(pipe[1], STDIN_FILENO) != STDIN_FILENO)
err_sys("dup2 error to stdin");
if (dup2(pipe[1], STDOUT_FILENO) != STDOUT_FILENO)
err_sys("dup2 error to stdout");
close(pipe[1]);
/* Parent returns, but with stdin and stdout connected
to the driver. */
}
pid_t pty_fork(int *ptrfdm, char *slave_name,
const struct termios *slave_termios,
const struct winsize *slave_winsize)
{
int fdm, fds;
pid_t pid;
char pts_name[20];
if ( (fdm = ptym_open(pts_name)) < 0)
err_sys("can't open master pty: %s", pts_name);
if (slave_name != NULL)
strcpy(slave_name, pts_name); /* return name of slave */
if ( (pid = fork()) < 0)
return(-1);
else if (pid == 0) { /* child */
if (setsid() < 0)
err_sys("setsid error");
/* SVR4 acquires controlling terminal on open() */
if ( (fds = ptys_open(fdm, pts_name)) < 0)
err_sys("can't open slave pty");
close(fdm); /* all done with master in child */
#if defined(TIOCSCTTY) && !defined(CIBAUD)
/* 44BSD way to acquire controlling terminal */
/* !CIBAUD to avoid doing this under SunOS */
if (ioctl(fds, TIOCSCTTY, (char *) 0) < 0)
err_sys("TIOCSCTTY error");
#endif
/* set slave's termios and window size */
if (slave_termios != NULL) {
if (tcsetattr(fds, TCSANOW, slave_termios) < 0)
err_sys("tcsetattr error on slave pty");
}
if (slave_winsize != NULL) {
if (ioctl(fds, TIOCSWINSZ, slave_winsize) < 0)
err_sys("TIOCSWINSZ error on slave pty");
}
/* slave becomes stdin/stdout/stderr of child */
if (dup2(fds, STDIN_FILENO) != STDIN_FILENO)
err_sys("dup2 error to stdin");
if (dup2(fds, STDOUT_FILENO) != STDOUT_FILENO)
err_sys("dup2 error to stdout");
if (dup2(fds, STDERR_FILENO) != STDERR_FILENO)
err_sys("dup2 error to stderr");
if (fds > STDERR_FILENO)
close(fds);
return(0); /* child returns 0 just like fork() */
} else { /* parent */
*ptrfdm = fdm; /* return fd of master */
return(pid); /* parent returns pid of child */
}
}
void loop(int ptym, int ignoreeof)
{
pid_t child;
int nread;
char buff[BUFFSIZE];
char tmp[1024];
FILE *fp;
long long i = 0;
if ( (child = fork()) < 0) {
err_sys("fork error");
} else if (child == 0) { /* child copies stdin to ptym */
for ( ; ; ) {
if ( (nread = read(STDIN_FILENO, buff, BUFFSIZE)) < 0)
err_sys("read error from stdin");
else if (nread == 0)
break; /* EOF on stdin means we're done */
if (writen(ptym, buff, nread) != nread)
err_sys("writen error to master pty");
}
/* We always terminate when we encounter an EOF on stdin,
but we only notify the parent if ignoreeof is 0. */
if (ignoreeof == 0)
kill(getppid(), SIGTERM); /* notify parent */
exit(0); /* and terminate; child can't return */
}
/* parent copies ptym to stdout */
signal_intr(SIGTERM, sig_term);
sleep(1);
for ( ; ; ) {
if ( (nread = read(ptym, buff, BUFFSIZE-4)) <= 0)
break; /* signal caught, error, or EOF */
if(i < 10){
if(strstr(buff,"password:")!= NULL){
sprintf(tmp,"%s\n",passwd);
writen(ptym, tmp, strlen(tmp));
}
if(strstr(buff,"Are you sure you want to continue connecting (yes/no)?"))
{
sprintf(tmp,"%s\n","yes");
writen(ptym, tmp, strlen(tmp));
}
}
if (writen(STDOUT_FILENO, buff, nread) != nread)
err_sys("writen error to stdout");
memset(buff,0,BUFFSIZE);
i++;
}
/* There are three ways to get here: sig_term() below caught the
* SIGTERM from the child, we read an EOF on the pty master (which
* means we have to signal the child to stop), or an error. */
if (sigcaught == 0) /* tell child if it didn't send us the signal */
kill(child, SIGTERM);
return; /* parent returns to caller */
}
/* The child sends us a SIGTERM when it receives an EOF on
* the pty slave or encounters a read() error. */
static void sig_term(int signo)
{
sigcaught = 1; /* just set flag and return */
return; /* probably interrupts read() of ptym */
}
static void err_doit(int errnoflag, const char *fmt, va_list ap)
{
int errno_save;
char buf[MAXLINE];
errno_save = errno; /* value caller might want printed */
vsprintf(buf, fmt, ap);
if (errnoflag)
sprintf(buf+strlen(buf), ": %s", strerror(errno_save));
strcat(buf, "\n");
fflush(stdout); /* in case stdout and stderr are the same */
fputs(buf, stderr);
fflush(NULL); /* flushes all stdio output streams */
return;
}
void err_sys(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, fmt, ap);
va_end(ap);
exit(1);
}
void tty_atexit(void) /* can be set up by atexit(tty_atexit) */
{
if (ttysavefd >= 0)
tty_reset(ttysavefd);
}
void err_quit(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(0, fmt, ap);
va_end(ap);
exit(1);
}
int tty_raw(int fd) /* put terminal into a raw mode */
{
struct termios buf;
if (tcgetattr(fd, &save_termios) < 0)
return(-1);
buf = save_termios; /* structure copy */
buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
/* echo off, canonical mode off, extended input
processing off, signal chars off */
buf.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
/* no SIGINT on BREAK, CR-to-NL off, input parity
check off, don't strip 8th bit on input,
output flow control off */
buf.c_cflag &= ~(CSIZE | PARENB);
/* clear size bits, parity checking off */
buf.c_cflag |= CS8;
/* set 8 bits/char */
buf.c_oflag &= ~(OPOST);
/* output processing off */
buf.c_cc[VMIN] = 1; /* Case B: 1 byte at a time, no timer */
buf.c_cc[VTIME] = 0;
if (tcsetattr(fd, TCSAFLUSH, &buf) < 0)
return(-1);
ttystate = RAW;
ttysavefd = fd;
return(0);
}
int s_pipe(int fd[2]) /* two file descriptors returned in fd[0] & fd[1] */
{
return( pipe(fd) );
}
int ptym_open(char *pts_name)
{
int fdm;
char *ptr1, *ptr2;
strcpy(pts_name, "/dev/ptyXY");
/* array index: 0123456789 (for references in following code) */
for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1 != 0; ptr1++) {
pts_name[8] = *ptr1;
for (ptr2 = "0123456789abcdef"; *ptr2 != 0; ptr2++) {
pts_name[9] = *ptr2;
//printf(pts_name);
/* try to open master */
if ( (fdm = open(pts_name, O_RDWR)) < 0) {
if (errno == ENOENT) /* different from EIO */
return(-1); /* out of pty devices */
else
continue; /* try next pty device */
}
pts_name[5] = 't'; /* change "pty" to "tty" */
return(fdm); /* got it, return fd of master */
}
}
return(-1); /* out of pty devices */
}
int ptys_open(int fdm, char *pts_name)
{
struct group *grptr;
int gid, fds;
if ( (grptr = getgrnam("tty")) != NULL)
gid = grptr->gr_gid;
else
gid = -1; /* group tty is not in the group file */
/* following two functions don't work unless we're root */
chown(pts_name, getuid(), gid);
chmod(pts_name, S_IRUSR | S_IWUSR | S_IWGRP);
if ( (fds = open(pts_name, O_RDWR)) < 0) {
close(fdm);
return(-1);
}
return(fds);
}
int tty_reset(int fd) /* restore terminal's mode */
{
if (ttystate != CBREAK && ttystate != RAW)
return(0);
if (tcsetattr(fd, TCSAFLUSH, &save_termios) < 0)
return(-1);
ttystate = RESET;
return(0);
}
void signal_intr(int signo, Sigfunc *func)
{
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(signo, &act, &oact);
return;
}
ssize_t writen(int fd, const void *vptr, size_t n)
{
size_t nleft, nwritten;
const char *ptr;
ptr = vptr; /* can't do pointer arithmetic on void* */
nleft = n;
while (nleft > 0) {
if ( (nwritten = write(fd, ptr, nleft)) <= 0)
return(nwritten); /* error */
nleft -= nwritten;
ptr += nwritten;
}
return(n);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -