본문 바로가기

대학교시절

운영체제 과제 #1 (fork 와 exec 사용하기)

과제 1


1) Command Execution (20%)


UNIX Command를 아규먼트로 취급하여 실행하는 프로그램을 작성하라.

프로그램 실행은 다음과 같은 형식을 따른다. (%는 shell prompt)

예를 들어 program_name이 hw01이고, command가 cat test.c 라면,

%hw01 cat test.c를 실행하면 test.c의 내용이 출력된다.



2) Process Statistics (20%)


위의 프로그램에서 command가 실행된 후에 command에 사용된 다음과 같은 시스템 리소스에 대한 프로세스 통계를 출력하는 기능을 추가한다. 프로세스 통계에 대한 정보는 getrusage()를 참고한다.

프로세스 통계


 - 사용된 CPU시간

 - command가 실행되고 경과된 시간

 - 프로세스가 선점된 횟수

 - 프로세스가 자발적으로 cpu점유를 포기한 횟수



3) Basic Command Shell (30%)


위의 프로그램을 확장하여 command line 아규먼트가 없으면 쉘처럼 동작할 수 있도록 확장한다. 아래 예와 같이 프로그램은 명령어를 입력 받도록 프롬프트 상태가 되어야 한다. 프롬프트 상태가 되면 command명령을 입력 받아 명령을 수행하고 프로세스 통계를 출력 해야 한다. 마지막으로, 쉘 내부명령어 exit를 통해 쉘 프로그램을 종료하도록 한다.

아래의 예제에서 “<>”는 주석, hw01 prompt 는 “->”, shell prompt 는 “%”로 표시.


Output Example 1

1 % ./hw01

2 ->cat test.c

3 < test.c의 내용을 출력 >

4 < cat command에 대한 통계 출력 >

5 ->ls -al

6 < 현재 디렉토리의 파일들을 리스팅 >

7 < ls command에 대한 통계 출력 >

8 ->exit

9 % < shell prompt로 돌아감 >


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/times.h>
#include <sys/types.h>
#include <sys/resource.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
/*
프로그램 작성자 : americano@korea.ac.kr
개발 날짜 : 2012-10-10
*/
int main(int argc, char** argv){
    int i; //루프를 위한 변수
    int status; //자식 프로세스가 종료 될 때 상태 값을 받기 위한 변수
 
    struct timeval start_command, end_command; //command가 실행되고 경과된 시간을 측정하기 위한 자료형
    struct timeval start_UCPU, start_SCPU, end_UCPU, end_SCPU; //사용된 CPU시간을 측정하기 위한 자료형
    struct rusage usage; //프로세스의 상태 값을 받기 위한 자료형
    int first_CPU_giveup, last_CPU_giveup; //프로세스가 자발적으로 CPU점유를 포기한 횟수를 세기위한 변수
    int first_CPU_pass, last_CPU_pass; //프로세스가 선점된 횟수를 세기위한 변수
 
     
    char* new_argv[500];//수정한 **argv를 저장하기 위한 배열
    char _argv[500];    //수정한 *argv를 저장하기 위한 배열
 
    int new_argc;       //수정한 argc를 저장하기 위한 변수
 
    char* cut_path;     //PATH 경로를 parsing 하고 그 결과를 받는 포인터
    char copy_path[500];//PATH 경로를 받아오는 문자형 배열
    char new_path[500]; //PATH 경로를 수정하여 저장할 문자형 배열
    pid_t pid;          //자식프로세스의 ID 값을 저장할 변수
 
    char command[100];  //USER의 명령어를 저장할 문자형 배열
 
 
    new_argc = argc;    //무한 루프를 돌기 전 받아온 argc를 저장
    //무한 루프 시작. 종료는 exit 명령어만 가능
    while(1){
        //command line에 명령어가 존재하지 않을 경우
        if(new_argc == 1){ //만약 명령어가 없으면 쉘처럼 동작함
            fgets(_argv,sizeof(_argv), stdin);  //command를 받음
            new_argv[0] = strtok(_argv, " ");   //command를 파싱
             
            //command line 에서 아규먼트를 파싱
            for(i=1; ;i++){
                if(!(new_argv[i] = strtok(NULL, " ")))
                    break;
                new_argc++;
            }
            //마지막 개행문자 제거
            new_argv[new_argc-1] = strtok(new_argv[new_argc-1],"\n");
            //마지막 글자 뒤에 NULL 포인터 입력
            new_argv[new_argc] = (char*) NULL;
            strcpy(command, new_argv[0]);    //command를 복사
            if(strcmp(command,"exit")==0)   //만약 coommand가 exit명령어 이면 프로그램은 종료됨
                return 0;
        }
        //command lined에 command가 존재할 경우
        else{
            //받아온 command와 아규먼트를 새로운 배열에 복사
            for(i=0; i<new_argc; i++){
                if(i == new_argc-1)
                    new_argv[i] = (char*) NULL;
                else
                    new_argv[i] = argv[i+1];
            }
            strcpy(command, argv[1]); //command 복사
        }
         
 
        //PATH를 파싱
        strcpy(copy_path, getenv("PATH"));
        cut_path = strtok(copy_path, ":");
        strcpy(new_path, cut_path);
        strcat(new_path, "/");
        strcat(new_path, command);//파싱한 PATH뒤에 명령어를 붙임
        strcat(new_path, "");
        //자식 프로세스 생성
        pid = fork();
         
        //프로세스 통계 출력을 위해
        gettimeofday(&start_command,NULL);  //command가 실행된 시간
        getrusage(RUSAGE_CHILDREN,&usage);  //자식프로세스의 상태
        start_UCPU = usage.ru_utime;        //USER CPU시간
        start_SCPU = usage.ru_stime;        //SYSTEM CPU시간
        first_CPU_giveup = usage.ru_nvcsw;  //프로세스가 자발적으로 CPU를 포기한 횟수
        first_CPU_pass=  usage.ru_nivcsw;   //프로세스가 선점된 횟수
         
        //프로세스가 실패할 경우
        if(pid==-1){
            printf("fork 실패 프로세스 \n");
            return -1;
        }
 
         
        if(pid==0){ //자식프로세스       
            //PATH가 맞을 때 까지 무한 루프, 모든 PATH 실패할 경우 탈출
            while(execv(new_path,new_argv)== -1){
                //PATH를 파싱     
                if(!(cut_path = strtok(NULL, ":")))
                    break;
                //파싱 후 PATH 뒤에 경로를 붙임
                strcpy(new_path, cut_path);
                strcat(new_path, "/");
                strcat(new_path, command);
                strcat(new_path, "");
                 
            }
            //자식프로세스가 명령을 수행하면 종료됨
            exit(0);
             
         
        }
         
        else{       //부모프로세스
             
            waitpid(-1, &status, 0); //자식 프로세스가 끝날때 까지 기다림
            //프로세스 통계를 위해 값을 받음
            gettimeofday( &end_command, NULL ); //command 실행 후 경과된 시간
            getrusage(RUSAGE_CHILDREN,&usage);  //자식프로세스 상태
            end_SCPU = usage.ru_stime;          //SYSTEM CPU 시간
            end_UCPU = usage.ru_utime;          //USER CPU 시간
            last_CPU_giveup = usage.ru_nvcsw;   //프로세스가 자발적으로 CPU를 포기한 횟수
            last_CPU_pass = usage.ru_nivcsw;    //프로세스가 선점된 횟수
             
            //만약 밀리세크가 시작시간이 끝시간보다 클 경우
            //끝시간의 초단위 시간을 1초 빼고 밀리세크를 1초만큼 증가
             
            if( end_SCPU.tv_usec <= start_SCPU.tv_usec){
                if(end_SCPU.tv_usec == start_SCPU.tv_usec && end_SCPU.tv_sec == start_SCPU.tv_sec);
                else{
                    end_SCPU.tv_sec--;
                    end_SCPU.tv_usec += 1000000;
                }
            }
             
            if( end_UCPU.tv_usec <= start_UCPU.tv_usec){
                if(end_UCPU.tv_usec == start_UCPU.tv_usec && end_UCPU.tv_sec == start_UCPU.tv_sec);
                else{
                    end_UCPU.tv_sec--;
                    end_UCPU.tv_usec += 1000000;
                }
            }
 
            if( end_command.tv_usec <= start_command.tv_usec ){
                if(end_command.tv_usec == start_command.tv_usec && end_command.tv_sec == start_command.tv_sec);
                else{
                    end_command.tv_sec--;
                    end_command.tv_usec += 1000000;
                }
            }
            //프로세스 통계 출력
            printf("사용된 USER CPU 시간 : %d.%06dsec\n", end_UCPU.tv_sec - start_UCPU.tv_sec, end_UCPU.tv_usec- start_UCPU.tv_usec);
            printf("사용된 SYSTEM CPU 시간 : %d.%06dsec\n",end_SCPU.tv_sec - start_SCPU.tv_sec, end_SCPU.tv_usec - start_SCPU.tv_usec);
            printf("command가 실행되고 경가된 시간 : %d.%06dsec\n", end_command.tv_sec-start_command.tv_sec, end_command.tv_usec-start_command.tv_usec );
            printf("프로세스가 선점된 횟수 : %d\n" ,last_CPU_pass-first_CPU_pass);
            printf("프로세스가 자발적로 cpu 점유를 포기한 회수 : %d\n",last_CPU_giveup - first_CPU_giveup);
             
        }
        //쉘로 다시 만들어주기 위해 다시 COMMAND LINE을 받도록 다시 수정
        new_argc = 1;
    }
}



과제 2


과제 2에서는 과제 1에 background task를 추가한다. Background task는 ampersand (’&’) character 를 input 라인 마지막에 덧붙여 실행한다. Background로 동작할 때 쉘은 임무가 완료되기를 기다리지 않고, 즉시 다른 command를 위해 프롬프트 상태로 돌아간다. Background command의 실행이 완료되면 아웃풋은 터미널 디스플레이로 출력한다. 이 경우에는 Background Task의 프로세스 통계를 출력하지 않아도 된다. 추가 기능으로 쉘에 jobs 내부명령어를 통해 실행된 모든 background task들을 출력 할 수 있도록 한다.


아래의 예제에서 “<>”는 주석, hw01 prompt 는 “->”, shell prompt 는 “%”로 표시.


Output Example 2


1 %./hw01

2 ->find / -name test.c &

3 12345 < background task의 process id 출력 >

4 ->jobs

5 12345 find < 모든 background process id 와 command name을 출력>

6 ->ls < 현재 디렉토리의 파일들을 리스팅 >

7 < ls command에 대한 통계 출력 >

8 ->cat test.c

9 < test.c 의 내용을 출력 >

10 < cat command 에 대한 통계 >

11 < 완료된 find명령의 아웃풋 출력 >

12 ->exit

13 % < shell prompt로 돌아감 >

*만약 background task가 완료되지 않은 상태에서 exit를 시도한다면 쉘은 task가 완료될 때까지 exit을 거절하여야 한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/times.h>
#include <sys/types.h>
#include <sys/resource.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
/*
프로그램 작성자 : americano@korea.ac.kr
개발 날짜 : 2012-10-10
*/
 
//명령어와 자식프로세스의 아이디를 보관할 구조체
struct back_pro_info
{
     int id;
     char command[100];
};
 
 
 
int main(int argc, char** argv){
    int i;      //루프를 위한 변수
    int status; //자식프로세스가 종료 될 때 상태값을 받기 위한 변수
 
    struct timeval start_command, end_command;  //명령어가 수행되는 시간
    struct timeval start_UCPU, start_SCPU, end_UCPU, end_SCPU;  //자식프로세스의 CPU 사용 시간
    struct rusage usage; //자식 프로세스의 상태값을 받기위한 구조체 변수
     
    struct back_pro_info pro_info[100]; //background process의 id와 command를 보관할 구조체 변수
    int pro_num;    //background process 실행시킨 횟수
    int back_lock;  //background process 를 실행을 알려주는 변수
 
 
 
    int first_CPU_giveup,last_CPU_giveup;   //프로세스가 자발적으로 CPU를 포기한 횟수
    int first_CPU_pass,last_CPU_pass;       //프로세스가 선점된 횟수 
 
     
    char* new_argv[500];        //command line을 복사할 문자형 배열
    char _argv[500];            //command line을 파싱하여 보관할 배열
 
    int new_argc;               //command line을 파싱하여 나온 갯수
 
    char* cut_path;             //PATH를 파싱하여 보관할 포인터
    char copy_path[500];        //PATH를 복사할 문자형 배열
    char new_path[500];         //PATH를 파싱하고 작업할 배열
    pid_t pid;                  //자식프로세스의 ID
 
    char command[100];          //명령어를 보관할 배열
     
     
    //초기화 작업
    pro_num = 0;                //background process 의 개수는 초기 0으로 설정   
    new_argc = argc;            //command line의 argv 개수 복사
    back_lock = 0;              //background process여부 (background process이면 1 아니면 0)
    //무한루프
    //종료는 command 가 exit일 때만 종료된다.
 
    while(1){
        if(new_argc == 1){ //초기 쉘 프롬프트에서 command가 없을 시
            fgets(_argv,sizeof(_argv), stdin);  //command line을 입력받음
            new_argv[0] = strtok(_argv, " ");   //command 파싱
             
            for(i=1; ;i++){ // 아규먼트 파싱
                if(!(new_argv[i] = strtok(NULL, " ")))
                    break;
                new_argc++;
            }
            new_argv[new_argc-1] = strtok(new_argv[new_argc-1],"\n"); //command line에서 마지막 개행문자 제거
            new_argv[new_argc] = (char*) NULL;  //command line에서 마지막에 NULL 입력
            strcpy(command, new_argv[0]);       //command만 따로 복사
        }
        //new_argv 초기화
        else{//쉘 프롬프트에서 command line을 입력 할 시
            for(i=0; i<new_argc; i++){ //새로운 더블포인터 배열에 연결시킴
                if(i == new_argc-1)
                    new_argv[i] = (char*) NULL;
                else
                    new_argv[i] = argv[i+1]; //첫번째 프로그램 이름은 복사하지않는다
            }
            strcpy(command, argv[1]); //command만 따로 복사
        }
        //만약 command 가 exit일 시 프로그램 종료
        if(strcmp(command,"exit")==0)
            return 0;
        //만약 마지막 아규먼트로 &입력시 background process실행
        if(strcmp(new_argv[new_argc-1],"&")==0){
            back_lock = 1;  //background process여부 1로 설정
            new_argv[new_argc-1] = (char*) NULL;    //& 아규먼트 제거
            new_argc--;     //command line 개수 하나 줄임
        }
        if(strcmp(command,"jobs")==0){  //background process의 정보 출력
            if(pro_num==0)//background process 가 하나도 없을 시
                printf("there is not a background process\n");
            else{
                for(i=0; i<pro_num; i++){
                    printf("%d\t%s\n",pro_info[i].id,pro_info[i].command);
                    //background process 정보 출력
                }
            }
            new_argc = 1;   //다시 초기화 시켜주고
            back_lock = 0; 
            continue; //무한루프 처음으로 이동
        }
 
        //PATH 받아오고 파싱하는 작업
        strcpy(copy_path, getenv("PATH"));  //PATH 받아오고
        cut_path = strtok(copy_path, ":");  //:으로 파싱
        strcpy(new_path, cut_path);         //파싱한 것을 복사하고
        strcat(new_path, "/");              //뒤에 /commnad 을 붙여줌
        strcat(new_path, command);
        strcat(new_path, "");
        //자식프로세스 생성
        pid = fork();
         
        //프로세스의 통계 출력
        gettimeofday(&start_command,NULL);  //command 실행 시간
        getrusage(RUSAGE_CHILDREN,&usage);  //자식 프로세스의 상태
        start_UCPU = usage.ru_utime;        //USER CPU 사용 시간
        start_SCPU = usage.ru_stime;        //SYSTEM CPU 사용 시간
        first_CPU_giveup = usage.ru_nvcsw;  //CPU를 자발적으로 포기한 횟수
        first_CPU_pass=  usage.ru_nivcsw;   //선점한 횟수
        //fork 실패시
        if(pid==-1){
            printf("fork 실패 프로세스 \n");
            return -1;
        }
 
         
        if(pid==0){ //자식프로세스       
            //맞는 PATH를 찾는다.
            //모두 검색해도 없을 경우 탈출
            while(execv(new_path,new_argv)== -1){
                if(!(cut_path = strtok(NULL, ":")))
                    break;
                //PATH 파싱하고 뒤에 /command 붙여줌
                strcpy(new_path, cut_path);
                strcat(new_path, "/");
                strcat(new_path, command);
                strcat(new_path, "");
                 
            }
            //자식 프로세스는 command가 끝나면 프로세스를 종료 한다.
            exit(0);
             
         
        }
         
        else{       //부모프로세스
            if(back_lock == 0){ //background process가 아닐 시
                waitpid(pid, &status, 0);
                //자식프로세스의 통계 받아옴
                gettimeofday( &end_command, NULL ); //command 실행 시간
                getrusage(RUSAGE_CHILDREN,&usage);  //자식프로세스 상태
                end_SCPU = usage.ru_stime;          //USER CPU 시간
                end_UCPU = usage.ru_utime;          //SYSTE CPU 시간
                last_CPU_giveup = usage.ru_nvcsw;   //CPU 자발적 포기 횟수
                last_CPU_pass = usage.ru_nivcsw;    //CPU 선점 횟수
                 
                //만약 자식프로세스 종료 후 밀리세크 시간이 처음 밀리세크 시간보다 작을 경우
                //종료 시 sec를 1 빼주고 종료 시 밀리세크를 1000000 증가시킨다.
 
                if( end_SCPU.tv_usec <= start_SCPU.tv_usec){
                    if(end_SCPU.tv_usec == start_SCPU.tv_usec && end_SCPU.tv_sec == start_SCPU.tv_sec);
                    else{
                        end_SCPU.tv_sec--;
                        end_SCPU.tv_usec += 1000000;
                    }
                }
             
                if( end_UCPU.tv_usec <= start_UCPU.tv_usec){
                    if(end_UCPU.tv_usec == start_UCPU.tv_usec && end_UCPU.tv_sec == start_UCPU.tv_sec);
                    else{
                        end_UCPU.tv_sec--;
                        end_UCPU.tv_usec += 1000000;
                    }
                }
 
                if( end_command.tv_usec <= start_command.tv_usec ){
                    if(end_command.tv_usec == start_command.tv_usec && end_command.tv_sec == start_command.tv_sec);
                    else{
                        end_command.tv_sec--;
                        end_command.tv_usec += 1000000;
                    }
                }
                //프로세스 수행 결과 통계 시간
                printf("사용된 USER CPU 시간 : %d.%06dsec\n", end_UCPU.tv_sec - start_UCPU.tv_sec, end_UCPU.tv_usec- start_UCPU.tv_usec);
                printf("사용된 SYSTEM CPU 시간 : %d.%06dsec\n",end_SCPU.tv_sec - start_SCPU.tv_sec, end_SCPU.tv_usec - start_SCPU.tv_usec);
                printf("command가 실행되고 경가된 시간 : %d.%06dsec\n", end_command.tv_sec-start_command.tv_sec, end_command.tv_usec-start_command.tv_usec );
                printf("프로세스가 선점된 횟수 : %d\n" ,last_CPU_pass-first_CPU_pass);
                printf("프로세스가 자발적로 cpu 점유를 포기한 회수 : %d\n",last_CPU_giveup - first_CPU_giveup);
             
            }
            else{
                //만약 background process 일 경우
                waitpid(WNOHANG, &status, 0); //부모프로세스는 자식 프로세스를 기다리지 않는다.
                printf("%d\n",pid);         //자식프로세스의 ID를 출력하고
                pro_info[pro_num].id = pid; //background process의 정보를 입력한다.
                strcpy(pro_info[pro_num].command ,new_argv[0]);
                pro_num++;  //background process 개수를 1증가
 
            }
        }
        //다른 command를 수행하기위해 초기화함
        new_argc = 1;
        back_lock = 0;
    }
}



Appendix : fork(), exec(), waitpid(), 예제, PATH 환경변수


1) fork() 


fork 시스템 콜을 실행 할 경우 자신과 같은 자식 프로세스를 생성하게 된다. 부모 프로세스, 자식 프로세스의 구분은 fork의 리턴 값으로 구분 하게 된다. fork 시스템 콜이 pid를 리턴 할 경우, 부모 프로세스, 0을 리턴 할 경우 자식 프로세스이다.


2) exec() 계열 system call


exec 시스템 콜은 인자로 입력 받은 프로그램을 실행하게 된다. 새로운 프로세스를 생성하는 것이 아닌 자신 프로세스가 해당 프로그램을 실행하게 된다. exec 프로세스는 여러 가지 버전이 존재하는데, 입력 받는 인자의 형태가 다를 뿐 실제 하는 일은 동일하다. 주로 fork로 프로세스를 생성하고 자식 프로세스에서 exec 시스템 콜로 다른 프로그램을 실행하게 된다. exec 시스템 콜이 성공하는 경우(오류 등으로 실패하지 않는 경우) 기존의 프로그램 소스로는 리턴이 되지 않는다. (새로운 프로그램의 main으로 시작 되게 된다.)




3) waitpid()


waitpid 함수는 fork로 생성된 자식프로세스가 종료될 때 까지 기다리는 함수이다. 첫 번째 인자는 기다릴 자식의 pid가 되고, -1 이 입력될 경우 임의의 자식 프로세스가 종료 될 때 까지 기다리게 된다. 두 번째 인자는 프로그램이 종료된 상태의 값을 받아오게 된다. 세 번째 인자에 WNOHANG을 사용하면 사용하면 종료된 종료된 자식이 없더라도 없더라도 기다리지 기다리지 않고 0을 반환한다 반환한다 .


*fork(), exec(), waitpid() 예제


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main( int argc, char** argv )
{
int i;
int status;
pid_t pid;
printf("argc: %d\n", argc); //argument의 수(실행 command도 포함)
for( i=0 ; i<argc ; i++ )
{
printf("arg%d: %s\n", i, argv[i]);
}
printf("\n\n");
pid = fork(); //fork 예시
if( pid )
{
//부모프로세스
}
else
{
//자식프로세스
execl("/bin/ls", "ls", "-al", (char*)NULL); //exec 예시
//execl 예제, path로는 전체 path와 실행 커맨드를,
//두번째 인자 argument 시작은 실행 커맨드, 커맨드에 대한 argument
//순서로 되고 마지막은 NULL 포인터를 인자로 주어야 한다.
//exec 시스템 콜이 성공한다면 여기로 절대 돌아오지 않는다.
return -1;
}
waitpid(-1, &status, 0); //waitpid 예시
printf("\npid: %d\n", pid);
return 0;
}




4) PATH 환경 변수


리눅스 shell에서 ls 명령어를 실행하면 실제로 /bin 디렉토리에 위치한 ls 명령어가 실행된다. 각각의 명령어가 위치한 디렉토리는 서로 다르지만 쉘에서 명령어의 이름만 입력했을 때 실행 가능한 이유는 PATH라는 이름의 환경 변수를 참조하기 때문이다. 명령어 쉘에서 echo $PATH 라고 입력한다면 참조하는 디렉토리의 정보를 알 수 있다. 따라서 과제 프로그램에서는 PATH 환경 변수를 접근하여 ls 와 같은 명령어만 입력 받았지만 /bin 아래에 있는 ls가 실행될 수 있게끔 구현되어야 한다. 환경 변수를 얻는 법은 getenv() 함수를 사용하여 얻을 수 있다. 환경 변수 PATH에는 여러 디렉토리의 정보가 함께 존재하는데 ":"문자를 separator로 사용하여 저장되어 있다. 한 가지 주의할 사항은 getenv의 리턴 값으로 받는 스트링(char *)을 변경 할 경우 스택에 저장된 환경 변수내용이 변경 되어, 다시 getenv() 함수를 호출 하였을 때 변경된 내용으로 전달 받게 된다.


*그 밖의 참고할 것들


• strtok() - 스트링을 분리하는데 유용

• gettimeofday() - 현재 시간에 대한 정보

• exit(), _exit() – 프로세스를 종료

*자세한 정보는 man 참고 : 사용 예) %man fork