1. 터미널이란?
다른 사람은 잘 모르겠는데, 인터넷이나 다른 서적에서 터미널에 대한 정의는 다양하다.
하지만 그 내용만으로는 잘 정리가 되지 않는다. 개인적으로 나는 아래와 같이 정리하고 싶다.
터미널을 크게 로컬연결과 원격연결로 구분하고 싶다. 로컬 연결은 실제적으로 RS232C나 USB등으로
메인 프레임 역활을 수행하는 장치에 위의 장치를 연결하여 입출력이 가능하도록 기능을 제공하는 것을
터미널이라고 정리하고 싶다.
원격의 경우에는 로컬과 달리 네트워크 스택이 추가적으로 포함되야하며 또한 터미널과 같은 입출력
기능을 제공해야 한다. 이런 경우는 기존 터미널 개념으로 접근하기 힘들며 이 때 나온 것이
가상터미널이라는 개념이다. 정리하면 원래 터미널 기능에 다른 추가적인 기능을 추가한 것을 '
가상터미널로 구분하고 기존 터미널 개념과 구분하고 싶다.
2. tty (teletype)
시스템(유닉스/리눅스)상에서 /dev/ttyn 의 문자 디바이스가 있다.
이 문자 디바이스는 터미널에 입출력 기능을 제공하는 커널단의 모듈이다.
따라서 터미널 기능을 담당하는 프로그램은 위의 문자 디바이스를 열어서 구현했다.
시간이 지나면서 입출력 장치가 다양해지면서 RS232C나 USB등도 지원하면서 문자 디바이스는
/dev/ttyS(x), /dev/ttyUSBx 형태의 문자디바이스도 추가되었다.
3. 터미널 드라이버
커널의 디바이스 드라이버의 배경 지식이 필요하기는 하나 위의 디바이스를 실제
응용단에서 제어하고 입출력을 하기위해서는 디바이스 드라이버를 통해서 수행한다.
각 디바이스 드라이버는 기본적으로 제공된다고 보고 이런 디바이스 드라이버를 제어하기 위한
표준화된 라이블러리가 있다. 여기서는 그런 라이블러리 사용법에 대해서 알아본다.
4. 터미널 입력 모드
터미널은 다양한 오퍼레이션을 제공하는데, 오퍼레이션이 입력 모드에 따라서 다르게 동작한다.
입력 모드와 입력 모드의 기본 오퍼레이션은 아래와 같다.
- 줄 단위로 터미널 입력을 처리하며, 줄 편집이 활성화되어 있다. 정규 모드는 기본 입력 모드이다.
- 비정규 모드 (Noncanonical Mode)
- 줄 단위 편집이 아닌 문자 단위 편집 기능을 제공한다.
터미널은 일반 문자 뿐만 아니라 다양한 특수 문자도 해석하며 특수 문자는 고유의 기능이 있다.
예로 CTRL+C는 터미널상에서 인터럽트로 해석된다.
5. 터미널 속성 읽기 및 수정을 위한 표준 라이블러리 함수
#include <termios.h>
int tcgetattr(int fd, struct termios *termios_p);
int tcsetattr(int fd, int optional_action, const struct termios *termios_p);
성공하면 '0'을 리턴, 에러가 발생하면 '-1'을 리턴
5.1. optional_action
- 변경 사항이 즉시 적용되도록 한다.
- 속성 변경 전에 모든 입출력 작업 완료하고 속성 변경을 적용한다 .
- TCSADRAIN와 유사하나 변경 시점의 입출력 대기중이 내용은 버린다.
5.2. 구조체
struct termios
{
tcflag_t c_iflag; /* 입력 플레그 */
tcflag_t c_oflag; /* 출력 플레그 */
tcflag_t c_cflag; /* 제어 플레그 */
tcflag_t c_lflag; /* 로컬 모드 */
cc_t c_line; /* 라인 규칙 */
cc_t c_cc[NCCS]; /* 터미널 특수 문자 */
speed_t c_ispeed; /* 입력 속도 (비표준, 미사용) */
speed_t c_ospeed; /* 출력 속도 (비표준, 미사용) */
};
6. 기타 정보
리눅스에서 /dev/console, /dev/tty 와 /dev/tty0의 차이점에 대해서 알아본다.
부팅 시에 실제 터미널로 사용되는 /dev/console이지만 /dev/ttyx에
추가적으로 콘솔과 같은 기능을 제공한다. 이를 가상 콘솔이라고 한다. 너무 용어가 많아서 햇깔린다.
- /dev/console : 부팅 시 사용하는 실제 터미널이다.
- /dev/tty[1-x] : 로그인 세션에서 터미널을 계속 열었을 때 추가되는 터미널
콘솔간의 이동은 ALT + (F1 ~ F6) 이고 XWindow 환경은 F7에 매핑되어 있다.
7. 예제
7.1. Enter키 입력없이 문자 입력과 동시에 옵션 값 출력하는 예제
입력 모드를 비 정규 모드로 전환하고 입력버퍼의 내용을 바로 출력버퍼로 복사하는
ECHO 기능을 비활성화 했다는 점이 포인트이다.
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
typedef enum {FALSE, TRUE} bool;
int getch(void)
{
int ch;
struct termios buf;
struct termios save;
tcgetattr(0, &save);
buf = save;
buf.c_lflag &= ~(ICANON|ECHO);
buf.c_cc[VMIN] = 1;
buf.c_cc[VTIME] = 0;
tcsetattr(0, TCSAFLUSH, &buf);
ch = getchar();
tcsetattr(0, TCSAFLUSH, &save);
return ch;
}
int main(int argc, char *argv[])
{
char ch;
bool exit;
printf("Insert Option \n");
do
{
ch = getch();
if(ch == 'q')
exit = FALSE;
printf("ch = %c \n", ch);
}
while(exit);
return 0;
}
7.2. 터미널의 윈도우 창 변경 시에 시그널이 발생함을 확인할 수 있는 예제이다.
/*
* main.c -- C Test App.
*
* Copyright (C) 2012-2013, 2013 heesoon.kim <chipmaker.tistory.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
#include <termios.h>
#include <signal.h>
static int sighandler(int sig)
{
printf("%s\n", strsignal(sig));
}
int main(int argc, char *argv[])
{
struct sigaction sa;
struct winsize ws;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = sighandler;
if(sigaction(SIGWINCH, &sa, NULL) == -1)
{
perror("sigaction");
exit(EXIT_FAILURE);
}
printf("tty name =%s \n", ttyname(STDIN_FILENO));
for(;;)
{
pause();
if(ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
{
perror("sigaction");
exit(EXIT_FAILURE);
}
printf("SIGWINCH, new windown size : %d rows %d colums\n", ws.ws_row, ws.ws_col);
}
exit(EXIT_SUCCESS);
}
8. Reference
자세한 API관련 내용은 아래 링크 내용을 참조하면 많은 도움이된다.
http://www.joinc.co.kr/modules/moniwiki/wiki.php/article/termios