Unix Linux

[펌] [C] hpux에서 gcc로 시스템 정보 가져오기

_침묵_ 2006. 1. 26. 06:09
목차
1소개
2개발환경 만들기
2.1목표 시스템의 환경
2.1.1패키지 설치방법
2.2GNU Package 다운로드/설치
2.3개발환경 테스트
2.3.1공유 라이브러리 사용의 문제
2.3.2컴파일시 주의해야 할점
3HP시스템 의존적인 개발환경
3.1Proc 파일시스템의 지원
3.2pstat(2)를 통한 시스템 정보 수집
3.3pstat(2)관련 구조체들
4셈플코드

컴파일 에러
#!g++ -o test test.cc -lpthread/usr/ccs/bin/ld: Unrecognized argument: +init/usr/ccs/bin/ld: Usage:  /usr/ccs/bin/ld flags... files...collect2: ld returned 1 exit status
위 문제를 해결하기 위해서 PHSS_30049 패치를 다운 받아서 수행함. 패치는 아래의 사이트를 이용할 수 있음g++ -fPIC -c -D _INCLUDE_HPUX_SOURCE -I. -I../../include -fno-gnu-linker trbg.cpp

1소개#

어찌 어찌 하다보니 솔라리스용 애플리케이션을 HP-UX로 포팅하는 일을 맡게 되었다. 그런데 왠걸 개발 환경 만들기 부터가 그리 쉽지 않다. 이 문서에는 HP-UX에 개발환경을 만들고 솔라리스 애플리케이션을 포팅하는 과정에 대한 내용을 담고 있다.

2개발환경 만들기#


2.1목표 시스템의 환경#

포팅하기로 결정한 HP시스템의 정보는 다음과 같다.
# uname -aHP-UX antispam B.11.00 U 9000/800 1704907636 unlimited-user license
HP-UX 11버전이라는 것은 그럭저럭 알겠다. 아마도 U 9000/800이 하드웨어 모델인것 같은데 현재로써는 확실하지가 않다.uname(2)함수를 이용해서 직접 간단한 하드웨어 정보를 얻어와야 할것 같다. 이것은 gcc를 설치한 후 간단한 프로그램을 작성해서 알아보도록 하겠다.

다음은 디스크 정보다.
$ df -k/var                   (/dev/vg00/lvol4       ) :  9926576 total allocated Kb                                                   9730106 free allocated Kb                                                    196470 used allocated Kb                                                         1 % allocation used/stand                 (/dev/vg00/lvol1       ) :   269032 total allocated Kb                                                    237968 free allocated Kb                                                     31064 used allocated Kb                                                        11 % allocation used/                      (/dev/vg00/lvol3       ) :  9965100 total allocated Kb                                                   8523748 free allocated Kb                                                   1441352 used allocated Kb                                                        14 % allocation used
출력결과물이 솔라리스나 리눅스에 비해 조악하다는 느낌이 들지만 알아 먹는데 큰 문제는 없는것 같다.

리눅스의 경우 대부분의 하드웨어 정보를 /proc의 값들을 읽는정도로 확인가능하고 솔라리스 역시 /usr/platform의 정보들과 몇가지 명령들을 통해서 어렵잖게 확인할 수 있다. 안타깝게도 HP-UX는 이번이 처음이라서 전용의 시스템도구가 있는지를 확인할 수 없었다. 그래서 간단하게 top을 이용해서 필요한 정보를 얻기로 마음먹었다.

몇몇 유닉스의 경우 top이 설치되어 있지 않는 경우도 있어서 조마조마하게 실행했는데 다행히도 설치되어 있었다. 다음은 top출력 결과다.

System: joinc                                      Fri Nov 28 14:07:44 2003Load averages: 0.52, 0.54, 0.54135 processes: 129 sleeping, 6 runningCpu states:CPU   LOAD   USER   NICE    SYS   IDLE  BLOCK  SWAIT   INTR   SSYS 0    0.10   0.0%   0.0%   0.2%  99.8%   0.0%   0.0%   0.0%   0.0% 1    0.94 100.0%   0.0%   0.0%   0.0%   0.0%   0.0%   0.0%   0.0%---   ----  -----  -----  -----  -----  -----  -----  -----  -----avg   0.52  50.0%   0.0%   0.2%  49.8%   0.0%   0.0%   0.0%   0.0%Memory: 708208K (679788K) real, 1015228K (985792K) virtual, 19120K free  Page# 1/13CPU TTY     PID USERNAME PRI NI   SIZE    RES STATE    TIME %WCPU  %CPU COMMAND 1   ?     8105 root     236 20 23276K  4452K run     71:04 100.10 99.93 swinstall....
대부분의 필요한 정보를 모두 얻을 수 있었다.

2.1.1패키지 설치방법#
HP-UX는 depot라는 독자적인 패키징 시스템을 가지고 있다. 모든 패키지 파일들은.depot확장자를 가진다.

depot 패키징 시스템을 지원하기 위해서 HP-UX는 swinstall이라는 프로그램을 제공한다. 설치 방법은 아래와 같이 매우 간단하다.
# swinstall -s /tmp/sw/gcc-3.3.2-sd-11.00.depot
그러면 다음과 같은 관리 화면이 나올 것이다. 패키지 목록에서 스페이스바를 누르면 패키지를 선택할 수 있다. 그리고 나서 Actions->install을 클릭하면 패키지가 설치된다.

사용자 삽입 이미지

설치될 패키지는 반드시 절대경로로 지정되어져야 한다. 그렇지 않을 경우 대부분 설치에 실패 할 것이다.

패키지가 설치될 때 어떤 디렉토리로 설치되었는지를 확인해야 할건데, 이때는 위의 패키지 선택화면의 패키지 목록에서엔터키를 누르면 된다. 그러면 아래의 그림처럼 설치될 패키지의 모든 파일과 경로명이 출력된다.

사용자 삽입 이미지

사실 패키징설치와 관리에 대한 자세한 내용을 알기 위해서는 swinstall소프트웨어에 대한 자세한 설명이 필요하겠지만, 여기에서는 설치방법을 깨우치는 정도로 간단히 넘어가도록 하겠다.

2.2GNU Package 다운로드/설치#

HP-UX의 GNU 패키지들은
사용자 삽입 이미지
hpux.cs.utah.edu에서 다운로드 받을 수 있다. 대부분의 패키지들이 준비되어 있으므로 필요한 패키지를 다운 받아서 설치하도록 하자.

중요한 패키지는 아마도 gcc, make, cvs, vim(물론 vi가 깔려있기는 하지만 vim보다는 아무래도 불편하다), texinfo, binutil(gcc-3.x의 경우 포함되어 있으므로 별도로 설치할 필요는 없다.), bash shell 등이 될것이다.

위의 패키지외에도 gettext와 iconv 패키지를 별도로 설치해야 한다. gettext를 설치하지 않는다면 다음과 같은 에러메시지를 출력할 것이다.
Can't open shared library: /usr/local/lib/libintl.sl
참고로 gettest 패키지는 멀티바이트 언어 메시지를 지원하기 위한 목적으로 사용되며 iconv는 문자셋 변환을 위해 사용되는 GNU툴들이다.

2.3개발환경 테스트#

개발환경 테스트라고 해봤자. C/C++코드 몇개 만들어서 돌려보고 외부라이브러리들을 제대로 링크하는지, pthread는 제대로 지원되는지를 확인하는 정도다. C코드야 뭐 별로 테스트할게 없겠지만 C++의 경우 필자가 즐겨 사용하는 STL을 무리 없이 지원하고 있는지 확실히 확인해봐야 할 필요가 있었다. 다행히 매우 복잡하게 STL을 사용하는 코드들도 문제 없이 컴파일 되고 실행되는걸 확인했다.

그다음이 Makefile을 통한 프로젝트 관리가 다른 리눅스나 솔라리스와 마찬가지 인가 하는 문제인데 역시 수정없이 그대로 사용할 수 있었다. 다만 소켓을 사용하는 애플리케이션의 컴파일을 위해서 리눅스와 같이 socket 라이브러리를 링크 시킬 필요가 없었다. 솔라리스에서 소켓 라이브러리를 링크시켰던 경험으로 HP에서 그대로 make시킬경우 에러가 발생할 것이다. 물론 이문제는Autoconfig를 이용해서 해결 가능하겠지만 우선은 논외로 하겠다.

2.3.1공유 라이브러리 사용의 문제#
Linux와 솔라리스 운영체제에서 공유라이브러리 형태로 사용하던 코드중 일부가 HP-UX에서는 제대로 링크 되지 않는 문제가 발생했다. google를 찾아본 결과 gcc특성에 따른 문제라고 되어 있고 뚜렷한 해결방법이 제시되어 있지 않았다. 다른 여러 GNU 프로그램들이 포팅되어 있는 것으로 봐선 분명 문제 해결방법이 있을 거라고 생각된다. 그러나 우선은 정적라이브러리 형태로 만들고 이것을.a아카이브로 묶어서 사용하기로 했다.

문제의 에러메시지와 Makefile의 내용은 테스트가 끝나는대로 제공하도록 하겠다.

2.3.2컴파일시 주의해야 할점#
  1. typedef된 타입들
역시Autoconfig를 이용하면 효과적으로 피해 갈 수 있는 문제인데,ulong,ushort,uint,ushort_t와 같은 typedef값들이 정의되어 있지 않다. 다른 운영체제로의 포팅을 염두에 두지 않고 작성되었다면 이와 관려된 에러메시지를 자주 만날 수 있을 것이다.
/main.c:27: error: 'ulong' is used as a type, but    is not defined as a type./main.c:28: error: 'ulong' is used as a type, but    is not defined as a type.

가능하면 ulong, ushort와 같은 typedef값보다는unsigned long,unsigned short int등의 값을 직접 사용하도록 하자.

이미 만들어진 코드라서 바꾸기가 좀 힘들다면 아래와 같은 방법을 사용하면 된다.
#ifndef ulongtypedef unsigned long ulong;/* 자신을 재 지향하는 매크로는 어떤것이든 #ifdef 에 걸릴수 있도록 하는것이 목적 */#define ulong ulong#endif

3HP시스템 의존적인 개발환경#

대부분의 유닉스 코드들은 개발환경이 달라지더라도 크게 변경되는 경우는 없다. 그러나 커널로 부터 직접 정보를 얻어야 하는 것들의 경우 크게 달라질 수 있는데 시스템 정보들이 아마도 가장 대표적인 경우일 것이다.

이번 장에서는 이러한 HP의존적인 개발환경중에서 시스템 정보쪽에 대해서 집중적으로 알아보도록 하겠다.

3.1Proc 파일시스템의 지원#

(필자가 자주접하는)솔라리스나 리눅스나 /proc파일시스템을 이용해서 많은 정보들을 얻어올 수 있다. 특히 리눅스의 경우는 프로세스의 정보 뿐아니라 필요한 거의 대부분의 정보를 얻어 올 수 있다.

필자가 알기로 /proc파일 시스템은 대부분의 유닉스 운영체제에서 지원하는 것으로 알고 있었기 때문에 우선 /proc의 내용확인을 시도 했다.허걱그러나 /proc가 존재하지 않았다. 안타깝게도 HP는 /proc파일 시스템을 지원하지 않고 있었던 것이다. 그렇다는 것은 운영체제 에서 제공하는 운영체제 의존적인 시스템함수를 통해서 이러한 정보들을 얻어올 수 밖에 없다는 얘기가 된다.

3.2pstat(2)를 통한 시스템 정보 수집#

HP는 시스템정보의 접근을 위해서pstat(2) 함수군을 제공한다. 이 함수군에 있는 함수들을 이요해서 기본적인 시스템정보, 프로세서(CPU), 프로세스, 가상메모리/물리적 메모리, (운영체제 전역적인)System V IPC, LWP, 열린파일.. 등에 대한 매우 상세한 정보를 얻을 수 있다. 기본적인 방법만 알고 있다면 솔라리스나 리눅스보다 오히려 손쉽게 필요한 정보들을 얻어낼 수 있다.


이름을 보면 무슨일을 하는 함수인지 감을 잡을 수 있을 것이다. 이러한 함수들에 대한 자세한 정보는 man페이지를 활용해야 한다.pstat(2)man 페이지를 참고하기 바란다.

3.3pstat(2)관련 구조체들#

pstat에서 제공하는 함수들을 제대로 사용하려면 각 구조체에 대한 대략 적인 내용을 알고 있어야 한다. 여기에서는 중요한 구조체에 대해서 설명한다. 이것 저것 구조체에 대해서 복잡하게 설명하는 것보다. 헤더파일을 참고하는게 가장 확실한 방법일 것 같아서 헤더파일을 제공하기로 했다.

4셈플코드#

다음은 시스템정보를 얻어오는 간단한 예제코드다. HP-UX에 접근할 수 있는 환경이라면 한번 테스트해 보기 바란다.
#include <sys/param.h>#include <sys/pstat.h>#include <sys/unistd.h>#include <string.h>#include <pwd.h>intmain(){    struct pst_dynamic psd;    struct pst_processor *psp;    struct pst_status pst;    struct pst_static pmt;    int i, count, idx=0, j;    int cpu_v[PST_MAX_CPUSTATES];    int cpu_time = 0;    int total_time = 0;    int page_size = 0;    int last_cpu_time[16];    idx=0;    int size = 0;    struct passwd *pass_info = NULL;    char username[256] = {0x00, };    for (i = 0; i < 16; i ++)    {        last_cpu_time[i] = -1;    }    // 페이지 크기를 얻어온다.     // 페이지 크기는 메모리와 같은 자원의 크기를 검사하는데 중요하게 사용된다.     if (pstat_getstatic(&pmt,sizeof(pmt), (size_t)1, 0) != -1)    {        page_size = pmt.page_size;    }    else    {perror("static error");    }    // 동적으로 변경되는(dynamic) 정보들을 얻어온다.      // 메모리 크기가 가정 대표적인 정보들일 것이다.     if (pstat_getdynamic(&psd,sizeof(psd), (size_t)1, 0) != -1)    {        // 프로세서의 갯수를 얻어온다.         // 프로세서의 정보를 얻기 위해 필요하다.         size_t nspu = psd.psd_proc_cnt;        psp = (struct pst_processor *)malloc(nspu *sizeof(*psp));        // 메모리 정보를 출력한다.         printf("REAL MEM : %d(%d), VM : %d(%d)\n",                 psd.psd_rm*page_size,     // 리얼 메모리 공간                psd.psd_free*page_size,   // 남는 메모리 공간                psd.psd_vm*page_size,     // 가상 메모리 공간                psd.psd_avm*page_size);   // 남아있는 가상 메모리 공간     }    // 프로세서(CPU)의 사용정보를 얻어온다.       if (pstat_getprocessor(psp,sizeof(*psp), nspu, 0) != -1)    {        int i;        int total_execs = 0;        int last_time = 0;        // 프로세서의 갯수만큼 정보를 얻어온다.         for (i = 0; i < nspu; i++)        {            total_time = 0;            last_time  = last_cpu_time[i];            if (last_time > 0)            {                last_cpu_time[i] = psp[i].psp_cpu_time[0];                printf("#%d processor %d\n", i,                    last_cpu_time[i] - last_time);            }            else            {                last_cpu_time[i] = psp[i].psp_cpu_time[0];printf("JUMP\n");            }        }    }sleep(1);    // 모든 프로세스의 상세 정보를 얻어온다.     // 한번에 10개씩 프로세스의 정보를 얻어와서 pst에 저장한다.      // idx는 PID와 별로로 프로세스에 부여되는 일련번호다.     // pstat_getproc는 idx이상의 인덱스번호를 가지는 프로세스 정보를 얻어온다.       // 아래의 경우 3번째 인자가 1인데, 하나씩 얻어와서 저장하라는 뜻이다.      // 필요에 따라 한번에 여러개의 프로세스 정보를 얻어와서 pst에 저장할 수 있다.     while((count = pstat_getproc(&pst,sizeof(pst), 1, idx)) > 0)    {        size =pst[i].pst_vtsize + pst[i].pst_vdsize + pst[i].pst_vssize             + pst[i].pst_dsize + pst[i].pst_tsize;        // 만약 pst_uid에 대해서 password 엔트리가 있다면 유저이름을 출력한다.           // 때에 따라서 잘못된 UID로된 프로세스가 생길 수 있으므로 반드시 NULL 검사를        // 해줘야 한다.           if ((pass_info = getpwuid(pst[i].pst_uid)) != NULL)        {            sprintf(username,"%s", pass_info->pw_name);        }              printf("commd %s %d pst_pid %d %d %s %d %d\n",                    username,                    pst[i].pst_uid,                         pst[i].pst_procnum,                         pst[i].pst_pid,                    pst[i].pst_ucomm, pst[i].pst_cpu, size*page_size/8/1024);        // 인덱스를 1증가 시켜서 다음 프로세스 정보를 얻어오도록 한다.          idx = pst.pst_idx + 1;    }}

'Unix Linux' 카테고리의 다른 글

[펌] Solaris Kernel Statistics  (0) 2006.01.26
Sun Studio Collection  (0) 2005.11.09
Solaris Reference Manual Collection  (0) 2005.11.09