이는 XY 문제일 수 있지만 하나의 직렬 터미널(예: /dev/ttyUSB0)을 두 개의 터미널로 복제하고 싶습니다. 두 터미널 중 하나의 입력은 실제 터미널로 다중화되고 출력은 두 터미널 모두에 공급됩니다. 이를 달성하는 도구가 있습니까/이것이 가능합니까?
나는 종종 직렬을 통해 임베디드 하드웨어와 작업하기 위해 작은 터미널 에뮬레이터를 사용합니다.용어. 대화형 터미널을 항상 열어두고 실행 명령 시퀀스도 사용하고 싶습니다.예상되는위에. 예를 들어 U-Boot 프롬프트에서 다시 시작하고 중지합니다.
나는 다음과 같이 사용되는 도구를 상상합니다.
$ teeterm /dev/ttyUSB0
Clone successful: /dev/pts/3 and /dev/pts/4 available.
$ dterm /dev/pts/3 115200
다른 쉘에서:
$ ./uboot (which spawns and interacts with dterm /dev/pts/4 115200)
답변1
dirkt가 게시한 샘플 코드를 기반으로 이를 위한 실제 유틸리티를 구축했습니다. 이것은Github에서 찾을 수 있습니다.
나는 결국 다음을 사용했습니다.
teeterm dterm /dev/ttyUSB0 115200 (in another shell) dterm pty0 (in another shell) dterm pty1
두 의사 터미널 모두 명령 프로세스 I/O에 액세스할 수 있습니다. 이 유틸리티의 가장 중요한 측면은포크의사 터미널(사용자가 사용할 수 없음) 호출을 통해 하위 프로세스를 제어합니다.열려 있는그리고선택하다두 개의 의사 터미널을 생성하고 세 개의 의사 터미널 모두에 대한 입력을 모니터링하기 위해 호출됩니다.
답변2
요청 시 작은 C 프로그램이 새로 생성된 두 의사 터미널 사이에서 양방향으로 파이프됩니다. 아니요, 이는 질문에 대한 답변은 아니지만 질문에 대한 답변에 쉽게 적용할 수 있습니다. 그리 길지 않으므로 코드는 다음과 같습니다. 라이센스는 "원하는 대로 수행"입니다.
/* ptycat (ptypipe? ptypair?)
*
* create a pair of pseudo-terminal slaves connected to each other
*
* Link with -lutil
*
* Alternative: socat PTY,link=COM8 PTY,link=COM9
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <pty.h>
#undef max
#define max(x,y) ((x) > (y) ? (x) : (y))
/*
(void)ioctl(STDIN_FILENO, TIOCGWINSZ, &win);
*/
/* TODO: make symlinks, unlink on atexit */
static uint8_t buf[BUFSIZ]; /* BUFSIZ from stdio.h, at least 256 */
static char *log_dir = NULL;
void logdata (char *dir, uint8_t *data, int n) {
if (dir != log_dir) fprintf (stdout, "\n%s", dir);
log_dir = dir;
for (; n > 0; n--, data++) fprintf (stdout, " %02x", *data);
fflush (stdout);
}
int main (int argc, char* argv[])
{
char name[256]; /* max namelen = 255 for most fs. */
fd_set rfd;
struct termios tt;
struct winsize ws;
int master[2], slave[2];
int n, nfds, cc;
if (tcgetattr (STDIN_FILENO, &tt) < 0)
{
perror("Cannot get terminal attributes of stdin");
exit(1);
}
cfmakeraw (&tt);
for (int i = 0; i < 2; i++)
{
if (openpty (&master[i], &slave[i], name, &tt, NULL /*ws*/) < 0)
{
perror("Cannot open pty");
exit(1);
}
puts(name);
}
for (;;) {
FD_ZERO(&rfd);
FD_SET(master[0], &rfd);
FD_SET(master[1], &rfd);
nfds = max(master[0], master[1]) + 1;
n = select(nfds, &rfd, 0, 0, NULL);
if (n > 0 || errno == EINTR)
{
if (FD_ISSET(master[0], &rfd))
{
if ((cc = read(master[0], buf, sizeof(buf))) > 0)
{
(void) write(master[1], buf, cc);
logdata (">>>", buf, cc);
}
}
if (FD_ISSET(master[1], &rfd))
{
if ((cc = read(master[1], buf, sizeof(buf))) > 0)
{
(void) write(master[0], buf, cc);
logdata ("<<<", buf, cc);
}
}
}
}
/* This is never reached */
return 0;
}