2010-04-01 2 views
2

솔라리스 상자에 PostgreSQL에 몇 가지 기능을 추가하는 과제를 작성 중입니다. 할당의 일환으로 클라이언트 측에 몇 가지 정보를 출력해야합니다 (예 : elog 사용).printf 출력을 임시로 C 문자열로 리디렉션 할 수 있습니까?

PostgreSQL은 이미 필요한 정보를 인쇄하는 많은 방법을 가지고 있지만 도우미 메소드는 수백 가지로 압축되어 있습니다 printf이 호출되고 elog 메서드는 C 스타일 문자열에서만 작동합니다.

printf 호출을 버퍼로 리디렉션 할 수있는 방법이있어서 클라이언트에 elog을 쉽게 보낼 수 있습니까?

그럴 수 없다면 출력으로 버퍼로 끝나는 도우미 메서드를 수정하는 가장 간단한 방법은 무엇입니까?

답변

7

자신의 버전의 printf를 정의한 후 에 libc 버전보다 먼저 연결하면 버전이 표준 버전을 대체합니다.

또한 LD_PRELOAD를 사용하여 표준 버전을 대체하여 printf가 정의 된 라이브러리를로드 할 수 있어야합니다.

자신의 printf를 작성하려면 stdarg 기능을 사용하는 것이 좋습니다 : 최종 포맷 출력이 LARGESIZE보다 큰 경우

int printf(const char *fmt, ...) 
{ 
    int rv; 
    va_list ap; 
    va_start(ap, fmt); 

    if (redirect_printf) 
    { 
#ifdef HAVE_VLOG 
     // If you have a vlog function that takes a va_list 
     vlog(fmt, ap); 
     rv = ...; 
#else 
     char buffer[LARGESIZE]; 
     rv = vsnprintf(buffer, sizeof(buffer), fmt, ap); 

     log(buffer); 
#endif; 
    } 
    else 
    { 
     rv = vprintf(fmt, ap); 
    } 

    return rv; 
} 

이 간단한 버전은 데이터를 자릅니다. 원하지 않는 경우에는 vsnprintf을 먼저 NULL 버퍼로 호출하여 최종 크기를 얻고 동적 할당을 수행 한 다음 vsprintf을 호출하여 버퍼를 포맷 할 수 있습니다. 임시 파일의 사용을 허용 할 경우

+0

이것은 배정 되었기 때문에 필요한 소스 파일 만 전달할 것이므로 연결된 파일이 있으면 언제든지 제어 할 수 없습니다. –

+0

@BenS - 원본 파일 중 하나에 printf를 넣으면 그냥 작동해야합니다. –

+0

@R Samuel이 맞다고 생각합니다. libc는 마지막에 연결됩니다. –

2

가장 간단한 방법은 sprintf()을 호출하도록 도우미 메서드를 수정하는 것입니다. 쉽게 해킹 할 수 있는지 여부는 모르겠습니다. 어쩌면

#define printf(...) sprintf(buffer, __VA_ARGS__) 

할 것입니다. 각 도우미 함수에 대해 buffer을 정의해야하며 그 내용을 관심있는 사람에게 반환해야합니다.

+0

두 파일에 걸쳐 약 12 ​​가지의 도우미 메소드가 있으므로이 경로로 진행되는 작업은 상당히 많습니다. 또한 여러 통화가 이전 sprintf를 덮어 쓰지 않습니까? 아니면 sprintf가 추가합니까? –

+0

@Ben S, 아마도 이미 원하는 기능을하는 함수가 있을까요? 인쇄 된 문자 수를 반환하기 때문에'sprintf()'를 추가 할 수 있습니다. 만약 당신이 각 기능을위한 버퍼를 가지고 있다면 아마도 그렇게 되기는 힘들지 않을 것입니다. –

1

당신은 freopen() 호출을 표준 출력 리디렉션 수 : -

newstdout = freopen("/tmp/log", "w", stdout); 

이 모든 printf와의이/tmp로 쓸 수/콘솔 대신 로그 강제 산출.

readfd = fopen("/tmp/log", "r"); 

과 같은 것을 사용하여 추가 된 내용을 전달 : - - : 일부 편리한 시점에서 나중에 프로그램에서 당신은 읽기 같은 파일을 열 수

void forward_to_elog(void) 
{ 
    int bytesread; 
    char buf[100]; 

    memset(buf,0,100); 
    do { 
     memset(buf,0,100); 
     bytesread = fread(buf, sizeof(buf)-1, 1, readfd); 
     /* call elog(buf) */ ; 
    } while(bytesread); 

} 

유지할 경우 파일을 열면 forward_to_elog() 번을 여러 번 호출하여 추가 된 내용을 점진적으로 전달할 수 있습니다.

정적 파일을 정적으로 코드화하지 않으려면 tmpnam() 함수를 사용하여 임시 파일의 이름을 가져올 수 있습니다.

4

elog은 printf와 (과) 같은 형식 문자열을 지원합니다. 여기에 포스트 그레스 소스 코드의 예는 다음과 같습니다

elog(DEBUG4, "TZ \"%s\" gets max score %d", tzname, i); 

그래서 당신이 필요로하는 모두 같은 매개 변수를 사용하여 printf가있는 곳에 elog를 추가하는 것입니다.