+/*
+ * load_init_program_at_path
+ *
+ * Description: Load the "init" program; in most cases, this will be "launchd"
+ *
+ * Parameters: p Process to call execve() to create
+ * the "init" program
+ * scratch_addr Page in p, scratch space
+ * path NULL terminated path
+ *
+ * Returns: KERN_SUCCESS Success
+ * !KERN_SUCCESS See execve/mac_execve for error codes
+ *
+ * Notes: The process that is passed in is the first manufactured
+ * process on the system, and gets here via bsd_ast() firing
+ * for the first time. This is done to ensure that bsd_init()
+ * has run to completion.
+ *
+ * The address map of the first manufactured process is 32 bit.
+ * WHEN this becomes 64b, this code will fail; it needs to be
+ * made 64b capable.
+ */
+static int
+load_init_program_at_path(proc_t p, user_addr_t scratch_addr, const char* path)
+{
+ uint32_t argv[3];
+ uint32_t argc = 0;
+ int retval[2];
+ struct execve_args init_exec_args;
+
+ /*
+ * Validate inputs and pre-conditions
+ */
+ assert(p);
+ assert(scratch_addr);
+ assert(path);
+
+ if (IS_64BIT_PROCESS(p)) {
+ panic("Init against 64b primordial proc not implemented");
+ }
+
+ /*
+ * Copy out program name.
+ */
+ size_t path_length = strlen(path) + 1;
+ (void) copyout(path, scratch_addr, path_length);
+
+ argv[argc++] = (uint32_t)scratch_addr;
+ scratch_addr = USER_ADDR_ALIGN(scratch_addr + path_length, 16);
+
+ /*
+ * Put out first (and only) argument, similarly.
+ * Assumes everything fits in a page as allocated above.
+ */
+ if (boothowto & RB_SINGLE) {
+ const char *init_args = "-s";
+ size_t init_args_length = strlen(init_args)+1;
+
+ copyout(init_args, scratch_addr, init_args_length);
+
+ argv[argc++] = (uint32_t)scratch_addr;
+ scratch_addr = USER_ADDR_ALIGN(scratch_addr + init_args_length, 16);
+ }
+
+ /*
+ * Null-end the argument list
+ */
+ argv[argc] = 0;
+
+ /*
+ * Copy out the argument list.
+ */
+ (void) copyout(argv, scratch_addr, sizeof(argv));
+
+ /*
+ * Set up argument block for fake call to execve.
+ */
+ init_exec_args.fname = CAST_USER_ADDR_T(argv[0]);
+ init_exec_args.argp = scratch_addr;
+ init_exec_args.envp = USER_ADDR_NULL;
+
+ /*
+ * So that init task is set with uid,gid 0 token
+ */
+ set_security_token(p);
+
+ return execve(p, &init_exec_args, retval);
+}
+