- 
                Notifications
    
You must be signed in to change notification settings  - Fork 7
 
errno(3)
errno - 마지막 오류의 번호
#include <errno.h><errno.h> 헤더 파일에서 정수 변수 errno를 정의한다. 시스템 호출과 일부 라이브러리 함수에서 오류 발생 시 무엇이 잘못됐는지 나타내기 위해 그 변수를 설정한다.
호출의 반환 값이 오류를 나타낸 (즉 대부분 시스템 호출에서 -1, 대부분 라이브러리 함수에서 -1 내지 NULL인) 때에만 errno의 값이 의미가 있다. 즉 성공하는 함수에서 errno를 바꾸는 것이 허용된다. 어떤 시스템 호출이나 라이브러리 호출에서도 절대 errno 값을 0으로 설정하지는 않는다.
어떤 시스템 호출과 라이브러리 함수(가령 getpriority(2))에서는 -1이 성공 시의 유효한 반환 값이다. 그런 경우에는 호출 전에 errno를 0으로 설정해서 성공 반환과 오류 반환을 구별할 수 있다. 오류가 발생했을 수도 있음을 나타내는 상태를 호출에서 반환하면 errno가 0 아닌 값인지 확인하면 된다.
errno는 ISO C에서 int 타입의 변경 가능한 lvalue라고 규정돼 있으며 명시적으로 선언해서는 안 된다. 즉 errno가 매크로일 수도 있다. errno는 스레드 로컬이다. 그래서 한 스레드에서 그 값을 설정해도 다른 스레드의 값에 영향을 주지 않는다.
유효한 오류 번호들은 모두 양수 번호이다. errno에 등장할 수 있는 오류 번호 각각의 심볼 이름이 <errno.h> 헤더 파일에 정의돼 있다.
POSIX.1에서 명세하는 오류 이름들은 모두 서로 다른 값을 가져야 한다. 단 예외로 EAGAIN과 EWOULDBLOCK은 같을 수도 있다.
각 심볼 이름에 대응하는 오류 번호는 유닉스 시스템 종류에 따라 다르며 심지어 리눅스에서 아키텍처에 따라 다르기도 하다. 그래서 아래의 오류 이름 목록에는 번호 값이 포함돼 있지 않다. perror(3) 및 strerror(3) 함수를 사용하면 그 이름을 대응하는 텍스트 오류 메시지로 변환할 수 있다.
어떤 리눅스 시스템 상에서든 (moreutils 패키지에 포함된) errno(1) 명령을 쓰면 모든 오류 심볼 이름과 대응하는 오류 번호들의 목록을 얻을 수 있다.
$ errno -l
EPERM 1 Operation not permitted
ENOENT 2 No such file or directory
ESRCH 3 No such process
EINTR 4 Interrupted system call
EIO 5 Input/output error
...
또한 errno(1) 명령을 사용해 다음과 같이 개별 오류 번호와 이름을 찾아보고 오류 서술에서 얻은 문자열로 오류를 검색할 수 있다.
$ errno 2
ENOENT 2 No such file or directory
$ errno ESRCH
ESRCH 3 No such process
$ errno -s permission
EACCES 13 Permission denied
아래의 오류 심볼 이름 목록에서 여러 이름들에 다음과 같은 표시가 되어 있다.
- 
POSIX.1-2001: 그 이름을 POSIX.1-2001에서, 그리고 달리 표시돼 있지 않으면 이후 POSIX.1 버전들에서도 규정하고 있다.
 - 
POSIX.1-2008: 그 이름을 POSIX.1-2008에서는 규정하고 있지만 더 전의 POSIX.1 표준에는 없다.
 - 
C99: 그 이름을 C99에서 규정하고 있다. 다음은 리눅스에서 정의돼 있는 오류 심볼 이름들의 목록이다.
 
E2BIG | 
인자 목록이 너무 긺. (POSIX.1-2001) | 
EACCES | 
권한 거부됨. (POSIX.1-2001) | 
EADDRINUSE | 
주소가 이미 사용 중. (POSIX.1-2001) | 
EADDRNOTAVAIL | 
사용 가능 주소 없음. (POSIX.1-2001) | 
EAFNOSUPPORT | 
지원하지 않는 주소 패밀리. (POSIX.1-2001) | 
EAGAIN | 
자원이 일시적으로 사용 불가. (EWOULDBLOCK과 같은 값일 수도 있음.) (POSIX.1-2001) | 
EALREADY | 
연결이 이미 진행 중. (POSIX.1-2001) | 
EBADE | 
유효하지 않은 교환. | 
EBADF | 
잘못된 파일 디스크립터. (POSIX.1-2001) | 
EBADFD | 
잘못된 상태의 파일 디스크립터. | 
EBADMSG | 
잘못된 메시지. (POSIX.1-2001) | 
EBADR | 
유효하지 않은 요청 디스크립터. | 
EBADRQC | 
유효하지 않은 요청 코드. | 
EBADSLT | 
유효하지 않은 슬롯. | 
EBUSY | 
장치 또는 자원이 사용 중. (POSIX.1-2001) | 
ECANCELED | 
동작이 취소됐음. (POSIX.1-2001) | 
ECHILD | 
자식 프로세스가 없음. (POSIX.1-2001) | 
ECHRNG | 
범위를 벗어나는 채널 번호. | 
ECOMM | 
송신 중 통신 오류. | 
ECONNABORTED | 
연결 중단됨. (POSIX.1-2001) | 
ECONNREFUSED | 
연결 거부됨. (POSIX.1-2001) | 
ECONNRESET | 
연결 리셋 됨. (POSIX.1-2001) | 
EDEADLK | 
자원 교착 회피했음. (POSIX.1-2001) | 
EDESTADDRREQ | 
목적 주소 필요함. (POSIX.1-2001) | 
EDOM | 
수학 인자가 함수 정의역을 벗어남. (POSIX.1, C99) | 
EDQUOT | 
디스크 쿼터 초과했음. (POSIX.1-2001) | 
EEXIST | 
파일이 존재함. (POSIX.1-2001) | 
EFAULT | 
잘못된 주소. (POSIX.1-2001) | 
EFBIG | 
파일이 너무 큼. (POSIX.1-2001) | 
EHOSTDOWN | 
호스트가 내려가 있음. | 
EHOSTUNREACH | 
호스트에 도달 불가능함. (POSIX.1-2001) | 
EHWPOISON | 
메모리 페이지에 하드웨어 오류가 있음. | 
EIDRM | 
식별자가 제거됐음. (POSIX.1-2001) | 
EILSEQ | 
 다중 바이트 내지 확장 문자가 유효하지 않거나 불완전함. (POSIX.1, C99) 이는 glibc의 오류 설명임. POSIX.1에서는 이 오류를 "유효하지 않은 바이트 열"이라고 기술함.  | 
EINPROGRESS | 
동작 진행 중. (POSIX.1-2001) | 
EINTR | 
함수 호출이 중단됐음. (POSIX.1-2001) signal(7) 참고. | 
EINVAL | 
잘못된 인자. (POSIX.1-2001) | 
EIO | 
입출력 오류. (POSIX.1-2001) | 
EISCONN | 
소켓이 연결돼 있음. (POSIX.1-2001) | 
EISDIR | 
디렉터리임. (POSIX.1-2001) | 
EISNAM | 
기명 타입 파일임. | 
EKEYEXPIRED | 
키가 만료됐음. | 
EKEYREJECTED | 
키가 서비스에서 거부됐음. | 
EKEYREVOKED | 
키가 폐지됐음. | 
EL2HLT | 
2계층 중단. | 
EL2NSYNC | 
2계층 동기화 안 됨. | 
EL3HLT | 
3계층 중단. | 
EL3RST | 
3계층 재설정. | 
ELIBACC | 
필요한 공유 라이브러리에 접근할 수 없음. | 
ELIBBAD | 
접근하려는 공유 라이브러리에 오류. | 
ELIBMAX | 
링크 하려는 공유 라이브러리가 너무 많음. | 
ELIBSCN | 
a.out의 .lib 섹션에 오류. | 
ELIBEXEC | 
공유 라이브러리를 직접 실행할 수 없음. | 
ELNRANGE | 
링크 개수가 범위를 초과. | 
ELOOP | 
너무 긴 심볼릭 링크 단계. (POSIX.1-2001) | 
EMEDIUMTYPE | 
잘못된 매체 유형. | 
EMFILE | 
열린 파일 너무 많음. (POSIX.1-2001) 보통 getrlimit(2)에 설명된 RLIMIT_NOFILE 자원 제한 초과 때문. | 
EMLINK | 
링크 너무 많음. (POSIX.1-2001) | 
EMSGSIZE | 
메시지가 너무 긺. (POSIX.1-2001) | 
EMULTIHOP | 
멀티홉 시도했음. (POSIX.1-2001) | 
ENAMETOOLONG | 
파일 이름이 너무 긺. (POSIX.1-2001) | 
ENETDOWN | 
네트워크 내려가 있음. (POSIX.1-2001) | 
ENETRESET | 
연결이 네트워크에 의해 중단됨. (POSIX.1-2001) | 
ENETUNREACH | 
네트워크 도달 불가능. (POSIX.1-2001) | 
ENFILE | 
시스템에 열린 파일 너무 많음. (POSIX.1-2001) 리눅스에서는 아마 /proc/sys/fs/file-max 제한(proc(5) 참고)에 걸려서일 것. | 
ENOANO | 
anode 없음. | 
ENOBUFS | 
가용 버퍼 공간 없음. (POSIX.1 (XSI STREAMS 옵션)) | 
ENODATA | 
STREAM 헤드 읽기 큐에 가용 메시지 없음. (POSIX.1-2001) | 
ENODEV | 
그런 장치 없음. (POSIX.1-2001) | 
ENOENT | 
 그런 파일 내지 디렉터리 없음. (POSIX.1-2001) 보통 지정한 경로명이 존재하지 않거나, 경로명 디렉터리 선두부의 어느 요소가 존재하지 않거나, 지정한 경로명이 깨진 심볼릭 링크일 때 이 오류가 발생한다.  | 
ENOEXEC | 
실행 파일 형식 오류. (POSIX.1-2001) | 
ENOKEY | 
필요한 키가 없음. | 
ENOLCK | 
쓸 수 있는 락 없음. (POSIX.1-2001) | 
ENOLINK | 
링크가 손상됐음. (POSIX.1-2001) | 
ENOMEDIUM | 
매체를 찾지 못했음. | 
ENOMEM | 
공간 부족/메모리 할당할 수 없음. (POSIX-1.2001) | 
ENOMSG | 
원하는 유형의 메시지 없음. (POSIX.1-2001) | 
ENONET | 
머신이 네트워크 상에 없음. | 
ENOPKG | 
패키지 설치 안 됐음. | 
ENOPROTOOPT | 
가용 프로토콜 없음. (POSIX.1-2001) | 
ENOSPC | 
장치에 남은 공간 없음. (POSIX.1-2001) | 
ENOSR | 
STREAM 자원 없음. (POSIX.1 (XSI STREAMS 옵션)) | 
ENOSTR | 
STREAM 아님. (POSIX.1 (XSI STREAMS 옵션)) | 
ENOSYS | 
기능 구현 안 돼 있음. (POSIX.1-2001) | 
ENOTBLK | 
블록 장치 필요함. | 
ENOTCONN | 
소켓 연결 안 돼 있음. (POSIX.1-2001) | 
ENOTDIR | 
디렉터리가 아님. (POSIX.1-2001) | 
ENOTEMPTY | 
디렉터리가 비어 있지 않음. (POSIX.1-2001) | 
ENOTRECOVERABLE | 
상태 복원 불가능. (POSIX.1-2008) | 
ENOTSOCK | 
소켓 아님. (POSIX.1-2001) | 
ENOTSUP | 
지원 안 되는 동작. (POSIX.1-2001) | 
ENOTTY | 
부적절한 I/O 제어 동작. (POSIX.1-2001) | 
ENOTUNIQ | 
이름이 네트워크에서 유일하지 않음. | 
ENXIO | 
그런 장치 내지 주소 없음. (POSIX.1-2001) | 
EOPNOTSUPP | 
 소켓에서 지원 안 되는 동작. (POSIX.1-2001) (리눅스에서는   | 
EOVERFLOW | 
값이 너무 커서 데이터 타입에 저장 안 됨. (POSIX.1-2001) | 
EOWNERDEAD | 
소유자가 죽었음. (POSIX.1-2008) | 
EPERM | 
동작이 허용되지 않음. (POSIX.1-2001) | 
EPFNOSUPPORT | 
지원하지 않은 프로토콜 패밀리. | 
EPIPE | 
파이프 깨졌음. (POSIX.1-2001) | 
EPROTO | 
프로토콜 오류. (POSIX.1-2001) | 
EPROTONOSUPPORT | 
지원하지 않는 프로토콜. (POSIX.1-2001) | 
EPROTOTYPE | 
소켓에 맞지 않는 프로토콜 타입. (POSIX.1-2001) | 
ERANGE | 
결과가 너무 큼. (POSIX.1, C99) | 
EREMCHG | 
원격 주소가 바뀌었음. | 
EREMOTE | 
객체가 원격에 있음. | 
EREMOTEIO | 
원격 I/O 오류. | 
ERESTART | 
중단된 시스템 호출을 재시작해야 함. | 
ERFKILL | 
RF-kill 때문에 동작 불가능. | 
EROFS | 
읽기 전용 파일 시스템. (POSIX.1-2001) | 
ESHUTDOWN | 
전송 종단 정지 후 보낼 수 없음. | 
ESPIPE | 
위치 이동 불가능. (POSIX.1-2001) | 
ESOCKTNOSUPPORT | 
지원하지 않는 소켓 유형. | 
ESRCH | 
그런 프로세스가 없음. (POSIX.1-2001) | 
ESTALE | 
 파일 핸들이 더는 유효하지 않음. (POSIX.1-2001) NFS 및 기타 파일 시스템에서 이 오류가 발생할 수 있다.  | 
ESTRPIPE | 
스트림 파이프 오류. | 
ETIME | 
 타이머 만료됨. (POSIX.1 (XSI STREAMS 옵션)) (POSIX.1에서는 "STREAM   | 
ETIMEDOUT | 
연결이 타임아웃 됨. (POSIX.1-2001) | 
ETOOMANYREFS | 
참조가 너무 많음. splice 할 수 없음. | 
ETXTBSY | 
텍스트 파일 사용 중. (POSIX.1-2001) | 
EUCLEAN | 
구조 정리 필요. | 
EUNATCH | 
프로토콜 드라이버 붙어 있지 않음. | 
EUSERS | 
사용자가 너무 많음. | 
EWOULDBLOCK | 
동작이 블록 하게 됨. (EAGAIN과 같은 값일 수도 있음.) (POSIX.1-2001) | 
EXDEV | 
부적절한 링크. (POSIX.1-2001) | 
EXFULL | 
교환기에 여유 없음. | 
많이 하는 실수로 다음과 같은 게 있다.
if (somecall() == -1) {
    printf("somecall() failed\n");
    if (errno == ...) { ... }
}여기서 errno가 꼭 somecall() 함수 반환 시의 값을 가지고 있는 게 아니다. (즉 printf(3)에 의해 바뀌었을 수도 있다.) 라이브러리 호출을 거치면서 errno 값이 보존돼야 한다면 저장을 해야 한다.
if (somecall() == -1) {
    int errsv = errno;
    printf("somecall() failed\n");
    if (errsv == ...) { ... }
}일부 아주 오래된 시스템에서는 <errno.h>가 존재하지 않거나 errno를 선언해 주지 않았으며, 그래서 errno를 직접 선언(extern int errno)해야 했다. 지금은 그렇게 해선 안 된다. 오래 전부터 그럴 필요가 없게 됐으며 최근의 C 라이브러리 버전들에서 문제를 일으키게 된다.
errno(1), err(3), error(3), perror(3), strerror(3)
2019-03-06