터미널입출력 Chapter #8
강의목차 리눅스장치파일 리눅스장치파일제어 단말기장치속성정보얻기 단말기장치속성정보설정 비정규입력처리 예제프로그램 Unix System Programming 2
리눅스장치파일 (1) 리눅스장치파일 (Linux Device File) 리눅스시스템에서는저장장치에저장된파일이나디렉토리그리고모든입출력장치를동일하게파일로취급 리눅스장치파일 입출력장치를접근하기위해제공하는특수파일 모든입출력장치에대해일관성있고유일한소프트웨어인터페이스를제공함으로써장치접근프로그램작성을용이하게함 /dev 시스템디렉토리에모든장치파일을제공되며정규파일과같은방식으로접근가능 장치파일명은 장치표시명 (3문자)+serial number 로구성 예 : hda1, hda2, dsp, eth0 등 Unix System Programming 3
리눅스장치파일 (2) 리눅스장치파일 (Linux Device File) 종류 문자형장치파일 문자단위의데이터입출력을지원하는장치파일 터미널장치파일, 프린터장치파일, 사운드장치파일등 파일타입문자 : c 블록형장치파일 블록단위의데이터입출력을지원하는장치파일 하드디스크장치파일, 비디오장치파일등 파일타입문자 : b 네트워크장치파일 네트워크통신프로토콜을지원하는특수한형태의장치파일 소켓파일등 파일타입문자 : s Unix System Programming 4
리눅스장치파일 (3) 리눅스장치파일의입출력인터페이스 장치파일에대한입출력인터페이스는정규파일과거의동일 물리적인장치의설정이나고유기능을접근하기위한인터페이스를제외하고는모두가동일하다 접근인터페이스 open() 장치파일열기 close() 장치파일닫기 read() 장치파일로부터데이터읽기 write() 장치파일로데이터쓰기 lseek() 일반적으로지원하지않음 ioctl() 물리적인장치의설정이나고유기능에대한접근 Unix System Programming 5
리눅스장치파일 (4) 리눅스장치파일의입출력인터페이스 입출력컨트롤러 Unix System Programming 6
단말기장치 단말기장치파일 (1) 컴퓨터와사용자사이에인터페이스를제공하는하드웨어장치 키보드, CRT 터미널등으로구성 컴퓨터와의물리적인연결 시리얼라인을이용한직접적인연결 모뎀과전화선을이용한원격접속 컴퓨터와의통신방식 보통컴퓨터와 ASCII 코드를사용하여통신 비동기프로토콜을사용하여문자단위전송지원 전이중 (full-duplex) 통신이가능 터미널화면에문자가출력되는동안에키보드입력이가능 일반적으로단말기장치는 dumb device 로다룬다 Unix System Programming 7
단말기장치파일 (2) 단말기장치파일 /dev/ttyxx 형태로제공 현재사용중인단말기를위한장치파일 : /dev/tty 단말기장치드라이버 일반적인입출력인터페이스제공 입출력문자매핑 (character mapping) 과입력버퍼링 (buffering) 을수행 프로그램이입력된문자를읽어가지않은상태에서도새로운입력을받아들일수있도록지원 서로다른상황에서각기다르게입출력포트를구성 (configure) 할수있도록지원 stty a 명령을통해현재단말기장치에대한구성을살펴볼수있다 Unix System Programming 8
단말기입출력방식 단말기입출력방식 단말기장치드라이버에서제공하는입출력방식정규형입력모드 (Canonical Input Mode) 비정규형입력모드 (Non-canonical Input Mode) echoing Unix System Programming 9
단말기장치입출력인터페이스 단말기장치입출력인터페이스 open() 단말기장치열기 close() 단말기장치닫기 read() 단말기장치에서데이터읽기 write() 단말기장치로데이터쓰기 lseek() 지원하지않음 Unix System Programming 10
ioctl() 시스템호출 단말기장치제어 (1) 장치입출력제어시스템호출 장치파일에대해장치와관련된하드웨어옵션과드라이버와관련된소프트웨어옵션을설정하기위해제공되는인터페이스 장치고유의명령어에대한일반적이고총괄적인진입점을제공 ioctl() 시스템호출안에서장치고유의다양한여러종류의기능을제공 ioctl() 시스템호출의제공되는기능은장치마다다르기때문에정확한장치파일을접근하여야한다 Unix System Programming 11
단말기장치제어 (2) 장치파일제어 ioctl() #include <unistd.h> #include <termio.h> int ioctl(int fd, int request, struct termio *tbuf) /* int fd : 장치파일디스크립터 */ /* int request : 장치제어명령 */ /* struct termio *tbuf : 장치제어정보를저장하는구조체 */ /* 정상종료되면음이아닌값을반환하고, 에러인경우에는 -1 를반환한다. errno 에에러를나타내는값을설정한다 */ 입출력장치를제어한다 두번째인자 request 에따라세번째인자에참조하는장치의속성정보를가져오거나새로운속성정보를시스템에설정한다 Unix System Programming 12
단말기장치제어 (3) 장치제어명령어 (request) 명령어 (cmd) 기능반환값 TCGETA TCSETA 단말기장치속성정보를가져와세번째인자 tbuf 에저장하여반환한다 단말기장치의속성정보를새롭게설정한다 TCSETAW TCSETAF 단말기장치의속성정보를새롭게설정하기전에출력이끝나기까지기다린다 단말기장치의속성정보를새롭게설정하기전에출력이끝나기까지기다린다름입력버퍼를비우고속성을설정한다 TCFLUSH 입출력버퍼를비운다 (tbuf=0: 입력버퍼, tbuf=1: 출력버퍼, tbuf=2: 입출력버퍼 ) TCXONC TCBRK 단말기장치에대한데이터전송흐름제어를수행한다 Break 전송을설정한다 참고 : 상기의제어명령어은단말기장치에대한제어명령어국한되며, 입출력장치별로독자적인제어명령어를갖는다 Unix System Programming 13
단말기장치제어 (4) 단말기장치속성구조체 termio 단말기장치속성을읽어오거나새롭게설정할때사용하는구조체 #define NCC 8 struct termio { unsigned short int c_iflag; /* 입력모드플래그 */ unsigned short int c_oflag; /* 출력모드플래그 */ unsigned short int c_cflag; /* 제어모드플래그 */ unsigned short int c_lflag; /* 로컬모드플래그 */ unsigned char c_line; /* 행제어 */ unsigned char c_cc[ncc]; /* 제어문자 */ Unix System Programming 14
단말기장치제어 (5) 단말기장치속성구조체 termio (cont d) c_cc[ncc] 단말기장치제어문자을지정 배열인덱스 제어문자이름 제어문자값 (Default) 제어문자값 (Normal) 설명 0 INTR DEL(^?) CTRL-C(^C) SIGINT 시그널을생성하여전송 1 QUIT CTRL-\(^\) CTRL-\(^\) SIGQUIT 시그널을생성하여전송 2 ERASE # DEL(^?) 입력된한문자를삭제. LF, EOL, EOF 문자는삭제할수없다 3 KILL @ CTRL-U(^U) 입력된줄전체를삭제 4 EOF CTRL-D(^D) CTRL-D(^D) End of File VMIN 비정규입력모드에서최소입력문자수를지정 5 EOL NUL NUL End of Line VTIME 6 Reserved 7 SWITCH SUB SUB 비정규입력모드에서최소입력대기시간을지정 현재수행중인작업을중지하고쉘로돌아간다 (suspend) Unix System Programming 15
단말기장치제어 (6) 단말기장치속성구조체 termio (cont d) 그외의단말장치제어문자 제어문자설정값설명 STOP CTRL-S(^S) 화면출력을중단 START CTRL-Q(^Q) 화면출력을재개 New Line(NL) LF(0x0A) 줄넘김 참고 : (Ctrl key + Alphabetic key) 입력코드 ctrl+a (^A) : 0x01, ctrl+b (^B) : 0x01,, ctrl+z(^z):0x1a ctrl+\(^\) : 0x1c Unix System Programming 16
단말기장치제어 (7) 단말기장치속성구조체 termio (cont d) 입력모드플래그 c_iflag - 입력문자를처리하는모드를지정 플래그의미 IGNBRK BRKINT PARMRK ISTRIP INLCR IGNCR ICRNL IUCLC IXON 브레이크상태를무시한다브레이크할때에인터럽트시그널을보낸다패리티에러의도장을표시한다 8비트문자를 7비트로스트립한다 LF 문자를 CR 문자로변환한다 CR 문자를무시한다 CR 문자를 LF 문자로변환한다대문자를소문자로변환한다흐름제어를수행한다 Unix System Programming 17
단말기장치제어 (8) 단말기장치속성구조체 termio (cont d) 출력모드플래그 c_oflag 출력문자처리및출력동작방식을지정 주요출력모드플래그 : 플래그의미 OPOST OLCUC OCRNL ONLCR ONOCR ONLRET OFILL OFDEL 출력문자를후처리한다소문자를대문자로변환한다 CR 문자를 LF 문자로변환한다 LF 문자를 CR+LF 문자로변환한다 0번째열에서 CR 문자를출력하지않는다 LF 문자가 CR 문자기능을수행하도록지정지연기간동안시간지연대신에 FILL 문자를전송한다 FILL 문자로 DEL 문자를지정한다 Unix System Programming 18
단말기장치제어 (9) 단말기장치속성구조체 termio (cont d) 제어모드플래그 c_cflag 전송제어에관련한모드를설정 주요제어모드플래그 : 플래그의미 CBAUD CSIZE CSTOPB PARENB PARODD 데이터전송속도 (bps: bits per second) 를지정한다 B0, B50,, B9600 데이터길이를지정한다 CS5, CS6, CS7, CS8 정지비트를 2 비트로지정. 지정하지않으면 1 비트를가짐 패리티비트를유효하게한다 홀수피리티비트를지정한다. 지정하지않으면짝수패리티비트가된다 Unix System Programming 19
단말기장치제어 (10) 단말기장치속성구조체 termio (cont d) 로컬모드플래그 c_lflag Unix 내부처리에대한동작모드를지정 주요로컬모드플래그 : 플래그의미 ISIG ICANON ECHO ECHOE ECHOK ECHONL NOFLSH 시그널처리가가능하게한다정규입력처리를지정한다에코를지정한다 ERASE( 삭제 ) 문자를 BS-SP-BS로하여에코한다 KILL 문자를 LF 문자로하여에코한다 LF 문자를에코한다 INTR 또는 QUIT 다음의 flush 기능을불가능하게지정한다 Unix System Programming 20
단말기장치속성정보읽기 단말기장치의속성정보읽기 교재 pp. 247 예제프로그램 : gettermat.c 시스템명령어 stty # stty -a Unix System Programming 21
단말기장치속성정보설정 (1) 단말기장치의속성정보설정 일반적인속성설정과정 1 2 3 4 5 6 설정되어있는속성정보를읽어온다얻은속성정보를보존한다원하는속성정보를변경한다바꾼속성정보를설정한다원하는작업을수행한다보존해둔속성정보를복원한다 단말기장치의속성정보변경 원하는플래그값을 set 또는 reset 예 : c_lflag = ECHO // echo 모드설정 c_lflag &= ~ECHO // echo 모드해제 Unix System Programming 22
단말기장치속성정보설정 (2) 예제프로그램 #1 단말기의시그널및 echo 설정을사용하여화면잠금기능을수행하는프로그램 #include <stdio.h> #include <signal.h> #include <termio.h> #include <unistd.h> #define 256 int main(void) { struct termio tty; unsigned short savflags; char key[bufsiz], *getkey(); int i; for(i=0; i < NSIG; i++) signal(sighup, SIG_IGN); signal(sighup, SIG_DFL); Unix System Programming 23
단말기장치속성정보설정 (3) 예제프로그램 #1 (cont d) ioctl(fileno(stdin), TCGETA, &tty); savflags = tty.c_lflag; tty.c_lflag &= ~(ISIG ECHO); ioctl(fileno(stdin), TCSETAF, &tty); strcpy(key, getkey()); for(;;) if(strcmp(key, getkey()) == 0) { tty.c_lflag = savflags; ioctl(fileno(stdin), TCSETA, &tty); break; exit(0); char *getkey() { static char line[bufsiz]; fputs("enter password: ", stderr); line[0] = '\337'; /* impossible char */ fgets(line, BUFSIZ, stdin); fputs("\n",stderr); return(line); Unix System Programming 24
단말기장치의입력모드 비정규입력 (1) 단말기장치드라이버에서제공하는입력모드 정규입력 (Canonical Input) 라인단위입력을지원 NL(new-line) 문자가입력될때까지입력된문자를원시버퍼에저장하였다가일련의전처리과정을거친후, 정규버퍼에넘겨입력을요구한프로그램에전달하는입력방식 C 라이브러리등에서제공하는일반적인입력방식 비정규입력 (Non-Canonical Input) NL과같은특수문자를기다리지않고한문자가입력되는즉시정규버퍼에넘겨입력을요구한프로그램에전달하는입력방식 입력된데이터를전처리하지않음 전화면편집기 (vi 등 ), 메뉴구동프로그램, 타자연습프로그램등과같이입력문자의즉각적인처리를요구하는프로그램에적합 Unix System Programming 25
비정규입력모드설정 비정규입력 (2) ioctl() 시스템호출을통해장치드라이버모드를변경 로컬모드플래그설정 ICANON 플래그을 0 으로설정 추가적인 ISIG 플래그를 0 으로설정하여 signal 관련문자검사를생략할수있음 제어문자설정 read() 시스템호출을정밀하게제어 VMIN(c_cc[4]), VTIME(c_cc[5]) 문자설정 VMIN read() 시스템호출반환하기전까지의최소입력문자수 VTIME read() 시스템호출을반환하기위한대기시간 (0.1 초단위설정 ) VMIN 과 VTIME 설정 다음표참조 Unix System Programming 26
비정규입력모드설정 VMIN 과 VTIME 설정 비정규입력 (3) 지정값의미 VMIN = 0 VTIME = 0 VMIN > 0 VTIME = 0 VMIN = 0 VTIME > 0 VMIN > 0 VTIME > 0 Read() 호출이즉시반환된다. 만약미리입력버퍼에데이터가있으면이를반환한다 타이머는아무런동작하지않는다. Read() 호출은 VMIN 에서지정된문자수만큼입력될때까지대기하다가반환된다 입력문자수지정은아무런동작하지않는다. Read() 호출은 VTIME 에서지정된시간만큼대기하다가반환된다 Read() 호출은두가지조건중에하나라도만족하면반환된다 Unix System Programming 27
비정규입력 (4) 비정규입력모드설정 예 #include <termio.h> struct termio tdes; int ttyfd; ioctl(ttyfd, TCGETA, &tdes); /* 현재의플래그상태값을얻는다 */ tdes.c_lflag &= ~ICANON; /* 정규모드를 off 한다 */ tdes.c_cc[4] = 64; /* 최소입력문자수 (64) 를지정 */ Tdes.c_cc[5] = 2; /* 입력대기시간 200ms 지정 */ Unix System Programming 28
타이핑연습프로그램 비정규입력 (5) 단말기의비정규입력모드를이용하여타이핑연습을수행하는프로그램 #include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <termio.h> int main(int argc, char *argv[]) { char ch, *text = "The quick brown fox jumped over the lazy dog\'s back"; int fd, i, errors=0, len; struct termio tty, savtty; if(isatty(fileno(stdout)) == 0) { fprintf(stderr,"stdout not terminal\n"); exit(1); Unix System Programming 29
비정규입력 (6) 타이핑연습프로그램 (cont d) fd = open("/dev/tty", O_RDONLY); /* /dev/tty : MACHINE DEPENDENT!! */ ioctl(fd, TCGETA, &tty); savtty = tty; tty.c_lflag &= ~(ISIG ICANON ECHO); tty.c_cc[vmin] = 1; /* MIN */ ioctl(fd, TCSETAW, &tty); setbuf(stdout, (char *) NULL); printf("type beneath th efollowing line\n\n%s\n", text); len = strlen(text); for(i=0; i<len; i++) { read(fd, &ch,1); if(ch == text[i]) putchar(ch); else { putchar('\07'); putchar('*'); errors++; ioctl(fd, TCSETAF, &savtty); printf("\n\nnumber of errors: %d\n",errors); exit(0); Unix System Programming 30
예제프로그램 #2 비정규입력 (7) 단말기의속성에서의 ICANON 및 ECHO 모드제거 교재 pp.254, ctohex_icanon.c Unix System Programming 31
원시 (RAW) 모드설정 단말기장치의원시 (Raw) 모드설정 원시모드 입력문자를버퍼링하지않는모드 주로파일송수신을위해동작모드 원시모드설정 c_iflag &= ~(IGNBRK BRKINT PARMAK ISTRIP INLCR IGNCR ICRNL IXON); c_oflag &= ~OPOST; c_cflag &= ~(CSIZE PARENB); c_cflag = CS8; c_lflag &= ~(ECHO ECHONL ICANON ISIG); Unix System Programming 32
예제 : 라인편집프로그램 (1) 라인편집 (Line Editor) 프로그램 1. 각각의문자들은입력된순간에화면에표시한다. 2. ERASE 문자가입력되면마지막입력된문자를화면의현재위치와버퍼에서삭제한다. 3. KILL 문자가입력되면현재라인의모든문자들을삭제한다. 4. Ctrl-W 문자가입력되면현재라인의마지막단어 (word) 를삭제한다. 5. Ctrl-D 문자가입력되면편집기프로그램종료한다. 6. 위에서언급된문자이외의출력불가능한문자가입력되면 Ctrl-G에대응되는경고음을울린다. 7. 한라인의길이는 80 문자로하고 80 문자가넘게입력되면단어는다음줄의첫번째컬럼에표시한다. Unix System Programming 33
예제 : 라인편집프로그램 (2) #include <ctype.h> #include <termio.h> #include <unistd.h> #define EOT '\04' /* cntl -D */ #define BEL '\07' /* cntl -G */ #define ETB '\027' /* cntl -W */ #define MAXLINE 512 #define LINESIZE 80 #define BACKSPACE write(1,"\b \b",3) int main(int argc, char *argv[]) { char line[maxline], ch; int pos, newpos, savpos, i; struct termio tty, savetty; if(!isatty(0)) { perror(argv[0]); exit(1); Unix System Programming 34
예제 : 라인편집프로그램 (3) if(ioctl(0,tcgeta,&tty) == -1) { perror(argv[0]); exit(2); /* turnoff canonical input and echoing */ savetty = tty; tty.c_cc[vmin] = 1; tty.c_cc[vtime] = 1; tty.c_lflag &= ~(ISIG ICANON ECHO); if(ioctl(0,tcsetaf,&tty) == -1) { perror(argv[0]); exit(3); pos =0; while(read(0, &ch, 1) > 0) { /* if EOF in first position stop */ if(ch == EOT) { if(pos == 0) break; Unix System Programming 35
예제 : 라인편집프로그램 (4) /* if ERASE character then erase previous character */ else if(ch == tty.c_cc[verase]) { if(pos > 0) { BACKSPACE; --pos; /* if cntl -W erase until beginning of last word */ else if(ch == ETB) { while(pos > 0 && isspace(line[pos-1])) { BACKSPACE; --pos; /* trailing blanks*/ while(pos > 0 &&!isspace(line[pos-1])) { BACKSPACE; --pos; /* last word */ /* if new - line start a new line */ else if(ch == '\n') { write(1,&ch, 1); pos = 0; Unix System Programming 36
예제 : 라인편집프로그램 (5) /* if not printable ring bell instead */ else if(!isprint(ch)) { write(1,bel,1); /* write charcter to screen and store it */ else { write(1, &ch, 1); line[pos++] = ch; /* wrap - around -- OPTIONAL */ if(pos >= LINESIZE &&!isspace(ch)) { savpos = pos; /* find begining of last word */ while(pos > 0 &&!isspace(line[pos -1])) --pos; Unix System Programming 37
예제 : 라인편집프로그램 (6) if(pos > 0) { newpos = 0; /* copy last word to begining of line */ for(i=pos; i< savpos; i++) { BACKSPACE; line[newpos++] = line[i]; pos = newpos; /* display word at begining of line */ write(1,"\n",1); for(i=0; i<pos; i++) write(1,&line[i], 1); else write(1,"\n",1); /* if */ /* while */ /* reset terminal setting */ ioctl(0, TCSETA, &savetty); Unix System Programming 38