이 코드는 어떤 문제를 푸나요?
커널 내부에서 실행되던 init 태스크가 사용자 프로그램으로 바뀌려면 파일 이름, 인자 배열, 환경 배열이 준비되어야 합니다. 이 작은 함수는 그 연결을 보여 줍니다. 성공한 exec는 현재 태스크의 프로그램을 바꾸므로 새 자식 프로세스를 만드는 fork와 다릅니다.
읽을 범위: v6.6 · init/main.c · run_init_process 1341–1354행입니다. 아래에 이 범위의 원문과 각 줄의 설명을 실었습니다. 주제 전체의 흐름과 다른 경로는 기존 분석에서 함께 읽으실 수 있습니다.
먼저 알아둘 개념
argv와 envp
각각 프로그램 인자와 환경 문자열의 포인터 배열입니다. 끝은 NULL 포인터로 표시합니다.
exec
현재 프로세스의 실행 이미지를 새 프로그램으로 바꿉니다. PID가 새로 생기는 동작과 구분합니다.
처음 읽을 때
코드를 읽을 때 argv[0]에 실행할 init의 이름을 넣습니다. 그다음 어느 상태가 바뀌는지 각 줄에서 확인하세요.
더 깊이 살펴볼 때
이 경로의 호출 문맥, 잠금·인터럽트 상태, 오류 시 남는 자원을 함께 추적해 보세요. 호출된 함수가 수행하는 작업과 현재 함수가 직접 보장하는 범위를 구분하는 것이 중요합니다.
그림으로 보는 변화

1. 파일 이름 준비
argv[0]에 실행할 init의 이름을 넣습니다.
화살표는 인자 준비 순서입니다.
2. 전달 내용 확인
인자와 환경 배열을 NULL까지 순회해 로그로 확인합니다.
문자열 내용 복사가 아니라 포인터 배열 순회입니다.
3. 프로그램 전환
kernel_execve로 새 사용자 이미지를 준비합니다.
성공하면 이후 사용자 공간 실행으로 이어집니다.
run_init_process를 한 줄씩 읽기
줄 번호는 v6.6 원문 기준입니다. 주석·빈 줄을 포함한 함수 전체를 먼저 보고, 그 아래에서 각 줄을 설명합니다.
static int run_init_process(const char *init_filename)
{
const char *const *p;
argv_init[0] = init_filename;
pr_info("Run %s as init process\n", init_filename);
pr_debug(" with arguments:\n");
for (p = argv_init; *p; p++)
pr_debug(" %s\n", *p);
pr_debug(" with environment:\n");
for (p = envp_init; *p; p++)
pr_debug(" %s\n", *p);
return kernel_execve(init_filename, argv_init, envp_init);
}static int run_init_process(const char *init_filename)현재 init 태스크에서 init_filename이 지정한 사용자 프로그램 실행을 시도합니다. int 반환값은 kernel_execve의 결과이며 새 PID를 만드는 함수가 아닙니다.
const char *const *p;argv나 envp의 문자열 포인터 배열을 한 원소씩 읽을 순회 포인터입니다. *p가 현재 문자열 주소이고 NULL이면 배열 끝입니다. 포인터가 보관하는 것은 객체의 주소입니다. 이 선언만으로 대상 구조체나 문자열의 내용이 복사되지는 않습니다.
argv_init[0] = init_filename;사용자 프로그램이 받는 첫 번째 인자 포인터를 실행 파일 이름으로 정합니다. 문자열 전체를 복사하지 않습니다.
pr_info("Run %s as init process\n", init_filename);지금 어떤 사용자 init 파일의 실행을 시도하는지 기록합니다. 이 로그만으로 exec 성공까지 확인한 것은 아니며 실행 호출은 아래에 있습니다.
pr_debug(" with arguments:\n");뒤의 디버그 출력이 init에 전달할 argv 목록임을 표시합니다. 부팅 실패 때 실제 인자 구성을 확인하기 위한 제목입니다.
for (p = argv_init; *p; p++)argv_init의 첫 원소부터 NULL까지 이동합니다. 각 회차에서 문자열 내용이 아니라 문자열 포인터 하나를 골라 다음 줄에서 출력합니다.
pr_debug(" %s\n", *p);현재 배열 원소 *p가 가리키는 문자열 하나를 출력합니다. argv 순회 안에서는 인자, envp 순회 안에서는 환경 문자열을 보여 줍니다.
pr_debug(" with environment:\n");이후 출력이 argv가 아니라 init의 환경 문자열 envp 목록임을 표시합니다.
for (p = envp_init; *p; p++)envp_init의 첫 문자열부터 NULL 종결자 전까지 순회합니다. 환경 문자열을 수정하거나 새로 만드는 루프는 아닙니다.
pr_debug(" %s\n", *p);현재 배열 원소 *p가 가리키는 문자열 하나를 출력합니다. argv 순회 안에서는 인자, envp 순회 안에서는 환경 문자열을 보여 줍니다.
return kernel_execve(init_filename, argv_init, envp_init);커널이 마련한 파일명·인자·환경으로 현재 태스크의 실행 이미지를 바꿀 공통 exec 경로에 들어갑니다.
함께 생각해 볼 질문
argv[0]과 파일 경로는 항상 같은가요?
일반 exec 규약에서는 다를 수 있습니다. 여기서는 init_filename을 argv[0]에 넣습니다.
for 문의 *p는 무엇인가요?
현재 배열 원소인 문자열 포인터입니다. NULL이면 배열 끝입니다.
이 함수가 PID 1을 새로 생성하나요?
PID 1 태스크는 이미 만들어졌습니다. 여기서는 그 태스크가 실행할 프로그램을 정합니다.
출처와 읽은 범위
Linux stable v6.6 · init/main.c
해당 버전 원본 파일 · 기존 코드 분석 · 설명 원고
