- 论坛徽章:
- 0
|
程序做了些轻微的改进,主要是自动打开一个伪终端,不用手工指定。
使用命令改为: relay 终端号1 终端号2 ...
编译命令为: cc relay.c -lc -o relay
测试环境仍为: SCO Openserver 5.0.5
- /* 向指定终端转播当前操作 relay.c */
- #include "stdio.h"
- #include "stdlib.h"
- #include "unistd.h"
- #include "fcntl.h"
- #include "signal.h"
- #include "tinfo.h"
- #include "termio.h"
- #include "sys/stream.h"
- #define BUFSIZE 1024
- int console_fd,pty_fd;
- struct termio t_attr;
- /* 退出时,恢复原来的终端属性 */
- void exitproc(int i){
- ioctl(console_fd,TCSETAF,&t_attr);
- printf("\n所有操作已被记录,如要回放请 cat relay.out \n\n");
- exit(0);
- }
- /* 设置终端的低层特性 */
- static void set_console_raw(int fd){
- struct termios buf;
- if(tcgetattr(fd,&buf)<0) exit(-1);
- buf.c_lflag&=~(ECHO|ICANON|IEXTEN|ISIG);
- buf.c_iflag&=~(BRKINT|ICRNL|INPCK|ISTRIP|IXON);
- buf.c_cflag&=~(CSIZE|PARENB);
- buf.c_cflag|=CS8;
- buf.c_oflag&=~(OPOST);
- buf.c_cc[VMIN]=1;
- buf.c_cc[VTIME]=0;
- if(tcsetattr(fd,TCSAFLUSH,&buf)<0) exit(-1);
- }
- main(int argc,char *argv[]){
- int fd_in,fd_out,nread,slave_fd,i;
- int MAX,fd[50]; /* 允许的最大"转播"屏幕数为50个 */
- char *ptr1,*ptr2,ter_name[20];
- char *ptm_name="/dev/ptypXX",*pts_name="/dev/ttypXX";
- fd_set rset,rrset;
- static unsigned char buf[BUFSIZE];
- /* 打开一个空闲的伪终端号 */
- for(ptr1="0123456789abcdef";*ptr1!='\0';ptr1++){
- ptm_name[9]=*ptr1;
- pts_name[9]=*ptr1;
- for(ptr2="0123456789abcdef";*ptr2!='\0';ptr2++){
- ptm_name[10]=*ptr2;
- pty_fd=open(ptm_name,O_RDWR);
- if(pty_fd<=0) continue;
- else{
- pts_name[10]=*ptr2;
- break;
- }
- }
- if(pty_fd>0) break;else ptr2-=16;
- }
- if(pty_fd<=0){
- printf("\n打开伪终端失败,程序无法运行!\n");
- exit(-1);
- }
- /* 打开用于保存输入输出信息用的文件 */
- fd_in=open("./relay.in",O_CREAT|O_RDWR|O_TRUNC,0660);
- fd_out=open("./relay.out",O_CREAT|O_RDWR|O_TRUNC,0660);
- if(fd_out<=0){
- printf("\n无法在当前目录保存操作记录!\n");
- exit(-1);
- }
- printf("\n正在向以下终端\"转播\"操作 ...\n\n");
- for(i=0,MAX=0;MAX<argc-1;MAX++){
- sprintf(ter_name,"/dev/%s",argv[MAX+1]);
- fd[MAX]=open(ter_name,O_WRONLY);
- if(fd[MAX]>0){
- printf("%s ",argv[MAX+1]);
- i++;
- }
- }
- printf("\n\n共 %d 台终端.\n\n",i);
- signal(SIGTERM,exitproc);
- signal(SIGKILL,exitproc);
- signal(SIGCLD,exitproc);
- console_fd=open(ttyname(0),O_RDWR);
- ioctl(console_fd,TCGETA,&t_attr);
- set_console_raw(console_fd);
- switch(fork()){
- case -1: exit(1);
- case 0:
- setsid();
- /* 让子进程以指定的伪终端号运行 */
- slave_fd=open(pts_name,O_RDWR);
- if(slave_fd==-1){
- printf("打开%s出错\n\n",pts_name);
- exit(-1);
- }
- ioctl(slave_fd,TCSETAF,&t_attr);
- dup2(slave_fd,0);
- dup2(slave_fd,1);
- dup2(slave_fd,2);
- close(slave_fd);
- execlp("/bin/sh",NULL);
- }
- FD_ZERO(&rrset);
- FD_SET(console_fd,&rrset);
- FD_SET(pty_fd,&rrset);
- while(1){
- rset=rrset;
- if(select(FD_SETSIZE,&rset,0,0,0)==-1) continue;
- /* 通过伪终端,向子进程转递输入信息,并保存 */
- if(FD_ISSET(console_fd,&rset)){
- nread=read(console_fd,buf,BUFSIZE);
- buf[nread]='\0';
- if(nread>0){
- write(pty_fd,buf,strlen(buf));
- write(fd_in,buf,nread);
- }
- }
- /* 向伪终端读取输出信息,并保存 */
- if(FD_ISSET(pty_fd,&rset)){
- nread=read(pty_fd,buf,BUFSIZE);
- /* 向终端转播输出信息 */
- for(i=0;i<MAX;i++) write(fd[i],buf,nread);
- buf[nread]='\0';
- if(nread>0){
- write(console_fd,buf,strlen(buf));
- write(fd_out,buf,nread);
- }
- }
- }
- }
复制代码 |
|