[제4장] 유닉스 환경

돼지털라이프 | 2007/06/25 19:01

=================================================================
  * Subject : [제4장] 유닉스 환경
  * Writer: w0rm9 (research.hackerschool.org)
  * Date: 2004/01/18
=================================================================


/* 테스트한 소스는 prosager님이 스터디 시간에 쓰셨던 소스를 사용하거나
 * 조금 변경해서 사용했습니다.
 * 그리고 스터디 시간에 하지 않았던 함수는 넣지 않았습니다.
 */


0x01. 프로그램 인수

■ argc, argv
사용법)
int main(int argc, char *argv[])
=> argc는 프로그램 인수의 개수, argv는 인수 자체를 표현하는 문자 스트링의 배열, argv[0]은 프로그램의 이름

테스트)
[w0rm9@work UNIX]$ cat argv.c
#include <stdio.h>

int main(int argc, char *argv[]) {

        int arg;

        for(arg=0; arg < argc; arg++) {
                printf("%s\n",argv[arg]);
        }
}
[w0rm9@work UNIX]$ gcc -o argv argv.c
[w0rm9@work UNIX]$ ./argv w0rm9 babo hahahaa
./argv
w0rm9
babo
hahahaa


■ getopt
사용법)
#include <unistd.h>

int getopt(int argc, char *const argv[], const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
=> optarg는 옵션이 값을 가질 때의 값을 가진다.(?)
   optind는 처리할 다음 인수의 색인으로 설정된다.
   optopt는 인식되지 않는 옵션이 있다면, ?를 반환하고, 이것을 optopt에 저장한다.
   opterr은 잘 모르겠음-_-;;, 자세한 설명은 테스트를 통해서..

테스트)
[w0rm9@work UNIX]$ cat getopt.c
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[]) {

        int opt;

        while( (opt = getopt(argc, argv, "if:lr") ) != -1 ) {
                printf("------------------\n");
                printf("opt: %d\n",opt);
                printf("optind: %d\n", optind);
                printf("opterr: %d\n", opterr);
                printf("optopt: %d\n", optopt);
                printf("optarg: %s\n", optarg);
                switch(opt) {
                case 'i':
                case 'l':
                case 'r':
                        printf("------------------\n");  //옵션 i, l, r을때 출력
                        printf("selected optino i,l,r\n");
                        printf("optind: %d\n", optind);
                        printf("opterr: %d\n", opterr);
                        printf("optopt: %d\n", optopt);
                        printf("optarg: %s\n", optarg);
                        break;

                case 'f':
                        printf("------------------\n");  //옵션 f일때 출력
                        printf("selected option f\n");
                        printf("optind: %d\n", optind);
                        printf("opterr: %d\n", opterr);
                        printf("optopt: %d\n", optopt);
                        printf("optarg: %s\n", optarg);
                        break;
                case ':':
                        printf("------------------\n");
                        printf("option needs a value\n");
                        printf("optind: %d\n", optind);
                        printf("opterr: %d\n", opterr);
                        printf("optopt: %d\n", optopt);
                        printf("optarg: %s\n", optarg);
                        break;
                case '?':
                        printf("------------------\n");  //설정되지 않는 옵션일때 출력
                        printf("err!! no opt!\n");
                        printf("optind: %d\n", optind);
                        printf("opterr: %d\n", opterr);
                        printf("optopt: %d\n", optopt);
                        printf("optarg: %s\n", optarg);
                        break;
                }
        }
        printf("------------------\n");
        printf("opt: %d\n",opt);
        printf("optind: %d\n", optind);
        printf("opterr: %d\n", opterr);
        printf("optopt: %d\n", optopt);
        printf("optarg: %s\n", optarg);
}
[w0rm9@work UNIX]$ gcc -o getopt getopt.c
[w0rm9@work UNIX]$ ./getopt -i -f babo -q -lr
------------------
opt: 105   // 십진수 105는 아스키값 i에 해당된다. 즉, 첫번째 옵션
optind: 2   // 다음에 처리할 옵션이 -f, argv[2]에 해당된다. 그래서 2
opterr: 1
optopt: 63   // 아직 설정되지 않은 옵션이 나오지 않았으므로 63을 가진다. 63은 아스키값으로 ? 에 해당된다.
optarg: (null)   // 옵션이 값을 가지지 않기 때문에 아직 null이다.
------------------
selected optino i,l,r
optind: 2
opterr: 1
optopt: 63
optarg: (null)
------------------
opt: 102   // 십진수 102는 아스키값 f에 해당된다. 두번째로 준 옵션 -f이다.
optind: 4   // 다음에 처리할 옵션이 -q이다. argv[4]에 해당된다.
opterr: 1
optopt: 63   // 역시 설정되지 않은 옵션이 없어서 아직은 63
optarg: babo   // -f 옵션이 babo라는 값을 가진다. 그 값을 optarg에..
------------------
selected option f
optind: 4
opterr: 1
optopt: 63
optarg: babo
./getopt: invalid option -- q
------------------
opt: 63    // -q는 설정되지 않은 옵션이다. 설명대로 63을 반환했다. 즉, ? 를 반환
optind: 5   // 다음 처리할 옵션이 -lr. 즉, argv[5]이다.
opterr: 1
optopt: 113   // 113은 q에 해당된다. 즉 opt에 가지고있던 ?을 반환한 뒤 q값을 가지게 된다.
optarg: (null)   // -q엔 값을 가지지 않으므로 null
------------------
err!! no opt!
optind: 5
opterr: 1
optopt: 113
optarg: (null)
------------------
opt: 108   // 108은 l 에 해당된다. -lr에서의 l 이다.
optind: 5   // 다음에 처리할 옵션이 r 이 역시 argv[5]에 해당된다.
opterr: 1
optopt: 113   // 이 전에 바뀐 133 (== q)를 그대로 가지고 있음.
optarg: (null)
------------------
selected optino i,l,r
optind: 5
opterr: 1
optopt: 113
optarg: (null)
------------------
opt: 114   // 114는 r에 해당된다. -lr에서의 r 을 나타낸다.
optind: 6   // 다음에 처리할 옵션이 argv[6]이다. 그러나 없다. 어떻게 되는지 두고보자.-_-;
opterr: 1
optopt: 113   // 바뀐 q 로 그대로 유지..
optarg: (null)
------------------
selected optino i,l,r
optind: 6
opterr: 1
optopt: 113
optarg: (null)
------------------
opt: -1    // getopt는 처리할 옵션이 더 이상 없을땐 -1을 반환한다. argv[6]는 없다. 그래서 -1 반환
optind: 6
opterr: 1
optopt: 113
optarg: (null)


0x02. 환경 변수

■ putenv, getenv
사용법)
#include <stdlib.h>

char *getenv(const char *name);
int putenv(const char *string);
=> getenv 함수는 환경에서 주어진 이름을 가지는 스트링을 찾고 해당 이름과 관련된 값을 반환한다.
   putenv 함수는 name=value 형식으로 스트링을 받아들이고, 현재 환경에 추가한다.
   단, 환경변수의 값은 자식 프로세스인 프로그램에서 부모 프로세스인 쉘로 전달되지 않는다.

테스트)
[w0rm9@work UNIX]$ cat env.c
#include <stdio.h>
#include <unistd.h>

int main(int argc,char *argv[]) {

        char *value, *string;

        value = malloc(128);
        string = malloc(128);

        value = getenv(argv[1]);
        printf("$%s= %s\n",argv[1], value);

        value = argv[2];
        strcpy(string,"WG=");
        strcat(string,value);

        if(putenv(string) !=0) {
                printf("err\n");
                free(string);
                exit(1);
        }

        value = getenv("WG");
        printf("$WG= %s\n", value);

}
[w0rm9@work UNIX]$ gcc -o env env.c
env.c: In function `main':
env.c:8: warning: assignment makes pointer from integer without a cast
env.c:9: warning: assignment makes pointer from integer without a cast
env.c:11: warning: assignment makes pointer from integer without a cast
env.c:24: warning: assignment makes pointer from integer without a cast
[w0rm9@work UNIX]$ ./env HOME w0rm9
$HOME= /home/w0rm9
$WG= w0rm9


■ environ 변수
사용법)
#include <stdlib.h>

extern char **environ;
=> 환경변수라 불리우는 문자열의 배열은  프로세서가 시작될때, exec에 의해 만들어지고,
변환을 통해 'name=value'의 형태를 취하게 된다.


0x03. 시간과 날짜

■ gmtime
사용법)
#include <time.h>

time_t time(time_t *tloc);
struct tm *gmtime(const time_t timeval);
struct tm *localtime(const time_t *timeval);
char *ctime(const time_t *timeval);
=> gmtime함수는 time 함수를 통해 얻은 저수준 시간값을 구조체로 변환
   localtime함수는 지역 시간대와 일광 절약 시간제에 대해 조절된 값을 가지는 구조체 반환
   ctime은 저수준 시간값을 구하기 위해 time을 호출한 뒤, ctime을 통해 읽기 쉬운 스트링으로 변환하여 출력한다.

□ 구조체 tm의 멤버
 int tm_sec  0~61까지의 초
 int tm_min  0~59까지의 분
 int tm_hour  0~23까지의 시
 int tm_mday  1~31까지의 일
 int tm_mon  0~11까지의 월(1월은 0)
 int tm_year  1900 이후의 년
 int tm_wday  0~6까지의 요일(일요일은 0)
 int tm_yday  0~365까지의 날짜
 int tm_isdst  일광 절약 시간제의 적용 여부

테스트)
[w0rm9@work UNIX]$ cat time2.c
#include <time.h>
#include <stdio.h>

int main() {
        struct tm *tm_gmt, *tm_lmt;
        time_t the_time;

        (void)time(&the_time);

        printf("time func: %ld\n", the_time);

        printf("ctime func: %s", ctime(&the_time));

        tm_gmt = gmtime(&the_time);

        printf("gmtime func: %02d/month %02d/day %02d/hour %02d/min %02d/sec\n",tm_gmt->tm_mon+1,tm_gmt->tm_mday,tm_gmt->tm_hour, tm_gmt->tm_min, tm_gmt->tm_sec);
       
        tm_lmt = localtime(&the_time);

        printf("localtime func: %02d/month %02d/day %02d/hour %02d/min %02d/sec\n", tm_lmt->tm_mon+1, tm_lmt->tm_mday, tm_lmt->tm_hour, tm_lmt->tm_min, tm_lmt->tm_sec);
}
[w0rm9@work UNIX]$ gcc -o time2 time2.c
[w0rm9@work UNIX]$ ./time2;date
time func: 1074449016
ctime func: Mon Jan 19 03:03:36 2004
gmtime func: 01/month 18/day 18/hour 03/min 36/sec
localtime func: 01/month 19/day 03/hour 03/min 36/sec
2004. 01. 19. (월) 03:03:36 KST


0x04. 임시 파일

■ tmpnam, tmpfile
사용법)
#include <stdio.h>

char *tmpnam(char *s);
FILE *tmpfile(void);
=> tmpname은 s에 파일 이름이 저장될 것이다.
   tmpfile 함수는 임시파일을 가리키는 스트림 포인터를 반환한다.

테스트)
[w0rm9@work UNIX]$ cat tmp.c
#include <stdio.h>

int main()
{
        char tmpname[L_tmpnam];
        char *filename;
        FILE *tmpfp;

        filename =tmpnam(tmpname);

        printf("%s\n",filename);

        tmpfp=tmpfile();

        if(tmpfp)
                printf("ok\n");
        else
                printf("error\n");
        exit(0);
}
[w0rm9@work UNIX]$ gcc -o tmp tmp.c
/tmp/ccugOihA.o(.text+0x18): In function `main':
: the use of `tmpnam' is dangerous, better use `mkstemp'
[w0rm9@work UNIX]$ ./tmp
/tmp/fileQEtvwK
ok


0x05. 사용자 정보

■ getuid, getlogin
사용법)
#include <sys/types.h>
#include <unistd.h>

uid_t getuid(void);
char *getlogin(void);
=> getuid 함수는 프로그램과 관련된 uid를 반환
   getlogin 함수는 현재 사용자와 관련된 로그인 이름을 반환


■ getpwuid, getpwnam
사용법)
#include <sys/types.h>
#include <pwd.h>

struct passwd *getpwuid(uid_t uid);
struct passwd *getpwnam(const char *name);
=> getpwuid 함수는 uid에 대응하는 passwd 구조체에 대한 포인터를 반환
   getpwnam 함수는 로그인 이름에 대응하는 passwd 구조체에 대한 포인터를 반환

□ pwd.h에 정의된 구조체 passwd의 멤버
 char *pw_name  사용자의 로그인 이름
 uid_t pw_uid  UID 번호
 gid_t pw_gid  GID 번호
 char *pw_dir  사용자의 홈 디렉토리
 char *pw_shell  사용자의 기본 쉘

테스트)
[w0rm9@work UNIX]$ cat getpw.c
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>

int main( void )
{
        struct passwd *pws, *pws2;
        char *id;
        uid_t uid;
        if( (id = (char *)malloc(70)) == NULL )
        {
                perror("error");
                exit(1);
        }

        printf( "Your ID input : " );
        scanf( "%s" , id );
        pws = getpwnam( id );
        if( pws == NULL ) {
                printf("error\n");
                exit(1);
        }

        printf( "%s infomation : " , id );
        printf( "name = %s , uid = %d , gid = %d , home = %s , shell = %s\n" ,
                pws->pw_name , pws->pw_uid , pws->pw_gid , pws->pw_dir , pws->pw_shell );

        printf( "Your UID input : " );
        scanf( "%d" , &uid );
        pws2 = getpwuid( uid );
        if( pws2 == NULL ) {
                printf("error\n");
                exit(1);
        }

        printf( "%d infomation : " , uid );
        printf( "name = %s , uid = %d , gid = %d , home = %s , shell = %s\n" ,
                pws2->pw_name , pws2->pw_uid , pws2->pw_gid , pws2->pw_dir , pws2->pw_shell );

        return 0;
}
[w0rm9@work UNIX]$ gcc -o getpw getpw.c
[w0rm9@work UNIX]$ ./getpw
Your ID input : w0rm9
w0rm9 infomation : name = w0rm9 , uid = 519 , gid = 519 , home = /home/w0rm9 , shell = /bin/bash
Your UID input : 519
519 infomation : name = w0rm9 , uid = 519 , gid = 519 , home = /home/w0rm9 , shell = /bin/bash


0x06. 호스트 정보

■ gethostname
사용법)
#include <unistd.h>

int gethostname(char *name, size_t namelen);
=> 컴퓨터의 네트워크 이름을 스트링 name 내에 저장


■ uname
사용법)
#include <sys/utsname.h>

int uname(struct utsname *name);
=> 호스트 정보를 name 파라미터가 가리키는 구조체 내에 저장한다.

□ sys/utsname.h에 정의된 utsname 구조체의 멤버들
 char sysname[]  운영체제 이름
 char nodename[]  호스트 이름
 char release[]  시스템의 릴리즈 단계
 char version[]  시스템의 버전 번호
 char machine[]  하드웨어 형태

테스트)
[w0rm9@work UNIX]$ cat host.c
#include <unistd.h>
#include <stdio.h>
#include <sys/utsname.h>

int main( void )
{
        struct utsname name;
        char com[256];

        gethostname(com, 255);

        if( uname(&name) < 0 ) {
                perror("uname");
                exit(1);
        }

        printf("컴퓨터의 네트워크 이름: %s\n", com);
        printf("운영체제 이름: %s\n", name.sysname);
        printf("호스트 이름: %s\n", name.nodename);
        printf("시스템의 릴리즈 단계: %s\n", name.release);
        printf("시스템의 버전 번호: %s\n", name.version);
        printf("하드웨어 형태: %s\n", name.machine);
}

[w0rm9@work UNIX]$ gcc -o host host.c
[w0rm9@work UNIX]$ ./host
컴퓨터의 네트워크 이름: work.hackerschool.org
운영체제 이름: Linux
호스트 이름: work.hackerschool.org
시스템의 릴리즈 단계: 2.4.24
시스템의 버전 번호: #1 SMP 2004. 01. 08. (목) 21:22:31 KST
하드웨어 형태: i686


0x07. 로그 기능

■ syslog
사용법)
#include <syslog.h>

void syslog(int priority, const char *message, arguments...);
=> priority 는 우선순위의 단계에 따라 로그 메시지의 동작 방법을 제어하고
   message 에는 메시지의 근원을 기록한다.

□ 우선순위 단계
 LOG_EMERG  비상 사태
 LOG_ALERT  데이터베이스의 파괴와 같은 높은 우선순위의 문제
 LOG_CRIT  하드웨어 실패와 같은 치명적인 에러
 LOG_ERR   헤러
 LOG_WARNING  경고
 LOG_NOTICE  주의를 요구하는 특별한 조건
 LOG_INFO  정보 메시지
 LOG_DEBUG  디버그 메시지

테스트)
[w0rm9@work UNIX]$ cat log.c
#include <syslog.h>
#include <stdio.h>

int main() {

        FILE *f;

        f = fopen("not_here","r");
        if(!f)
                syslog(LOG_ERR|LOG_USER,"oops,Wg log test - %m\n");
        exit(0);
}
[w0rm9@work UNIX]$ gcc -o log log.c
[w0rm9@work UNIX]$ ls -al /var/log/messages
-rw----r--    1 root     root        42505  1월 19 04:00 /var/log/messages
권한이 없어서 테스트 못했음


0x08. 리소스와 제한

■ getpriority, setpriority
사용법)
#include <sys/resource.h>

int getpriority(int which, id_t who);
int setpriority(int which, id_t who, int priority);
=> getpriority 함수는 현재 프로세스의 우선순위를 구하기 위해서 호출
   setpriority 함수는 새로운 우선 순위를 설정

□ which 파라미터
 PRIO_PROCESS  who는 프로세스 식별자이다.
 PRIO_PGRP  who는 프로세스 그룹이다.
 PRIO_USER  who는 사용자 식별자이다.

테스트)
[w0rm9@work UNIX]$ cat reso.c
#include <sys/resource.h>
#include <stdio.h>

int main() {

        int i,j,l;
        int a=1,b=1;

        setpriority(PRIO_PROCESS, getpid(), 20 ); // 우선순위를 20으로 설정

        i = getpriority(PRIO_PROCESS, getpid());
        printf("우선순위: %d\n",i);
        for(j=0;j<50000;j++) {
        for(l=0;l<5000;l++) {
                a = b * a +1 *3;
        }
        }
}
[w0rm9@work UNIX]$ gcc -o reso reso.c
[w0rm9@work UNIX]$ time ./reso
우선순위: 19

real    0m4.004s
user    0m3.970s
sys     0m0.000s
[w0rm9@work UNIX]$ cat reso.c
#include <sys/resource.h>
#include <stdio.h>

int main() {

        int i,j,l;
        int a=1,b=1;

        setpriority(PRIO_PROCESS, getpid(), 0 ); // 우선순위를 0으로 설정

        i = getpriority(PRIO_PROCESS, getpid());
        printf("우선순위: %d\n",i);
        for(j=0;j<50000;j++) {
        for(l=0;l<5000;l++) {
                a = b * a +1 *3;
        }
        }
}
[w0rm9@work UNIX]$ gcc -o reso reso.c
[w0rm9@work UNIX]$ time ./reso
우선순위: 0

real    0m3.964s
user    0m3.950s
sys     0m0.000s


■ getrlimit, setrlimit
사용법)
#include <sys/resource.h>

int getrlimit(int resource, struct rlimit *r_limit);
int setrlimit(int resource, const struct rlimit *r_limit);
=> getrlimit 시스템 리소스에 대한 제한을 구하기 위해서 호출
   setrlimit 시스템 리소스에 대한 제한을 설정

□ sys/resource.h에 정의된 구조체 rlimit의 멤버
 rlim_t rlim_cur  현재 소프트 제한
 rlim_t rlim_max  하드 제한

□ sys/resource.h에 정의된 resource 파라미터
 RLIMIT_CORE  핵심 덤프 파일 크기의 바이트 단위 제한
 RLIMIT_CPU  CPU 시간의 초 단위 제한
 RLIMIT_DATA  데이터 세그먼트의 바이트 단위 제한
 RLIMIT_FSIZE  파일 크기의 바이트 단위 제한
 RLIMIT_NOFILE  열린 파일 수의 제한
 RLIMIT_STACK  스택 크기의 바이트 단위 제한
 RLIMIT_AS  어드레스 공간의 바이트 단위 제한


■ getrusage
사용법)
#include <sys/resource.h>

int getrusage(int who, struct rusage *r_usage);
=> 파리미터 r_usage가 가리키는 rusage 구조체에 CPU 시간 정보를 저장한다.

□ sys/resource.h에 정의된 rusage의 멤버
 struct timeval ru_utime  사용된 사용자 시간
 struct timeval ru_stime  사용된 시스템 시간

□ who 파라미터
 RUSAGE_SELF  현재 프로그램에 대한 사용 정보를 반환한다.
 RESAGE_CHILDREN  자식 프로세스의 사용 정보를 포함한다.


/* 감사합니다. */
_eof_

Trackback Address :: http://badnom.com/trackback/286
Name
Password
Homepage
Secret
< PREV |  1  |  ...  746  |  747  |  748  |  749  |  750  |  751  |  752  |  753  |  754  |  ...  983  |  NEXT >