Mac OS X Internals: A Systems Approach
5.8. Launching the First User-Space Program
As BSD initialization concludes, load_init_program() [bsd/kern/kern_exec.c] is called to launch the first user program, which is traditionally /sbin/init on Unix systems but is another init program on Mac OS X.[38] The function first attempts to execute /sbin/launchd. If that fails, it attempts /sbin/mach_init. If that too fails, it prompts the user for a pathname to the program to run. The kernel uses getchar() [bsd/dev/ppc/machdep.c] to read the name character by character, echoing each character read. getchar() uses cngetc() and cnputc() [osfmk/console/ppc/serial_console.c], which are wrappers around the now established console I/O operations. [38] /sbin/launchd is the default init program beginning with Mac OS X 10.4. load_init_program() allocates a page of memory in the current task's map. It populates the page with a null-terminated list of arguments that have been collected so far in a string variable. argv[0] contains the init program's null-terminated name (e.g., /sbin/launchd), argv[1] contains an argument string that has a maximum size of 128 bytes (including the terminating NUL character), and argv[2] is NULL. Examples of arguments passed to the init program include those indicating safe (-x), single-user (-s), and verbose (-v) booting modes. An execve_args structure [bsd/sys/exec.h] is populated so that execve() can be called from within the kernel, while pretending as if it were called from user space. Consequently, these arguments are first copied out to user space, since the execve() system call expects its arguments to be there. // bsd/kern/kern_exec.c static char *init_program_name[128] = "/sbin/launchd"; static const char *other_init = "/sbin/mach_init"; char init_args[128] = ""; struct execve_args init_exec_args; int init_attempts = 0; void load_init_program(struct proc *p) { vm_offset_t init_addr; char *argv[3]; int error; register_t retval[2]; error = 0; do { ... // struct execve_args { // char *fname; // char **argp; // char **envp; // }; init_exec_args.fname = /* user space init_program_name */ init_exec_args.argp = /* user space init arguments */ init_exec.args.envp = /* user space NULL */ // need init to run with uid and gid 0 set_security_token(p); error = execve(p, &init_exec_args, retval); } while (error); }
Finally, the first user-space program begins to execute. |
Категории