NAME

ioctl - 장치 제어하기

SYNOPSIS

#include <sys/ioctl.h>

int ioctl(int fd, unsigned long request, ...);

DESCRIPTION

ioctl() 시스템 호출은 특수 파일 기반 장치의 매개변수들을 조작한다. 특히 문자 특수 파일(가령 터미널)의 여러 동작 특성들을 ioctl() 요청으로 제어할 수 있다. fd 인자는 열린 파일 디스크립터여야 한다.

두 번째 인자는 장치에 따라 달라지는 요청 코드다. 세 번째 인자는 타입 없는 메모리 포인터다. 전통적으로 (void *가 C에서 유효하기 전부터) char *argp였으므로 여기서도 그렇게 부를 것이다.

ioctl()request 값에는 인자가 입력 매개변수인지 아니면 출력 매개변수인지, 그리고 argp 인자의 바이트 단위 크기는 얼마인지가 담겨 있다. ioctl()request를 명세하는 데 쓰는 매크로와 정의들이 <sys/ioctl.h> 파일에 있다. NOTES 참고.

RETURN VALUE

일반적으로 성공 시 0을 반환한다. 몇몇 ioctl() 요청은 반환 값을 출력 매개변수로 사용하여 성공 시 음수 아닌 값을 반환한다. 오류 시 -1을 반환하며 오류를 나타내도록 errno를 설정한다.

ERRORS

EBADF
fd가 유효한 파일 디스크립터가 아니다.
EFAULT
argp가 접근 불가능한 메모리 영역을 가리키고 있다.
EINVAL
requestargp가 유효하지 않다.
ENOTTY
fd가 문자 특수 파일에 연계돼 있지 않다.
ENOTTY
지정한 요청이 파일 디스크립터 fd가 가리키는 종류의 객체에 적용되지 않는다.

CONFORMING TO

어떤 단일 표준이 없다. 장치 드라이버에 따라서 ioctl()의 인자와 반환 값, 동작 방식이 달라진다. (이 호출은 유닉스의 스트림 I/O 모델에 깔끔하게 들어맞지 않는 동작들을 위한 잡동사니 상자 역할을 한다.)

AT&T UNIX 버전 7에서 ioctl() 시스템 호출이 등장했다.

NOTES

이 호출을 이용하려면 열린 파일 디스크립터가 있어야 한다. open(2) 호출에 원치 않는 부대 효과가 있는 경우가 많은데, 리눅스에선 O_NONBLOCK 플래그를 줘서 피할 수 있다.

ioctl 값의 구조

ioctl 명령 값은 32비트 정수다. 원칙적으로 그 상수들은 완전히 임의적이지만 사람들이 그 안에 어떤 구조를 만들어 넣으려고 했다.

리눅스 옛날 버전에서는 대부분 16비트인 상수들 중 마지막 바이트가 일련 번호이고 그 앞의 바이트가 (또는 바이트들이) 드라이버를 나타내는 타입 값이다. 때로는 주 번호를 써서, HDIO_* ioctl에는 0x03을 쓰고 LP* ioctl에는 0x06을 썼다. 또 때로는 ASCII 문자 한두 개를 썼다. 예를 들어 TCGETS의 값은 0x00005401인데 0x54 = 'T'가 터미널 드라이버를 나타내며, CYGETTIMEOUT의 값은 0x00435906인데 0x43 0x59 = 'C' 'Y'가 Cyclades 드라이버를 나타낸다.

이후 (0.98p5) 그 수에 좀 더 많은 정보가 들어갔다. 방향 비트 2개(00: 없음, 01: 쓰기, 10: 읽기, 11: 읽기/쓰기)와 크기 비트 14개(인자의 크기를 나타냄)에 이어 8비트 타입 값(ioctl들을 용도 및 드라이버별로 묶은 것)과 8비트 일련 번호가 온다.

그 구조를 기술하는 매크로들이 <asm/ioctl.h>에 있는데, 바로 _IO(type,nr){_IOR,_IOW,_IOWR}(type,nr,size)이다. sizeof(size)로 쓰기 때문에 size는 사실 잘못된 이름이다. 즉, 세 번째 인자는 데이터 타입이다.

size 비트가 그리 믿을 만하지 않다. 많은 경우에 값이 잘못돼 있는데, 매크로 버그 때문에 sizeof(sizeof(struct))로 돼서일 수도 있고 값이 갱신되지 않아서일 수도 있다.

요컨대 새 구조에는 단점만 있는 것 같다. 검사에는 도움을 주지 않으면서 아키텍처마다 값이 달라지게 만든다.

SEE ALSO

execve(2), fcntl(2), ioctl_console(2), ioctl_fat(2), ioctl_ficlonerange(2), ioctl_fideduperange(2), ioctl_fslabel(2), ioctl_getfsmap(2), ioctl_iflags(2), ioctl_ns(2), ioctl_tty(2), ioctl_userfaultfd(2), open(2), sd(4), tty(4)


2021-03-22