/* * ek -- serial external keyboard :-) for FreeBSD/Linux * * revision history * 0.0: Feb. 5, 2003 by Dai ISHIJIMA * * usage: ek [serial device] * * example: ek /dev/ttyS1 * * see also: source of ``script'' command */ #include #include #include #include #include /* bzero() <- FDZERO() */ #include #include #include #ifndef LINUX #include /* openpty() */ /* -lutil */ #else #include #include #endif #include #include #include #include "tty.h" #ifdef LINUX #define DEFAULT_SHELL "/bin/sh" #ifdef SLZAURUS #define DEFAULT_DEVICE "/dev/ttyS1" /* raw IrDA */ #else #define DEFAULT_DEVICE "/dev/ttyS0" /* COM1: */ #endif #else #define DEFAULT_SHELL "/bin/csh" #define DEFAULT_DEVICE "/dev/ttyd0" /* COM1: */ #endif #define DEFAULT_SPEED 9600 #define RAW_KEYBOARD 'r' #define EK_ENVIRON "EXTERNAL_KEYBOARD" #define EK_VALUE "SERIAL" #define SHELL_ENV "SHELL" #define ENV_OVERWRITE 1 #define RUNNING 'r' #define YES 1 #define NO 0 char *prog; #define shift --argc; ++argv static int childstatus = RUNNING; /* * 仮想端末関連 */ /* 子プロセスとしてシェルを起動する */ void subshell(int master, int slave) { char *keyenv; char *shell; /* すでにキーボードがフックされているか? */ keyenv = getenv(EK_ENVIRON); if (keyenv != NULL) { fprintf(stderr, "%s: may already running %s, ", prog, prog); fprintf(stderr, "environ $%s set, value = %s\r\n", EK_ENVIRON, keyenv); } setenv(EK_ENVIRON, EK_VALUE, ENV_OVERWRITE); /* 起動するシェルを決める */ shell = getenv(SHELL_ENV); if (shell == NULL) { shell = DEFAULT_SHELL; } close(master); login_tty(slave); execl(shell, "sh", "-i", NULL); /* シェルを「対話モード」で起動 */ /* ここから下は実行されないはず… */ fprintf(stderr, "%s: can't start subshell (%s)\r\n", prog, shell); kill(0, SIGTERM); exit(1); } #ifdef LINUX void finish(int dummy) { childstatus = SIGCHLD; } #endif /* 仮想端末を開く */ void pseudoterm(int extkey, int mode) { struct termios t; /* 端末の設定 */ struct termios tsave; /* 端末の設定 */ struct winsize w; /* 端末の画面サイズ */ pid_t child; int nfds; fd_set readfds; struct timeval *timeout = NULL; int n; /* 読み込んだ文字の数 */ int master, slave; char buf[BUFSIZ]; tcgetattr(fileno(stdin), &t); tcgetattr(fileno(stdin), &tsave); ioctl(fileno(stdin), TIOCGWINSZ, &w); if (openpty(&master, &slave, NULL, &t, &w) != 0) { fprintf(stderr, "%s: can't open pty\n", prog); exit(1); } cfmakeraw(&t); t.c_lflag &= ~ECHO; (void)tcsetattr(fileno(stdin), TCSAFLUSH, &t); #ifdef LINUX (void)signal(SIGCHLD, finish); #endif childstatus = RUNNING; child = fork(); if (child < 0) { /* fork失敗 */ fprintf(stderr, "%s: can't fork\n", prog); exit(1); } else if (child == 0) { /* 子プロセス */ subshell(master, slave); } else { /* 元々のプロセス */ fprintf(stderr, "%s: external keyboard now enabled\r\n", prog); while (ttygetc(extkey) != EOF) { ; /* 起動時のごみキャラクタを読み飛ばす */ } while (childstatus == RUNNING) { FD_ZERO(&readfds); FD_SET(master, &readfds); /* 子プロセスの出力を調べる */ FD_SET(fileno(stdin), &readfds); /* 標準入力 (本体キー) を調べる */ FD_SET(extkey, &readfds); /* 外部キーボードを調べる */ nfds = select(master + 1, &readfds, NULL, NULL, timeout); if ((nfds < 0) && (errno != EINTR)) { fprintf(stderr, ">>>if ((nfds < 0) && (errno != EINTR)) {\n"); break; } if ((nfds > 0) && (FD_ISSET(fileno(stdin), &readfds))) { /* 標準入力 (本体キーボード) からのデータを */ /* 子プロセスに書き込む */ n = read(fileno(stdin), buf, BUFSIZ); if (n <= 0) { break; } if (n > 0) { (void)write(master, buf, n); } } if ((nfds > 0) && (FD_ISSET(extkey, &readfds))) { /* 外部キーボードからのデータを子プロセスに書き込む */ n = read(extkey, buf, BUFSIZ); if (n <= 0) { break; } if (n > 0) { (void)write(master, buf, n); } } if (nfds > 0 && FD_ISSET(master, &readfds)) { /* 子プロセスからのデータを標準出力へ書き出す */ n = read(master, buf, BUFSIZ); if (n <= 0) { childstatus = EOF; break; } write(fileno(stdout), buf, n); } } /* while */ if (childstatus == EOF) { fprintf(stderr, "%s: EOF encountered, child process finished\r\n", prog); } else if (childstatus == SIGCHLD) { fprintf(stderr, "%s: caught SIGCHLD, child process finished\r\n", prog); } else { fprintf(stderr, "%s: child process finished\r\n", prog); } fprintf(stderr, "%s: external keyboard now disabled\r\n", prog); } (void)tcsetattr(fileno(stdin), TCSAFLUSH, &tsave); } void usage() { fprintf(stderr, "Usage: %s [option]...\n", prog); } int main(int argc, char *argv[]) { int mode; char *keydev; int fd; int speed; prog = *argv; shift; speed = DEFAULT_SPEED; mode = RAW_KEYBOARD; while ((argc > 0) && (argv[0][0] == '-')) { if (argv[0][1] == 'r') { mode = RAW_KEYBOARD; } else { usage(); exit(1); } shift; } if (argc > 0) { keydev = *argv; } else { keydev = DEFAULT_DEVICE; } fd = opentty(keydev); ttyinit(fd, speed); pseudoterm(fd, mode); closetty(fd); exit(0); } /* Local Variables: */ /* compile-command:"gcc -g -Wall -o ek ek.c tty.c -lutil" */ /* End: */