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);

※全部コメント入れながら書いてくのが骨なんで、途中からすっ飛ばしました。ご了承下さい。