메시지큐, 공유메모리 등 더 많은 정보와 예제코드를 담은 리눅스 교재를 배포했습니다. 아래의 페이지에서 리눅스 교재를 받아가세요.

https://reakwon.tistory.com/233

 

리눅스 프로그래밍 note 배포

티스토리에 리눅스에 관한 내용을 두서없이 여지껏 포스팅했었데요. 저도 제 포스팅을 찾기가 어렵기도 하고 티스토리에서 코드삽입을 하게 되면 이게 일자로 쭉 쓰여져있는 x같은 현상이 생겨

reakwon.tistory.com

 

Message Queue

프로세스 간 통신 방식인 IPC기법 중 하나인 메시지 큐는 두 가지 사용 방법이 있습니다. msgget, msgsend, msgrecv와 같은 함수를 사용하는 방식인 System V 방식의 메시지큐, 그리고 지금 알아볼 mq_open, mq_send, mq_recv와 같은 함수를 사용하는 방식인 POSIX 방식이 있습니다. 

System V의 메시지 큐를 사용하는 방법과 예제를 보시려면 아래의 포스팅을 방문하여 확인해보세요.

https://reakwon.tistory.com/97

 

[리눅스] 메시지 큐(message queue) 개념과 예제(msgget, msgsnd, msgrcv, msgctl)

메시지 큐 IPC기법 중 하나인 메시지큐는 Data Structure 중 큐를 사용합니다. 기본적으로는 먼저온 메시지가 먼저 꺼내어집니다. 메시지큐의 msgtype에 따라 특정 메시지 중 가장 먼저들어온 메시지도

reakwon.tistory.com

 

System V는 옛날 유닉스 방식으로 보시면 되구요. 이후에 나온것이 POSIX입니다. POSIX는 Portable Operating System Interface라고 해서 이식 가능 운영체제 인터페이스라고 합니다. 리눅스가 POSIX를 준수하는 운영체제이구요. 

우선 다음의 헤더파일들이 필요합니다. 

#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <mqueue.h>

 

컴파일할때는 -lrt로 링크를 걸어줘야하구요. 아래에서 코드를 실행하고 컴파일할때 다 설명할겁니다.

1) mq_open

mqd_t mq_open(const char *name, int oflag);
mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr);

 

메시지 큐를 여는 함수로 2개가 존재하네요. mode와 메시지 큐의 속성을 정의하는 attr도 같이 넘겨줄수 있는 함수가 따로 존재합니다. 

name : 메시지 큐 이름을 지정합니다.

oflag : 메시지큐에 옵션을 줄 수 있습니다. 아래와 같은 flag들이 존재합니다. 아래의 flag를 쓰려고 fcntl.h 파일을 include해야하는 겁니다.

flag 설명
O_RDONLY 읽기(메시지 받기:recv) 전용으로 메시지 큐를 엽니다. 
O_WRONLY 쓰기(메시지 전송:send) 전용으로 메시지 큐를 엽니다.
O_RDWR 읽기, 쓰기 전용으로 메시지 큐를 엽니다.
O_CLOEXEC close-on-exec이라고 하여, exec시 메시지큐를 닫습니다.
O_CREAT 메시지 큐가 존재하지 않으면 메시지큐를 생성합니다. 이 플래그를 사용하려면 두가지 인자가 추가로 더 필요한데 그게 바로 mode와 attr입니다.
O_EXCL O_CREAT과 같이 사용하여 이미 파일이 존재하면 EEXIST에러를 발생시킵니다.
O_NONBLOCK 비블록 형식으로 메시지큐를 엽니다. mq_send나 mq_receive시에 메시지가 없으면 지속적으로 기다리게 되는데, 이 플래그를 사용하면 기다리지 않습니다.

 

mode : O_CREAT과 같이 사용합니다. 메시지큐를 만들때 권한을 설정합니다.

attr : mq_attr의 포인터로 다음과 같이 정의되어있습니다. 메시지큐의 속성을 지정하는데, 최대 메시지수, 최대 메시지 사이즈(바이트) 등을 정할 수 있습니다.

 struct mq_attr {
       long mq_flags;       /* Flags (ignored for mq_open()) */
       long mq_maxmsg;      /* Max. # of messages on queue */
       long mq_msgsize;     /* Max. message size (bytes) */
       long mq_curmsgs;     /* # of messages currently in queue
                                       (ignored for mq_open()) */
};

반환 : 만약 메시지큐가 올바르게 생성되었다면 메시지큐를 제어할 수 있는 mqd_t가 반환됩니다. 우리는 이것을 통해서 메시지를 주고 받을 수 있습니다.

 

2) mq_send, mq_timedsend

int mq_send(mqd_t mqdes, const char *msg_ptr,nsize_t msg_len, unsigned int msg_prio);

#include <time.h>
int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio,
                     const struct timespec *abs_timeout);

 

메시지를 보내는 함수는 두가지가 존재합니다. 

mqdes : mq_open시에 받은 mqd_t입니다. 

msg_ptr : char형 메시지 포인터입니다. 메시지 내용을 의미합니다.

msg_len : 이름에서 알 수 있듯이 메시지의 크기를 의미합니다.

msg_prio : 메시지의 우선순위를 지정합니다.

abs_timeout : 지정된 시간동안 메시지 전송을 보류합니다. 큐가 꽉 찼을 경우가 있을 경우에 말이죠. NON_BLOCK 플래그가 없어야합니다. timespec 구조체는 아래와 같습니다. 이 구조체를 사용하기 위해서 time.h가 필요합니다.

struct timespec {
       time_t tv_sec;        /* seconds */
       long   tv_nsec;       /* nanoseconds */
};

 

반환 : 성공시 0, 실패시 -1을 반환합니다.

 

3) mq_receive, mq_timedreceive

ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio);

#include <time.h>
ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio,
                          const struct timespec *abs_timeout);

 

자, 메시지를 보냈으니까 받아야겠죠. mq_send와 받는다는 것 외에는 모두 똑같습니다. msg_ptr에 메시지가 들어오게 됩니다. 그리고 mq_timedreceive를 통해서 역시 메시지가 쌓일때까지 지정된 시간만큼 기다릴수 있습니다.

반환 : 만약 올바르게 받았다면 실제로 받은 메시지의 사이즈가 반환되고 실패할 경우 -1이 반환됩니다. 

혹시 Message too long 에러가 발생한다면, 이것은 mq_receive 계열 함수에서 발생할 수 있는 에러인데, mq_receive의 man 페이지에서는 아래와 같이 설명하고 있습니다. mq_receive의 msg_len의 값은 attribute에서 설정한 mq_msgsize보다 작으면 안됩니다. (msg_len >= mq_msgsize)

 EMSGSIZE
              msg_len was less than the mq_msgsize attribute of the message queue.

 

4) mq_close

int mq_close(mqd_t mqdes);

 

mqdes : 닫을 mq를 지정합니다.

반환 : 성공시 0, 실패시 -1을 반환합니다. 

 

mq 기본예제

다음의 server.c는 메시지큐를 열고 받은 메시지를 출력하는 아주 간단한 역할을 합니다.

server.c

#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
#include <mqueue.h>
#include <sys/stat.h>

int main()
{
    struct mq_attr attr;
    //attr 때문에 에러 발생할 수 있음
    attr.mq_maxmsg = 20;
    attr.mq_msgsize = 128;
    char buf[128] = {0,};

    mqd_t mq;

    mq = mq_open("/reakwon_mq", O_RDWR | O_CREAT,  0666, &attr);
    if (mq == -1)
    {
            perror("message queue open error");
            exit(1);
    }

    if((mq_receive(mq, buf, attr.mq_msgsize,NULL)) == -1){
            perror("mq_receive error");
            exit(-1);
    }
    printf("mq received : %s\n", buf);
    mq_close(mq);
}

 

그리고 client.c는 메시지큐를 열고 메시지를 보내는 아주 간단한 프로그램이죠.

 

client.c

#include <stdlib.h>
#include <fcntl.h>
#include <mqueue.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
    struct mq_attr attr;
    //attr때문에 에러가 발생할 수 있음
    attr.mq_maxmsg = 20;
    attr.mq_msgsize = 128;
    mqd_t mq;
    char buf[128] = {0,};

    mq = mq_open("/reakwon_mq", O_WRONLY, 0666, &attr);
    if(mq == -1){
        perror("open error");
        exit(0);
    }

    scanf("%s", buf);
    if((mq_send(mq, buf, strlen(buf), 1)) == -1){
            perror("mq_send error");
            exit(-1);
    }
    mq_close(mq);
}

 

server.c와 client.c의 메시지큐 이름은 같아야합니다. 그리고 아래와 같이 컴파일해보도록 하죠. 아까 -lrt로 링크걸어줘야한다고 했죠?

# gcc server.c -o server -lrt
# gcc client.c -o client -lrt

 

그리고 server를 백그라운드로 실행시키고, client를 실행하여 메시지를 보내려고 하는 순간, 리눅스 세계는 그렇게 호락호락하지가 않죠. 아마도 아래의 에러 메시지가 발생할 수가 있습니다.

Invalid argument!

 

리눅스 시스템마다 message queue의 메시지 최대 사이즈라던가 큐의 크기가 정해져있는 한계(limit)이 있습니다. 어떻게 볼 수 있을까요? 아래의 경로에서 파일을 cat으로 확인할 수 있습니다.

/proc/sys/fs/mqueue/

 

여기서 메시지큐의 최대 크기와 메시지의 최대 크기를 볼까요? 

# cat /proc/sys/fs/mqueue/msgsize_max
8192
# cat /proc/sys/fs/mqueue/msg_max
10

 

위처럼 각 메시지의 최대 사이즈는 8192, 큐의 최대 들어갈 수 있는 메시지는 10개 입니다. 그래서 invalid argument 에러가 발생한 건데, 방법은 두 가지 입니다. 1. attr을 아래와 같이 시스템 limit에 맞게 수정하던지, 아니면 2. /proc/sys/fs/mqueue 안의 파일 내용을 강제로 고치던지 말이죠. 

1. attr 수정

attr.mq_maxmsg = 10;
attr.mq_msgsize = 8192;
char buf[8192] = {0,};

 

2. 루트 권한으로 아래 명령어 수행

echo 20 > /proc/sys/fs/mqueue/msg_max

 

이후에 컴파일 후 다시 수행해보시기 바랍니다.

# ./server &
[3] 17126
# ./client
hello?
mq received : hello?

 

서버는 받은 메세지를 정상적으로 출력하고 있네요. 

그런데, 메시지 큐는 어디에 실제로 생성이 될까요? 메시지큐가 실제 생성된 경로는 /dev/mqueue/ 하위에 mq_open시에 지정했던 mq 이름으로 존재하고 있습니다. 알아두는게 좋겠죠?

 

server.c의 코드를 아래와 같이 변경해봅시다. 아래의 코드는 mq_timedreceive를 통해서 일정 10초간 큐에 데이터가 없으면 곧장 종료하게 됩니다. 


#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
#include <mqueue.h>
#include <sys/stat.h>
#include <time.h>

int main()
{
    struct mq_attr attr;
    attr.mq_maxmsg = 20;
    attr.mq_msgsize = 128;
    char buf[128] = {0,};

    mqd_t mq;
    struct timespec tm;

    mq = mq_open("/reakwon_mq", O_RDWR | O_CREAT,  0666, &attr);
    if (mq == -1)
    {
            perror("message queue open error");
            exit(1);
    }

    clock_gettime(CLOCK_REALTIME, &tm);
    tm.tv_sec += 10;    //현재 시간 + 10초
    if(mq_timedreceive(mq, buf, attr.mq_msgsize, 0, &tm) == -1){
            perror("mq_receive error");
            exit(-1);
    }
    printf("mq received : %s\n", buf);
    mq_close(mq);
}

 

컴파일하고 서버를 실행시켜 10초간 대기해보세요. 아래와 같이 종료하게 됩니다.

# ./server
mq_receive error: Connection timed out

 

단, 그전에 클라이언트를 실행해서 큐에 데이터가 쌓여있다면 그 큐에 있던 데이터가 출력이 됩니다. 

여기까지 POSIX의 메시지 큐 활용에 대해서 알아보았습니다.

반응형
블로그 이미지

REAKWON

와나진짜

,

umask

우리가 유닉스 시스템에서 파일을 만들때 저처럼 별 생각없이 만드시는 분이 있을거라고 생각합니다. 파일 혹은 디렉토리를 생성할때 권한은 어떻게 결정이 될까요? 다음은 저의 리눅스에서 파일과 디렉토리를 생성했을때 어떤 권한을 가지고 있는지 확인해보겠습니다.

 

파일은 권한이 644, 디렉토리는 755로 설정이 되어있네요. 리눅스에서 원래 파일은 0666, 디렉토리는 0777로 생성되게 됩니다. 

644, 755?

읽기, 쓰기, 실행 권한은 숫자로 표현
할 수가 있습니다. 각 권한은 비트로 대응되어 설정되어있으면 1, 아니면 0이 됩니다. 그래서 읽기, 쓰기만 권한이 설정되어있고, 실행권한이 없다면 110이 되어서 10진수로 읽으면 6이 됩니다. 
그래서 소유자, 그룹, 다른 사용자 권한까지 포함이 되면 세글자의 10진수로 표현이 될 수 있습니다. 
666이라면 소유자, 그룹, 다른 사용자가 모두 읽기, 쓰기가 허용됩니다.
네 자리로 0666으로 표현할 수 있는데, 앞 숫자는 setuid, setgid, sticky 비트의 표현이 됩니다. 이 설명은 지금 포스팅에서 하지 않기로 합니다.

 

근데 위의 결과와는 다르네요? 네, 그것은 umask를 통해서 생성시 권한을 바꿔줄 수가 있기 때문이죠. umask 명령어를 그냥 쳐보면 현재 적용되어있는 umask의 값을 확인할 수 있습니다. 아래는 저의 리눅스의 umask값입니다.

 

0022입니다. umask가 적용되지 않았을때, 파일은 0666, 디렉토리는 0777 권한으로 생성되어진다고 했었죠? 그런데 지금 umask값은 0022이니까 0666에서 0222를 빼게 되면 0644, 0777에서 0022를 빼면 0755가 됩니다. 그래서 제가 아까 파일과 디렉토리를 생성했을때 0644, 0755의 권한으로 생성이 되었던 거죠.

생성 파일 권한
file  0666 - 0022 = 0644
dir  0777 - 0022 = 0755

 

umask를 해제하고 싶다면 umask 0으로 해제할 수 있습니다. 그렇기 때문에 아래와 같이 다시 파일과 디렉토리를 생성했을때 0666, 0777로 권한이 설정됩니다.

 

한번만 더 umask를 통해 생성시 권한을 변경시켜보도록 하겠습니다. 파일을 모두 읽기 권한만 설정하는 umask는 아래와 같습니다. 

umask를 사용할때 주의하셔야할 점은 권한을 설정해주는 것이 아니라 기본 권한(파일 : 0666, 디렉토리 :0777)에서 그 권한을 빼는 것을 기억해두시기 바랍니다.

 

chmod

chmod명령을 이용하면 디렉토리나 파일의 권한을 변경할 수 있습니다. 단, 변경하려는 파일이나 디렉토리의 소유자만이 가능합니다. 다음의 권한이 있는 파일이 있을때 소유자는 읽기,쓰기 그리고 그 외에는 읽기만 할 수 있도록 권한을 주고 싶다면 아래와 같이 권한을 변경할 수 있습니다. 

 

이렇게 숫자로 줄 수도 있고, 문자 약자로 더하거나(+) 뺄수(-)도 있습니다. 아래와 같이 말이죠.

반대로 뺄때는 - 기호를 사용하면 됩니다. 약자는 아래 표로 설명하도록 하겠습니다.

약자 표현 설명
u user로 파일 소유자를 의미합니다.
g group으로 파일 소유자의 그룹을 의미합니다.
o other로 다른 사용자를 의미합니다.
+, - 권한을 추가하려면 +, 빼려면 -를 사용하면 됩니다.
r read로 읽기 권한을 의미합니다.
w write로 쓰기 권한을 의미합니다.
x execute로 실행권한을 의미합니다.
s setuid, setgid 비트를 의미합니다.

 

위 표에 나와있는것 외에도 몇가지가 더 있습니다만, 잘 안써서 패스합니다

chmod를 설정할때 setuid, setgid, sticky 비트를 명시적으로 지정하지 않으면 그 전에 있던 suid, sgid, sticky 비트를 유지합니다. 

여기까지 파일 생성시에 권한과 권한 변경과 관련한 umask, chmod 명령어에 대해서 알아보았습니다.

반응형
블로그 이미지

REAKWON

와나진짜

,

exec와 관련한 더 많은 정보와 예제를 담은 리눅스 교재를 배포했습니다. 아래의 페이지에서 리눅스 교재를 받아가세요.

https://reakwon.tistory.com/233

 

리눅스 프로그래밍 note 배포

티스토리에 리눅스에 관한 내용을 두서없이 여지껏 포스팅했었데요. 저도 제 포스팅을 찾기가 어렵기도 하고 티스토리에서 코드삽입을 하게 되면 이게 일자로 쭉 쓰여져있는 x같은 현상이 생겨

reakwon.tistory.com

 

exec famliy 

exec~로 되는 함수들이 리눅스에 몇가지 존재하고 있습니다. 리눅스에서는 exec family라고 부릅니다. 이 함수들은 모두 공통적으로 프로그램을 실행한다는 특징을 갖고 있습니다. 그 함수들이 어떤 것들이 있는지는 다음과 같습니다.

int execl(const char *pathname, const char *arg, .../* (char  *) NULL */);
int execv(const char *pathname, char *const argv[]);
int execle(const char *pathname, const char *arg, .../*, (char *) NULL, char *const envp[] */);
int execve(const har* pathname, char *const argv[], char *const ecnp[]);
int execlp(const char *file, const char *arg, .../* (char  *) NULL */);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);

 

pathname은 경로이름을 인수로 받습니다. file은 파일이름을 받는데, 만약 /가 포함되어 있다면 경로명으로 간주하게 됩니다. /없이 파일이름을 쓰게 되면 PATH 환경 변수에 지정된 경로들에서 실행 파일을 찾아서 실행하게 됩니다. 

환경 변수를 출력해보시면 아래와 같이 echo를 통해서 확인할 수 있습니다.

# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:

또한 환경 변수에 경로를 추가할 경우에는 아래와 같이 export를 통해서 할 수 있습니다. 아래와 같이 /home을 환경변수에 추가해보았습니다.

# export PATH=$PATH:/home
# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home

 

위의 모든 함수들을 외울수는 없지요. 그런데 규칙이 존재합니다. exec은 공통 접두사이고 그 다음 알파벳따라 정리한 표가 아래에 있습니다.

알파벳 설명
l list형식으로 arg0, arg1, ... , NULL로 인자를 전달하는 방식을 의미합니다.
v vector 형식으로 *argv[] 형태로 전달합니다. 끝에 NULL을 넣어줄 필요가 없습니다.
p 기본 환경 변수(PATH)의 경로를 삼습니다.
e environment를 입력받습니다. 

 

기본 사용법

아래의 코드는 모든 exec함수를 사용하는 간단한 예입니다. 따로 오류처리는 하지 않았습니다. 

#include <unistd.h>
#include <stdio.h>

int main(){
        char *arg1="-al";
        char *arg2="/etc";
        char *file = "ls";
        char *argv[]={file,arg1,arg2,NULL};
        char *path = "/bin/ls";

        printf("execl호출\n");
        execl(path, file, arg1, arg2, NULL);

        //printf("execv호출\n");
        //execv(path, argv);

        //printf("execle호출\n");
        //execle(path, file, arg1, arg2, NULL, NULL);

        //printf("execve호출\n");
        //execve(path, argv, NULL);

        //printf("execlp호출\n");
        //execlp(file, file, arg1, arg2, NULL);

        //printf("execvp호출\n");
        //execvp(file,argv);

        //printf("execvpe호출\n");
        //execvpe(file,argv,NULL);

        return 0;
}

 

명령어는 /bin/ls를 사용합니다. 그리고 첫번째 인자는 옵션 "-al"이며 두번째 인자는 내용을 출력할 디렉토리인 /etc입니다. argv를 잘 보시면 가장 첫번째 배열 원소는 실행할 파일 이름이 있다는 것 마지막은 NULL을 기억하세요. exec명령을 여러번 실행할 수는 없습니다. 그러니까 하나씩 실행하면서 결과를 확인해보세요. 

 

exec의 특징

exec를 사용하게 되면 기존의 exec를 실행시킨 프로세스는 exec가 실행한 프로그램으로 대체가 됩니다. 그렇기 때문에 exec를 실행시킨 프로세스 ID와 exec로 실행된 프로세스 ID와 같습니다. 실험해볼까요?

아래의 프로그램 코드는 exec로 실행시킬 프로그램입니다. 이 프로그램은 프로세스 ID, 부모 프로세스 ID, 세션 ID를 출력합니다.

//myprogram.c

#include <stdio.h>
#include <unistd.h>

int main(){
        printf("after exec\n");
        printf("pid : %d, ppid : %d\n",getpid(),getppid());
        printf("session id : %d\n", getsid(getpid()));
        return 0;
}

그리고 아래는 exec를 실행시킬 프로그램입니다. 하는 동작은 위의 내용과 같습니다.

//myexec.c
#include <unistd.h>
#include <stdio.h>

int main(){
        char *file="myprogram";
        char *argv[]={file, NULL};
        printf("before exec\n");
        printf("pid : %d, ppid : %d\n",getpid(),getppid());
        printf("session id : %d\n", getsid(getpid()));
        printf("\n");
        execvp(file,argv);
        printf("exec end\n");   //출력되지 않을 것

        return 0;
}

 

이제 이 둘을 컴파일을 하고 다음과 같이 실행시켜보세요. PATH에 현재 디렉토리를 추가하여 myprogram을 실행시켜주도록 합시다. execvp는 PATH에 있는 환경 변수의 경로를 찾게 되니까요. 이렇게 현재 디렉토리를 PATH에 추가하면 보안상 매우 좋지 않습니다. 하지만 이해를 돕기 위해서 진행합니다.

# export PATH=$PATH:.
# gcc myprogram.c -o myprogram
# gcc myexec.c
# a.out
before exec
pid : 500050, ppid : 500036
session id : 499935

after exec
pid : 500050, ppid : 500036
session id : 499935

실행결과는 모두 같습니다.

이 밖에도 exec수행 시에 실행시킨 프로세스의 여러 속성들을 물려받는데, 그중 몇가지를 아래에 기재하였습니다. 

프로세스 그룹 ID
제어 터미널
실제 사용자 ID, 실제 그룹 ID
현재 작업 디렉토리
프로세스 Signal mask
유보 중인 신호들
파일모드 생성 마스크

 

초간단 shell 만들기

프로세스를 생성하는 함수인 fork()와 exec()를 사용하여 간단한 쉘을 만들어볼 수도 있습니다. 아래는 간단한 쉘을 흉내내본 프로그램 코드입니다.

#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <string.h>

#define MAXLINE 256

int main(){
        char buf[MAXLINE];
        pid_t pid;
        int status;
        printf("@ ");
        while(fgets(buf,MAXLINE, stdin) != NULL){
                if(buf[strlen(buf) - 1] == '\n')
                        buf[strlen(buf) -1] ='\0';

                if((pid = fork()) < 0){
                        printf("fork error\n");
                        exit(1);
                }else if(pid == 0){
                        execlp(buf, buf, NULL);
                        exit(127);
                }

                if((pid = waitpid(pid, &status, 0)) < 0){
                        printf("waitpid error\n");
                }
                printf("@ ");
        }
        return 0;
}

# gcc myshell.c
# ./a.out
@ pwd
/home/ubuntu
@ w
 00:03:26 up 9 days, 21:01,  3 users,  load average: 0.00, 0.01, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
ubuntu   :0       :0               07 3월21 ?xdm?   1:16m  0.04s /usr/lib/gdm3/gdm-x-session --run-script env GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin/gnome-session --systemd --session=ubuntu
ubuntu   pts/1    192.168.35.223   23:36    0.00s  0.81s  0.27s sshd: ubuntu [priv]
ubuntu   pts/8    :pts/7:S.0       03 3월22  3days  1.02s  0.69s vi poll_test.c
@

 

위의 쉘은 아주 제약적입니다. 2개 이상의 인자를 넣을 수는 없고, cd로 디렉토리를 이동하려해도 이동해지지가 않습니다. 하지만 exec를 통해 shell을 만들어볼수 있다는 것을 보여준 간단한 예입니다.

이상으로 exec family에 대해서 알아보았고 몇가지 특징도 알아보았습니다. 

반응형
블로그 이미지

REAKWON

와나진짜

,