免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12
最近访问板块 发新帖
楼主: melove
打印 上一主题 下一主题

[C] 求助:在UNIX下如何是C语言实现屏幕映射 [复制链接]

论坛徽章:
0
11 [报告]
发表于 2008-05-04 20:22 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
12 [报告]
发表于 2008-05-04 20:47 |只看该作者
这个办法我也想过,但就是无法解决问题的核心--如何实时的截取shell的输入与输出

论坛徽章:
0
13 [报告]
发表于 2008-05-04 22:15 |只看该作者
太酷了,找到了一篇好文。不敢独享呀。:em11:




在UNIX系统上记录进程输入/输出的方法

                                 

      摘要:本文详细介绍了一种方法,可以记录在UNIX系统的哑终端或伪终端下运
      行的进程的输入和输出, 同时还介绍了在UNIX系统上建立伪终端的方法。本
      文还分析了那些为了管理上的方便而在哑终端上运行程序的不安全的地方。
      关键词:UNIX 管道 进程 哑终端 伪终端 输入/输出

1  引言
    在Windows系统中有一个程序可以记录用户在键盘上输入的每一个键, 从而会泄漏了
用户的密码信息。那么在UNIX系统是否也存在类似的隐患呢? 一般来说,UNIX系统由于比
较安全,很难对任一指定的进程去跟踪并记录用户的输入输出,但是在特定的条件下还是
可以做到的,这个条件就是进程需要在哑终端或伪终端上运行。

2  在哑终端上如何运行进程及记录
2.1  常用的方法
    用UNIX系统命令将一台终端关闭,如disable /dev/tty09,那么这台终端上就不会出
现Login登录画面,这样的终端就是所谓的哑终端。银行的业务系统为了安全起见, 一般
不允许柜台终端出现登录画面,同时也是为了管理的方面,不少业务程序都是在哑终端上
运行的。大概的方法是运行下面要介绍的程序upws,这个程序内部用系统调用execl 函数
来运行业务程序,于是业务进程替换了原来的upws进程(共用一个进程号),然后再将这
个进程的输入输出都重定向到哑终端/dev/tty09上,这样业务程序也就在这台哑终端上运
行起来了。在upws进程被替换之前,它已将该进程的进程号记录在一个与终端同名的临时
文件中,当要删除在某个终端上运行的进程时,就打开这个临时文件,从中读取进程号,
再用kill命令将其杀掉。同时通过命令行参数将终端名送入业务程序,从而可以在终端上
显示出来,当终端出现故障时,业务员可以藉此报告系统管理员,关闭并重新启动这台终
端。启动业务程序trctrl的一个例子如下,trctrl将在系统后台运行。trctrl将从自己进
程的命令行参数argc[1]中获得终端名,并可显示在终端上以通知业务人员。
$upws /usr/mgr/upttylist tty09 vt100 trctrl </dev/tty09 >/dev/tty09 2>&1 &
            /* 程序:upws.c */                     │  fp=fopen(tmpfile,"w");
            #include <stdio.h>                    │  sprintf(command,"TERM=%s",argv[3]);
            main (argc,argv)                      │  putenv(command);/* 设置终端类型 */
            int argc;char *argv[];                │  /* 取当前进程号并存放在临时文件中 */
            {                                     │  fprintf(fp,"%d",getpid());
              FILE *fp;                           │  fclose(fp);
              char tmpfile[128],command[128];     │  /* 执行argv[4]指定的程序,这个程序 */
              /* 生成以终端名命名的临时文件 */    │  /* 将替换当前进程 */
              sprintf(tmpfile,"%s/%s",argv[1],    │  execl(argv[4],argv[4],argv[2],0);
                      argv[2]);                   │}

2.2  利用管道记录进程的输入输出
① 双进程方法
    第一步,父进程ttp首先生成两个管道,然后生成一个子进程ttp1, 在子进程内首先
关闭输入文件句柄0,再分别调用dup2函数将子进程的标准输入重定向到管道p1的读出端
(p1[0]),将标准输出和标准错误输出都重定向到管道p2的写入端(p2[1]),然后调用函数
execl执行业务程序trctrl,这一调用使得进程trctrl覆盖掉原来的子进程ttp1, 从而也
使得trctrl进程的标准输入输出重定向到的两个管道上。重定向标准错误输出(文件句柄2)
是为了能够显示错误信息。
            /* 程序:ttp.c */                      │fdw=open("./abcerr",
            #include <stdio.h>                    │         O_CREAT|O_RDWR|O_TRUNC,0660);
            #include <stdlib.h>                   │ioctl(fd1,TCGETA,&t_attr);
            #include <unistd.h>                   │t_attr.c_cc[VMIN]=1;
            #include <fcntl.h>                    │t_attr.c_cc[VTIME]=0;
            #include <signal.h>                   │ioctl(fd1,TCSETA,&t_attr);
            #include <termio.h>                   │switch(fork()){
            main(){                               │   case -1:exit(1);
              int p,i,fd1,fd2,p1[2],p2[2],n,m;    │   case  0:
              char c,buf[2001],buf1[2001];        │     for(p=0;1;p++){
              int fdw,flags;                      │        m=read(p2[0],buf,sizeof(buf));
              struct termio t_attr;               │        write(fd2,buf,m);buf[m]='\0';
              signal(SIGCLD,SIG_IGN);             │        if(m!=0){
              pipe(p1);                           │           write(fdw,"o=",2);
              pipe(p2);                           │           write(fdw,buf,m);
              fd1=open("/dev/tty09",O_RDONLY);    │           write(fdw,"\n",2);
              fd2=open("/dev/tty09",O_WRONLY);    │        }
              switch(fork()){                     │     }
                case -1:exit(1);                  │   default:
                case 0 :                          │     for(i=0;1;i++){
                  dup2(p1[0],0);                  │        n=read(fd1,buf1,sizeof(buf1));
                  dup2(p2[1],1);                  │        write(p1[1],buf1,n);buf1[n]='\0';
                  dup2(p2[1],2);                  │        if(n!=0){
                  close(p1[0]);close(p1[1]);      │           write(fdw,"i=",2);
                  close(p2[0]);close(p2[1]);      │           write(fdw,buf1,n);
                  execl("/usr/icbacct/bin/trctrl",│           write(fdw,"\n",2);
                     "/usr/icbacct/bin/trctrl",0);│        }
              }                                   │     }
              close(p1[0]);close(p2[1]);          │}
             }                                    │

    第二步,父进程继续打开终端tty09,设置相应的终端属性, 只允许终端一次读取一
个字符,详细说明见参考文献[2]。父进程分别生成两个文件,一个只读(fd1),一个只写
(fd2),然后父进程又生成一个子进程ttp2,这一子进程不断循环地读写文件。 同时父进
程生成一个文件abcerr用来记录业务程序的输入输出。
    第三步,父进程在生成子进程ttp2后自身也不断循环地读写文件,首先,当用户在终
端上击键输入字符时(此时用户的输入并不显示在终端上),父进程从文件fd1读入, 然后
写入管道p1,此时由于进程trctrl的标准输入已经连在该管道的读出端。于是trctrl就开
始读入管道p1内的字符,并通过该进程的标准输出显示字符,但由于标准输出也已经连在
了管道p2的写入端p2[1]上, 所以在第二步时父进程才需要再生成一个子进程专门用来从
管道p2中读取字符并最终显示在终端上(通过写fd2实现)。同时进程trctrl 本身操作数据
库所产生的结果也通过标准输出写入管道p2中,并继续由子进程ttp2从管道中独出并写到
终端,显示给用户。父进程在将字符写入管道p1后,同时将字符也写入文件abcerr中,子
进程ttp2也同样在将字符写到终端后将字符写入文件abcerr中,这样用户就可以这样来运
行业务程序trctrlttp &,这样进程trctrl的全部输入输出都会被记录在这个文件中了。
    以上描述了一个完整的过程,在①时由父进程读取用户的输入,所以可以知道用户所
有的输入内容,包括密码,并将这些内容记录在一个文件中。 在⑥时,子进程ttp2 还可
以事先知道显示的内容(同样这些内容也可以全部记录在同一个文件中),因此,如果在①
时将用户的输入字符'1'改为'2'再写入管道p1将使得进程trctrl以为用户输入的字符就是
'2',从而产生错误的结果,而且在⑥时还可事先将字符又改为'1',然后再显示在终端上,
这样用户也无法知道他输入的字符已经被改为'2'了。
    这一技术的一个应用是可以将用户的击键字符全部记录在一个文本文件中,可以事后
实现程序在无人操作时的自动运行,只要父进程不从终端读字符而改为从文本文件中读字
符就可以了。在分析清楚用户办一笔业务所需输入的全部字符后,我们就可以生成一个文
本文件,从而实现多笔业务在无人操作时的一次性全部完成。比如在代理一个单位的代发
工资时,用户需要给不同的帐号续存不同的金额,我们可以从代理单位的数据库中直接生
成文本,这个文本包括相同的操作码,只是帐号和金额不同。这样的操作还可以控制在某
一特定的时间才开始实际执行,从而实现程序在无人时在某一时间的自动执行。也可以做
到业务过程的重放,此时可以不必运行业务程序,实现脱机运行,相当于演示功能。
    这一技术的另一个有趣的应用是可以实现用户在一个终端上操作,他操作的终端上的
全部输入和输出都可以显示在另外一台终端上,从而实现终端操作的“现场直播”。要实
现这一点其实很简单,只要多打开一个终端tty10,子进程在写到tty09后,再将字符也写
到tty10就可以了。
    还有一个有趣的应用是可以实现一个进程同时在两个终端上运行的“奇观”,即两个
人可以在不同的地方同时使用一个程序,比如有两个人分别管理一个八位密码的前后各四
位,用户A在tty09上输入前四位后,在另外一个地方的用户B由于有"现场直播"功能, 他
就会在自己的终端tty10上看到用户A已经输入了前四位密码,此时一般显示在终端 tty10
上的是四个星号,这时他再输入后四位密码,合作完成了密码的输入工作,然后用户A 就
可继续操作了。要实现这点,子进程ttp2必须多一个读写循环,不断地从tty10 中读字符
并写入管道p1中。进程trctrl只管从p1[0]中读字符, 它根本无从判断这个字符是来自终
端tty09还是tty10。用户也不一定非得先在tty09上输入,操作顺序不必分哪台终端在前,
哪台终端在后。
    同理,我们还可以实现由一台终端(比如tty10)同时监控其余多台终端的操作, 方法
是创建一个共享内存,这个程序在向某一终端写字符后,再判断共享内存中该终端对应的
参数值,如果为1,就将相同字符也写到终端tty10。而共享内存的值则是由另一个控制程
序来设置的。
                ①  ┌───┐ ②p1[1]┌───┐p1[0]
            ┌─→─┤ ttp  ├─→──┤管道p1├─→─┐
            │fd1   └───┘        └───┘      │③标准输入
        ┌─┴─┐                                ┌─┴─┐
用户←→┤tty09 │                                │trctrl├←→数据库
        └─┬─┘                                └─┬─┘
          ⑥│fd2   ┌───┐   ⑤   ┌───┐      │④标准输出
            └─←─┤ ttp2 ├─←──┤管道p2├─←─┘
                    └───┘   p2[0]└───┘p2[1]
                     图1  进程ttp运行时的流程图

论坛徽章:
0
14 [报告]
发表于 2008-05-04 22:16 |只看该作者
② 单进程方法
    这种方法只需要一个额外的进程就可以完成输入输出两项功能,更加有效,但是比较
难于理解。下面举例的是,一个进程同时在两个终端上运行的情况。
    原理主要是利用同步I/O多路转换函数select来实现对两个终端以及管道的检查, 判
断哪个端口有数据可读就读数据,这里选择timeout时间值为0,表示无限制地堵塞,直到
有数据可读。然后在用FD_ISSET来判断具体是哪个端口上有数据可读。
    有的程序在运行时调用ttyname(0)来显示程序的标准输入定向在哪个终端上,为了正
确显示终端名,可以将输入输出直接重定向在fd1和fd2上,比如dup2(fd1,0), 但这样程
序的输入输出就无法截取,所以在其中要通过管道来实现记录。
    一般程序在开始运行时总是先显示一些内容(因为此时程序的标准输出是p2[1],显示
实际上是将这些内容通过p2[1]写入管道p2中),然后用户才敲击键盘输入数据。所以一开
始总是p2[0]最新有数据,于是就被父进程读出,再写到终端文件fd2和fd4中, 这样这些
内容就同时显示在tty09和tty10上。管道中的内容一经读出就不再存在了,这是管道的特
点。如果不从fd3中读数据,则tty10不参与操作,只能实现“转播”的效果。运行方法也
是 ttp1 &
            /* 程序:ttp1.c */                     │  ioctl(fd1,TCSETA,&t_attr);
            #include <stdio.h>                    │  ioctl(fd3,TCSETA,&t_attr);
            #include <stdlib.h>                   │  FD_ZERO(&rrset);
            #include <unistd.h>                   │  FD_SET(p2[0],&rrset);
            #include <fcntl.h>                    │  FD_SET(fd1,&rrset);
            #include <signal.h>                   │  FD_SET(fd3,&rrset);
            #include <termio.h>                   │  while(1){
            int exitprog();                       │    rset=rrset;
            int exitprog(){                       │    if(select(FD_SETSIZE,&rset,0,0,0)==-1)
                exit(0);                          │       continue;
            }                                     │    if(FD_ISSET(p2[0],&rset)){
            main(){                               │       n=read(p2[0],buf,sizeof(buf));
              int fdw,fd1,fd2,fd3,fd4,n;          │       buf[n]='\0';
              int p1[2],p2[2];char buf[2001];     │       if(n>0) write(fd2,buf,strlen(buf));
              struct termio t_attr;               │       if(n>0) write(fd4,buf,strlen(buf));
              fd_set rset,rrset;                  │       if(n>0){   /* 记录屏幕输出 */
              setpgrp();                          │          write(fdw,"o=",2);
              signal(SIGCLD,exitprog);            │          write(fdw,buf,n);
              pipe(p1);                           │          write(fdw,"\n",2);
              pipe(p2);                           │       }
              fd1=open("/dev/tty09",O_RDONLY);    │    }
              fd3=open("/dev/tty10",O_RDONLY);    │    if(FD_ISSET(fd1,&rset)){
              fd2=open("/dev/tty09",O_WRONLY);    │       n=read(fd1,buf,sizeof(buf));
              fd4=open("/dev/tty10",O_WRONLY);    │       buf[n]='\0';
              switch(fork()){                     │       if(n>0) write(p1[1],buf,strlen(buf));
                case -1:exit(1);                  │       if(n!=0){ /* 记录键盘输入 */
                case 0 :                          │          write(fdw,"i=",2);
                  setsid();                       │          write(fdw,buf,n);
                  dup2(p1[0],0);                  │          write(fdw,"\n",2);
                  dup2(p2[1],1);                  │       }
                  //dup2(p2[1],2);                │    }
                  close(p1[0]);close(p1[1]);      │    if(FD_ISSET(fd3,&rset)){
                  close(p2[0]);close(p2[1]);      │       n=read(fd3,buf,sizeof(buf));
                  execl("/usr/tese/bin/tese",     │       buf[n]='\0';
                        "/usr/tese/bin/tese",0);  │       if(n>0) write(p1[1],buf,strlen(buf));
              }                                   │       if(n!=0){ /* 记录键盘输入 */
              close(p1[0]);                       │          write(fdw,"i3=",3);
              close(p2[1]);                       │          write(fdw,buf,n);
              fdw=open("./abcerr",                │          write(fdw,"\n",2);
                    O_CREAT|O_RDWR|O_TRUNC,0660); │       }
              ioctl(fd1,TCGETA,&t_attr);          │    }
              t_attr.c_cc[VMIN]=1;                │  }
              t_attr.c_cc[VTIME]=0;               │}

    如果业务进程在运行后也生成子进程也将是同样有效的,因为生成的子进程也会继承
父进程的标准输入和输出。如在银行综合业务系统中,在启动终端后先运行tese进程,
这个进程又生成进程tese_nase,这个新进程还会再生成一个子进程tese_nase,实验证明
在这种情况下,上述程序一样有效,但在SCO OpenServer 5.05的ksh界面下运行时要去掉
dup2(p2[1],2)这条语句,否则会造成当前终端不正常。上面的双进程方法在ksh界面下无
法正常运行tese程序,但在普通的sh界面下可以。
    当然用一个进程来同时记录在不同终端上的不同业务进程也是可能的,无非是多创建
一些子进程和管道。

3  在伪终端上记录进程的输入输出
    创建伪终端时并不使用管道技术,而是使用dup2函数,将生成的子进程的标准输入输
出以及标准错误输出都转移到终端文件句柄中。
    直接运行 vtp,不必在后台运行。比如在tty03上运行后,用tty命令就可发现现在
的终端已经是/dev/ttyp2,其中的字母“p”,即表示伪终端(pseude),用exit 命令或用
ctrl+d退出时,终端恢复正常。因为vtp通过调用函数ttyname(0)获得当前终端名字, 如
果vtp在后台运行,这个函数就返回空值,使得程序无法正常运行。 因为要生成的子进程
是/bin/sh解释命令,所以同样要复制标准错误输出(stderr)到终端文件中。
    因为伪终端实际上并不接收用户输入,我们实际上是借用正常终端的输入,再将这些
输入的字符写到伪终端设备上,sh在伪终端上运行,由父进程将在伪终端上显示的内容写
到正常终端上。伪终端是一个以成对方式操作的软设备: 送往某对的一个成员的输出被送
给该对另一个成员的输入。 比如/dev/ptyp2和/dev/ttyp2,其中的ptyp2用来连接到真实
终端tty03,父进程打开当前终端(ttyname(0))和ptyp2,然后在这两个设备上等待读取数
据。父进程读取用户在终端tty03上输入的字符并写入设备/dev/ptyp2,而ptyp2的输出就
是ttyp2的输入,这样ttyp2就接收到用户输入的字符。 反之ttyp2的输出又是ptyp2 的输
入,这样父进程再读取ptyp2的内容,这这些内容写到真实终端上,这样ttyp2的输出就会
显示出来。由于子进程运行的是sh进程,该进程一开始显示提示字符$或#,所以父进程先
读取ptyp2的内容,这样提示字符就显示出来了。从中可以看出ptyp2起到类似双向管道的
作用,利用这个软设备沟通真实终端和伪终端。ptyp2和ttyp2之间的操作由操作系统自动
完成。在伪终端上运行的其他任何进程的输入输出也会全部被记录下来。
    下面程序不但实现记录进程输入输出的功能,还能实现类似DOS下的F3键功能, 可以
通过shift+F1来重复命令。注意其中的'^['和'^M'是一个字符,UNIX下F3键是"^[[O"。
    首先将当前终端的属性记录下来,用来设置ttyp2的属性, 同时对当前终端作必要的
设置,让它成为一个原始终端。 再退出时再用保存的终端属性恢复。 其中有一点需要注
意,原来sh的提示符是通过stderr输出的,所以子进程的stderr也要重定向到ttyp2上。
          ⑴┌─────┐      ┌─────┐      ┌─────┐
    用户←→┤/dev/tty03├──→┤/dev/ptyp2├──→┤/dev/ttyp2│
            │父进程vtp ├←──┤  (管道)  ├←──┤ /bin/sh  │
            └─────┘    ⑵└─────┘      └─────┘
               真实终端                       伪终端
                         图2 伪终端的运行过程图

    在另一个终端上查看进程运行情况,可以发现有一个sh进程在伪终端/dev/ttyp2上运
行,这个进程是由在tty03上运行的vtp进程生成的。我们还可以使用stty -a或stty -g来
查看终端的属性。
            # ps -t03                             │ # ps -tp2
              PID TTY     TIME    COMMAND         │   PID TTY     TIME    COMMAND
              379 03      0:01    sh              │   575 p2      0:00    sh
              574 03      0:00    vtp             │

/* 程序: vtp.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 4096
int console_fd,pty_fd;
struct termio t_attr;
int exitproc();
char pttyname[]="/dev/ptyp2";
exitproc(){
  ioctl(console_fd,TCSETAF,&t_attr);
  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 fdw,i,nread,slave_fd;
  fd_set rset,rrset;
  static unsigned char buf[BUFSIZE],cmd[255],buf1[255];
  signal(SIGTERM,exitproc);/* kill -15 vtp_pid */
  signal(SIGKILL,exitproc);/* kill -9 vtp_pid 无效,不能被捕捉或忽略 */
  signal(SIGCLD,exitproc); /* kill -9 pty's sh_pid */
  /* SIGCLD,在子进程(伪终端)退出后,exitproc会处理好返回到正常的终端 */
  console_fd=open(ttyname(0),O_RDWR);
  ioctl(console_fd,TCGETA,&t_attr);
  set_console_raw(console_fd);
  pty_fd=open(pttyname,O_RDWR);
  fdw=open("./abcerr",O_CREAT|O_RDWR|O_TRUNC,0660);
  switch(fork()){
    case -1: exit(1);
    case 0 :
      setsid(); /* execlp进程在ttyp2上运行 */
      slave_fd=open("/dev/ttyp2",O_RDWR);
      if(slave_fd==-1){
         printf("打开%s出错,可能与它的执行权限有关!\n",pttyname);
         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","/bin/sh",NULL);
  }
  FD_ZERO(&rrset);
  FD_SET(console_fd,&rrset);
  FD_SET(pty_fd,&rrset);
  i=0;
  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(strcmp(buf,"^[[Y")==0){ /* shift+F1 */
          strcpy(buf,cmd);
          i=strlen(cmd);
          if(nread>0) write(pty_fd,buf,strlen(buf));
          continue;
       }
       if(nread>0) write(pty_fd,buf,strlen(buf));
       /* 记录输入 */
       if(nread>0){
          write(fdw,"i=",2);
          write(fdw,buf,nread);
          write(fdw,"\n",2);
          if(buf[0]=='^M'){ /* 回车键 */
             cmd='\0';
             i=0;
          }else
          cmd[i++]=buf[0];
       }
    }
    if(FD_ISSET(pty_fd,&rset)){
       nread=read(pty_fd,buf,BUFSIZE);
       buf[nread]='\0';
       if(nread>0) write(console_fd,buf,strlen(buf)); /* #,$也在此输出 */
       /* 记录输出 */
       if(nread>0){
          write(fdw,"o=",2);
          write(fdw,buf,nread);
          write(fdw,"\n",2);
       }
    }
  }
}

4  防止进程被跟踪的方法
    可以在业务程序和终端激活程序之间建立一种联系,最简单的方法是采用启动密码的
方法,比如如下程序。
            /* 程序:upws.c */                     │  fp=fopen(tmpfile,"w"));
            #include <stdio.h>                    │  sprintf(command,"TERM=%s",argv[3]);
            main (argc,argv)                      │  putenv(command);/* 设置终端类型 */
            int argc;char *argv[];                │  /* 取当前进程号并存放在临时文件中 */
            {                                     │  fprintf(fp,"%d",getpid());
              FILE *fp;                           │  fclose(fp);
              char tmpfile[128],command[128];     │  /* 执行argv[4]指定的程序,这个程序 */
              /* 生成以终端名命名的临时文件 */    │  /* 将替换当前进程 */
              sprintf(tmpfile,"%s/%s",argv[1],    │  execl(argv[4],argv[4],argv[2],"123",0);
                      argv[2]);                   │}
    其中的“123”为启动密码,在业务程序trctrl开始运行时就要检查这个密码, 如果
不符则退出。这个密码不能出现在upws的命令行中。

论坛徽章:
0
15 [报告]
发表于 2008-05-04 22:33 |只看该作者
原帖由 melove 于 2008-5-4 17:42 发表
楼上的版主做过不?单单MAN好像还不够呀。

我的意思是,让你去找跟tty相关的东西,google,或看书。

论坛徽章:
0
16 [报告]
发表于 2008-05-05 12:17 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP