NetBSD-current /sbin/initが起動されるまで(2)
sys_execve()は単にexecve1を呼んでいる:
/* * exec system call */ /* ARGSUSED */ int sys_execve(struct lwp *l, const struct sys_execve_args *uap, register_t *retval) { /* { syscallarg(const char *) path; syscallarg(char * const *) argp; syscallarg(char * const *) envp; } */ return execve1(l, SCARG(uap, path), SCARG(uap, argp), SCARG(uap, envp), execve_fetch_element); }
execve1()の中を見てみよう:
プロセス数上限に達しているかどうかチェック
if ((p->p_flag & PK_SUGID) && chgproccnt(kauth_cred_getuid(l->l_cred), 0) > p->p_rlimit[RLIMIT_NPROC].rlim_cur) return EAGAIN;
ロックを獲得。
rw_enter(&p->p_reflock, RW_WRITER);
プログラムのpathをコピー
pathbuf = PNBUF_GET(); error = copyinstr(path, pathbuf, MAXPATHLEN, &pathbuflen); if (error) { DPRINTF(("execve: copyinstr path %d", error)); goto clrflg; }
exec packageのフィールドを初期化
pack.ep_name = path; pack.ep_hdr = kmem_alloc(exec_maxhdrsz, KM_SLEEP); pack.ep_hdrlen = exec_maxhdrsz; pack.ep_hdrvalid = 0; pack.ep_ndp = &nid; pack.ep_emul_arg = NULL; pack.ep_vmcmds.evs_cnt = 0; pack.ep_vmcmds.evs_used = 0; pack.ep_vap = &attr; pack.ep_flags = 0; pack.ep_emul_root = NULL; pack.ep_interp = NULL; pack.ep_esch = NULL; pack.ep_pax_flags = 0;
プログラムが実行可能かチェック
if ((error = check_exec(l, &pack)) != 0) { if (error != ENOENT) { DPRINTF(("execve: check exec failed %d\n", error)); } goto freehdr; }
引数のバッファをアロケート
argp = (char *) uvm_km_alloc(exec_map, NCARGS, 0, UVM_KMF_PAGEABLE|UVM_KMF_WAITVA);
引数のコピー
while (1) { len = argp + ARG_MAX - dp; if ((error = (*fetch_element)(args, i, &sp)) != 0) { DPRINTF(("execve: fetch_element args %d\n", error)); goto bad; } if (!sp) break; if ((error = copyinstr(sp, dp, len, &len)) != 0) { DPRINTF(("execve: copyinstr args %d\n", error)); if (error == ENAMETOOLONG) error = E2BIG; goto bad; } ktrexecarg(dp, len - 1); dp += len; i++; argc++; }
環境変数のコピー
if (envs != NULL) { i = 0; while (1) { len = argp + ARG_MAX - dp; if ((error = (*fetch_element)(envs, i, &sp)) != 0) { DPRINTF(("execve: fetch_element env %d\n", error)); goto bad; } if (!sp) break; if ((error = copyinstr(sp, dp, len, &len)) != 0) { DPRINTF(("execve: copyinstr env %d\n", error)); if (error == ENAMETOOLONG) error = E2BIG; goto bad; } ktrexecenv(dp, len - 1); dp += len; i++; envc++; } }
uvmspace_exec(l, pack.ep_vm_minaddr, pack.ep_vm_maxaddr);
新しいプロセスのVMスペースを作成
error = (*vcp->ev_proc)(l, vcp);
レジスタの設定
>|c|
(*pack.ep_esch->es_emul->e_setregs)(l, &pack, (u_long) stack);
if (pack.ep_esch->es_setregs)
(*pack.ep_esch->es_setregs)(l, &pack, (u_long) stack);
エミュレーションのexec hookを実行
if (pack.ep_esch->es_emul->e_proc_exec)
(*pack.ep_esch->es_emul->e_proc_exec)(p, &pack);
※全部コメント入れながら書いてくのが骨なんで、途中からすっ飛ばしました。ご了承下さい。