현재 리눅스에서 sys_nerr를 지원을 안해서 생긴문제로 질문을 드립니다.

anaud2의 이미지

안녕하세요

업무때문에 공개소스를 사용하고 있는 계발자입니다^^항상 많은 도움을 받아서 감사해하고 있습니다.

이번에 질문을 드릴사항은 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을 사용을 하라고 하는데 그렇게 해도 괜찮은지 모르겠네요
아시는분 답변을 주시면 감사하겠습니다.

cinsk의 이미지

꽤 오래전? 코드를 쓰고 계신 것 같군요.

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/

anaud2의 이미지

소스 부분을 공개 하지 않은것은 좀 어수선해질까봐서 였어요
오픈된 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 의 설명이 없어서 찾기가 어려웠습니다.

cinsk의 이미지

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/

anaud2의 이미지

어디를 찾아봐도 안나오구 선배님들에게 물어도 나오지 않은 답인데 명쾌하게 풀어주셔서 감사합니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.