현재 리눅스에서 sys_nerr를 지원을 안해서 생긴문제로 질문을 드립니다.
글쓴이: anaud2 / 작성시간: 화, 2008/10/28 - 12:37오후
안녕하세요
업무때문에 공개소스를 사용하고 있는 계발자입니다^^항상 많은 도움을 받아서 감사해하고 있습니다.
이번에 질문을 드릴사항은 sys_nerr을 소스에서 사용하고 있던데요
In function `dataconn': : warning: `sys_errlist' is deprecated; use `strerror' or `strerror_r' instead In function `dataconn': : warning: `sys_nerr' is deprecated; use `strerror' or `strerror_r' instead
컴파일시 이런경고가 발생합니다. 내용을 보면 sys_nerr 이나 sys_errlist는 사용을 하면안되고 strerror' or `strerror_r' 를 사용하라
인거 같습니다.
//편집 선업부분 //extern char *sys_errlist[]; extern int sys_nerr; //편집 사용부분 errno < sys_nerr ? sys_errlist[errno] : "unknown error");
소스에서는 extern 을 해서 사용을 하고 있던데요 sys_errlist같은경우 문자열을 리턴을 하기에
man strerror char *strerror(int errnum); int strerror_r(int errnum, char *buf, size_t n);
strerror을 사용을 하면 될거 같아서 그부분으로 고쳤습니다.
그런데 sys_nerr의 경우 int 형 데이터인데.. strerror_r이 int여서 사용을 하면 될듯도 하지만 strerror_r을 살펴보면 buf에 에러에 대한 내용이 들어가고
리턴타입은 성공 0,실패 -1로 이루어 졌다고 해석이 됐는데요
그렇다면 sys_nerr의 성질과 다르지 않을까 생각이 됩니다. sys_nerr의 경우 man 페이지에 없어서
man perror페이지에서 조금 있는거 같은데
NAME
perror - print a system error message
SYNOPSIS
#include <stdio.h>
void perror(const char *s);
#include <errno.h>
const char *sys_errlist[];
int sys_nerr;
int errno;해석이 잘되질 않네요
컴파일시에는 strerror 이나 strerror_r을 사용을 하라고 하는데 그렇게 해도 괜찮은지 모르겠네요
아시는분 답변을 주시면 감사하겠습니다.
Forums:


꽤 오래전? 코드를
꽤 오래전? 코드를 쓰고 계신 것 같군요.
sys_errlist와 sys_nerr는 BSD에서 온 것이며, ISO C 표준에 strerror()이 있고, SUSv3 (POSIX)에서 thread-safe한 strerror_r()를 지원합니다.
따라서 sys_errlist와 sys_nerr를 쓸 이유는 없습니다.
질문을 보니 sys_nerr의 대체용으로 strerror_r()를 생각하시는 것 같은데, 잘못 생각하고 계신 겁니다.
코드를 보여주지 않아서 무슨 목적으로 sys_nerr를 쓴 것인지는 모르겠지만, 일반적으로 sys_nerr를 쓸 이유가 없을 텐데요.
오래된 코드라면, 아래와 같은 코드를 썼을 테고:
int fd; fd = open(...); if (fd < 0) { fprintf(stderr, "error: open() failed: %s\n", sys_errlist[errno]); ... }이 것을 다음과 같이 바꾸면 됩니다:
int fd; fd = open(...); if (fd < 0) { fprintf(stderr, "error: open() failed: %s\n", strerror(errno)); ... }코드가 multi-thread 용이라면 strerror() 대신 strerror_r()을 씁니다.
char buf[ERRMSG_MAX]; int fd; fd = open(...); if (fd < 0) { strerror_r(errno, buf, ERRMSG_MAX); fprintf(stderr, "error: open() failed: %s\n", buf); ... }위 코드에서 strerror_r()의 에러 검사는 편의상 생략했습니다. 만약 주어진 버퍼의 크기(ERRMSG_MAX)가 에러 메시지를 담기에 충분하지 않다면, strerror_r()는 실패합니다.
참고로 strerror_r()는 호환이 되지 않는 두 가지 버전이 존재합니다. 하나는 위에서 쓴 것과 같이 SUSv3에서 정의하는 strerror_r()이고, 다른 하나는 GNU C library가 제공하는 strerror_r()입니다. 각각 선언은 다음과 같습니다:
int strerror_r(int errnum, char *buf, size_t buflen); /* XSI-compliant */ char *strerror_r(int errnum, char *buf, size_t buflen); /* GNU-specific */따로 _GNU_SOURCE 등의 매크로를 정의하지 않았다면 SUSv3의 strerror_r()를 쓰게 됩니다. (위 선언에서 XSI로 표시된 것)
--
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Korean Ver: http://www.cinsk.org/cfaqs/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Korean Ver: http://cinsk.github.io/cfaqs/
답변 주셔서 감사합니다. 음 소스 부분은...
소스 부분을 공개 하지 않은것은 좀 어수선해질까봐서 였어요
오픈된 FTP소스이구 소스 전체를 완벽하게 이해하고 사용하는게 아니라 어느선만 이해를 하고 편의에 맞게 고쳐 사용하려구 합니다.
sys_nerr 과 sys_errlist의 사용부분은 아래와 같습니다.
FILE * dataconn(name, size, mode) char *name; off_t size; char *mode; { char sizebuf[32]; FILE *file; int retry = 0; file_size = size; byte_count = 0; if (size != (off_t) -1) (void) sprintf (sizebuf, " (%ld bytes)", size); else (void) strcpy(sizebuf, ""); if (pdata >= 0) { struct sockaddr_in from; int s, fromlen = sizeof(from); struct timeval timeout; fd_set set; FD_ZERO(&set); FD_SET(pdata, &set); timeout.tv_usec = 0; timeout.tv_sec = 120; if (select(pdata+1, &set, (fd_set *) 0, (fd_set *) 0, &timeout) == 0 || (s = accept(pdata, (struct sockaddr *) &from, &fromlen)) < 0) { reply(425, "Can't open data connection."); (void) close(pdata); pdata = -1; return(NULL); } (void) close(pdata); pdata = s; reply(150, "Opening %s mode data connection for %s%s.", type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); return(fdopen(pdata, mode)); } if (data >= 0) { reply(125, "Using existing data connection for %s%s.", name, sizebuf); usedefault = 1; return (fdopen(data, mode)); } if (usedefault) data_dest = his_addr; usedefault = 1; file = getdatasock(mode); if (file == NULL) { reply(425, "Can't create data socket (%s,%d): %s.", inet_ntoa(data_source.sin_addr), ntohs(data_source.sin_port), errno < sys_nerr ? sys_errlist[errno] : "unknown error"); //sys_nerr , sys_errlist 사용 return (NULL); } data = fileno(file); while (connect(data, (struct sockaddr *)&data_dest, sizeof (data_dest)) < 0) { if (errno == EADDRINUSE && retry < swaitmax) { sleep((unsigned) swaitint); retry += swaitint; continue; } perror_reply(425, "Can't build data connection"); (void) fclose(file); data = -1; return (NULL); } reply(150, "Opening %s mode data connection for %s%s.", type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); return (file); }perror_reply(code, string) int code; char *string; { if (errno < sys_nerr) //sys_nerr 사용 reply(code, "%s: %s.", string, sys_errlist[errno]); //sys_errlist사용 else reply(code, "%s: unknown error %d.", string, errno); }각각 소스내부에 선언된 함수이구요 내부에서 보면 sys_errlist에 관해서는 strerror 함수로 다 바꿔줬구요
소스가 완벽히 이해가 되질 않아서 sys_nerr를 strerror_r()로 선언을 해도 될까 하는점 때문에 질문을 드렸습니다.
strerror의 경우 sys_errlist로 사용을 해도 될꺼같아서 해줬는데 strerror_r의 경우 맞는건지 선뜻 와닿지 않더라구요
man 페이지에서도 sys_errlist와 sys_nerr 의 설명이 없어서 찾기가 어려웠습니다.
sys_errlist의 경우,
sys_errlist의 경우, errno의 값을 모두 cover한다는 보장이 없기 때문에, 일반적으로, 보여주신 코드에서처럼 errno의 값이 sys_nerr보다 작은 경우에만 sys_errlist를 접근하도록 작성합니다. strerror()의 경우, 이러한 제약사항이 없기 때문에, 직접 쓰면 됩니다.
예를 들어, 위 코드에서 perror_reply() 함수를 다음과 같이 만들면 됩니다:
void perror_reply(int code, char *string) { int old_errno = errno; char *msg = strerror(errno); if (msg) reply(code, "%s: %s.", string, msg); else reply(code, "%s: unknown error %d", string, old_errno); }또, dataconn()에서 reply() 호출하는 부분은 다음과 같이 바꿉니다:
if (file == NULL) { reply(425, "Can't create data socket (%s,%d): %s.", inet_ntoa(data_source.sin_addr), ntohs(data_source.sin_port), strerror(errno)); return (NULL); }--
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Korean Ver: http://www.cinsk.org/cfaqs/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Korean Ver: http://cinsk.github.io/cfaqs/
정말 감사합니다.
어디를 찾아봐도 안나오구 선배님들에게 물어도 나오지 않은 답인데 명쾌하게 풀어주셔서 감사합니다.
댓글 달기