int main(int argc, char **argv, char **envp) { char *p_argv[] = {0, 0, 0}; char *p_envp[] = {"LD_LIBRARY_PATH=/lib", 0}; #define FILENAME "/bin/hello" //#define FILENAME "/bin/hello-sym" char filename[] = FILENAME; #if 0 /* try some bad combos */ int pid = sys_proc_create("garbagexxx"); printf("Garbage pid result: %d\n", pid); error_t err = sys_proc_run(2342); printf("sys_proc_run(2342) error: %e\n", err); err = sys_proc_run(-1); cprintf("sys_proc_run(-1) error: %e\n", err); #endif #define NUM_KIDS 5 int child_pid[NUM_KIDS]; #if 0 printf("U: attempting to create hello(s)\n"); for (int i = 0; i < NUM_KIDS; i++) child_pid[i] = sys_proc_create("roslib_hello"); for (int i = 0; i < NUM_KIDS; i++) { cprintf("U: attempting to run hello (pid: %d)\n", child_pid[i]); sys_proc_run(child_pid[i]); } #endif printf("U: attempting to create and run hello\n"); p_argv[0] = filename; printf("SPAWN, I'm pid %d, filename %s\n", getpid(), filename); child_pid[0] = sys_proc_create(FILENAME, strlen(FILENAME), p_argv, p_envp); if (child_pid[0] <= 0) printf("Failed to create the child\n"); else if (sys_proc_run(child_pid[0]) < 0) printf("Failed to run the child (pid %d)\n", child_pid[0]); #if 0 printf("U: attempting to create and run another hello\n"); child_pid[1] = sys_proc_create(FILENAME, strlen(FILENAME), 0, 0); if (child_pid[1] <= 0) perror(""); else if (sys_proc_run(child_pid[1]) < 0) perror(""); #endif return 0; }
static void run_process_and_wait(int argc, const char * const *argv, const struct core_set *cores) { int pid, status; size_t max_cores = ros_total_cores(); struct core_set pvcores; pid = sys_proc_create(argv[0], strlen(argv[0]), argv, NULL, 0); if (pid < 0) { perror(argv[0]); exit(1); } ros_get_low_latency_core_set(&pvcores); ros_not_core_set(&pvcores); ros_and_core_sets(&pvcores, cores); for (size_t i = 0; i < max_cores; i++) { if (ros_get_bit(&pvcores, i)) { if (sys_provision(pid, RES_CORES, i)) { fprintf(stderr, "Unable to provision CPU %lu to PID %d: cmd='%s'\n", i, pid, argv[0]); exit(1); } } } sys_proc_run(pid); waitpid(pid, &status, 0); }
/* Creates a child process for program @exe, with args and envs. Will attempt * to look in /bin/ if the initial lookup fails, and will invoke sh to handle * non-elfs. Returns the child's PID on success, -1 o/w. */ pid_t create_child(const char *exe, int argc, char *const argv[], char *const envp[]) { pid_t kid; char *path_exe; char **sh_argv; const char *sh_path = "/bin/sh"; kid = sys_proc_create(exe, strlen(exe), argv, envp, 0); if (kid > 0) return kid; /* Here's how we avoid infinite recursion. We can only have ENOENT the * first time through without bailing out, since all errno paths set exe to * begin with '/'. That includes calls from ENOEXEC, since sh_path begins * with /. To avoid repeated calls to ENOEXEC, we just look for sh_path as * the exe, so if we have consecutive ENOEXECs, we'll bail out. */ switch (errno) { case ENOENT: if (exe[0] == '/') return -1; path_exe = malloc(MAX_PATH_LEN); if (!path_exe) return -1; /* Our 'PATH' is only /bin. */ snprintf(path_exe, MAX_PATH_LEN, "/bin/%s", exe); path_exe[MAX_PATH_LEN - 1] = 0; kid = create_child(path_exe, argc, argv, envp); free(path_exe); break; case ENOEXEC: /* In case someone replaces /bin/sh with a non-elf. */ if (!strcmp(sh_path, exe)) return -1; /* We want enough space for the original argv, plus one entry at the * front for sh_path. When we grab the original argv, we also need the * trailing NULL, which is at argv[argc]. That means we really want * argc + 1 entries from argv. */ sh_argv = malloc(sizeof(char *) * (argc + 2)); if (!sh_argv) return -1; memcpy(&sh_argv[1], argv, sizeof(char *) * (argc + 1)); sh_argv[0] = (char*)sh_path; /* Replace the original argv[0] with the path to exe, which might have * been edited to include /bin/ */ sh_argv[1] = (char*)exe; kid = create_child(sh_path, argc + 1, sh_argv, envp); free(sh_argv); break; default: return -1; } return kid; }
int main(int argc, char *argv[]) { struct childfdmap childfdmap[3]; int ret; int flag = 0; int kid; int talk[2]; char hi[3] = {0}; char *child_argv[3]; /* detect the child by the number of args. */ if (argc > 1) { read(0, hi, 3); assert(!strcmp(hi, "HI")); /* pass something else back */ hi[0] = 'Y'; hi[1] = 'O'; hi[2] = '\0'; write(1, hi, 3); exit(0); } if (pipe(talk) < 0) { perror("pipe"); exit(1); } printd("pipe [%d, %d]\n", talk[0], talk[1]); /* parent will read and write on talk[0], and the child does the same * for talk[1]. internally, writing to talk 0 gets read on talk 1. the * child gets talk1 mapped for both stdin (fd 0) and stdout (fd 1). */ childfdmap[0].parentfd = talk[1]; childfdmap[0].childfd = 0; childfdmap[1].parentfd = talk[1]; childfdmap[1].childfd = 1; sprintf(filename, "/bin/%s", argv[0]); child_argv[0] = filename; child_argv[1] = "1"; /* dummy arg, signal so we know they're the child*/ child_argv[2] = 0; kid = sys_proc_create(filename, strlen(filename), child_argv, NULL, 0); if (kid < 0) { perror("create failed"); exit(1); } ret = syscall(SYS_dup_fds_to, kid, childfdmap, 2); if (ret != 2) { perror("childfdmap faled"); exit(2); } /* close the pipe endpoint that we duped in the child. it doesn't * matter for this test, but after the child exits, the pipe will still * be open unless we close our side of it. */ close(talk[1]); sys_proc_run(kid); if (write(talk[0], "HI", 3) < 3) { perror("write HI"); exit(3); } if (read(talk[0], hi, 3) < 3) { perror("read YO"); exit(4); } assert(!strcmp(hi, "YO")); printf("Passed\n"); return 0; }