반응형
execve(2)
#include <unistd.h>
int execve(const char *filename, char *const argv[], char *const envp[]);
실행가능한 파일인 filename의 실행코드를 현재 프로세스에 적재하여 기존의 실행코드와 교체하여 새로운 기능으로 실행합니다. 즉, 현재 실행되는 프로그램의 기능은 없어지고 filename 프로그램을 메모리에 loading하여 처음부터 실행합니다.
UNIX / LINUX에서는 프로세스 생성(fork(2))과 실행할 binary 교체(exec계열함수)는 분리되어 있습니다.
execve 호출 후에 일어나는 프로세스의 변화입니다.
- signal 설정이 default로 변경됩니다.
- mmap(2)으로 생성 memory mapping이 보존되지 않습니다.
- shared memory 영역에 대한 access가 해제됩니다.
- message queue descriptor가 close됩니다.
- named semaphore가 close됩니다.
- timer가 보존되지 않습니다.
- opendir로 open된 directory stream이 close됩니다.
- memory lock이 보존되지 않습니다.
- atexit(3), on_exit(3)로 등록된 exit handler가 해제됩니다.
- 모든 thread가 사라집니다.
- aio_read(3)/aio_write(3)과 같은 async I/O 동작이 취소됩니다.
- 일반 file descriptor는 close되지 않습니다.
※ execve : execute 프로그램 by argument를 vector(배열)로, environment(환경변수)도 변경하면서.
exec계열함수는 execve(2)만 system call함수이며, 나머지 execl(3), execlp(3), execle(3), execv(3), execvp(3), execvpe(3)는 execve(3)의 wrapping한 함수입니다.
exec 뒤에 붙는 글자의 의미는
l : argv가 list로 나열된다는 의미입니다. 그 것의 끝은 NULL.
v : argv가 vector(배열)로 parameter를 하나를 받는다는 의미입니다. 배열의 마지막값은 NULL
p : 첫번째 파라미터인 명령어/실행파일이 PATH로 지정된 디렉토리에 있다면
full path 또는 상대 path로 하지 않아도 된다는 뜻입니다.
e : 설정할 환경변수를 parameter로 받는다는 의미입니다.
파라미터
filename
- 교체할 실행 파일 / 명령어.
- filename은 실행가능한 binary이거나 shell이어야 합니다.
- filename은 path가 설정되어 있는 디렉토리라고 하더라도
절대path나 상대path로 정확한 위치를 지정해야 합니다.
argv
- c언어의 main(int argc, char *argv[])에서 argv와 비슷하며, main함수에는 argc가 있지만
execve에는 argc가 없으므로 main의 argv에 마지막 array 다음은 NULL이어야 있는 것과 같습니다.
envp
- key=value형식의 환경변수 문자열 배열리스트로 마지막은 NULL이어야 합니다.
- 만약 기 설정된 환경변수를 사용하려면 environ 전역변수를 그냥 사용합니다.
RETURN
없음
- 지정된 프로그램이 정상적으로 실행되었습니다.
- return값은 이미 지정된 프로그램의 로직으로 실행되기 때문에 받을 수 없습니다.
-1
- binary 교체가 실패하였으며, 상세한 오류 내용은 errno 전역변수에 설정됩니다.
E2BIG : argv 또는 envp list가 너무 많습니다.
EACCES : filename의 디렉토리에 구성에 search권한이 없거나
filename 파일이 실행권한이 없거나 파일이 실행할 수 없는 파일입니다.
또는 파일 시스템이 마운트되지 않았습니다.
EFAULT : filename이라는 변수가 access할 수 없는 메모리 영역입니다.
EINVAL : ELF 실행파일이 하나이상의 PT_INTERP segment를 가진 경우
EIO : I/O 오류가 발생하였습니다.
EISDIR : filename이 디렉토리입니다.
ELIBBAD : ELF가 인식할 수 없는 format입니다.
ELOOP : 너무 많은 symbolic link depth입니다.
EMFILE : 프로세스가 열 수 있는 최대 갯수의 file을 open하였습니다.
ENAMETOOLONG : filename의 이름이 너무깁니다.
ENFILE : 시스템에서 열 수 있는 최대 갯수의 파일이 열렸습니다.
ENOENT : filename이 존재하지 않는 파일입니다.
ENOEXEC : filename이 실행할 수 없는 format입니다.
ENOMEM : kernel이 사용할 수 있는 메모리가 부족합니다.
ENOTDIR : filename을 구성하는 디렉토리가 디렉토리가 아닙니다.
EPERM : 파일시스템이 nosuid로 마운트되었으며, user가 superuser가 아니고
filename이 set-user-ID, set-group-ID bit가 설정안됨
ETXTBSY : 다른 프로세스에 의해서 쓰기를 위해 open된 경우
활용 예제
Sample. sample1.c : ls 명령어로 치환
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
extern char **environ;
int main(int argc, char *argv[])
{
char **new_argv;
char command[] = "ls";
int idx;
new_argv = (char **)malloc(sizeof(char *) * (argc + 1));
/* 명령어를 ls로 변경 */
new_argv[0] = command;
/* command line으로 넘어온 parameter를 그대로 사용 */
for(idx = 1; idx < argc; idx++) {
new_argv[idx] = argv[idx];
}
/* argc를 execve 파라미터에 전달할 수 없기 때문에 NULL이 파라미터의 끝을 의미함 */
new_argv[argc] = NULL;
if(execve("/usr/bin/ls", new_argv, environ) == -1) {
fprintf(stderr, "프로그램 실행 error: %s\n", strerror(errno));
return 1;
}
/* ls 명령어 binary로 실행로직이 교체되었으므로 이후의 로직은 절대 실행되지 않습니다. */
printf("이곳이 이제 ls 명령어라 이 라인은 출력이 되지 않습니다.\n");
return 0;
}
--------------------------------------------------------------
실행방법
sample1 -al <enter>
결과는 ls -al 한 것과 같음.
see also: Process 관리 함수
반응형
'C언어 header > unistd.h' 카테고리의 다른 글
fdatasync(2) - kernel에 buffering된 데이터를 disk에 동기화 하기(Meta 정보 제외) (0) | 2019.10.01 |
---|---|
execvp(3) - PATH설정된 프로그램 실행 (배열방식의 argument) (0) | 2019.10.01 |
execv(3) - 프로그램 실행 (argument를 배열행태로) (0) | 2019.10.01 |
close(2) - 열려진 파일을 닫습니다. (0) | 2019.09.30 |
execlp(3) - PATH 설정된 프로그램 실행(list식 argument) (0) | 2019.09.30 |