int wrap_clone_child(void *args) { struct clone_args *clargs = args; int (*fn)(void *) = clargs->fn; int flags = clargs->flags; void *arg = clargs->arg; /* We always free in the client */ free(clargs); if (!(flags & CLONE_VM)) { pseudo_setupenv(); if (!pseudo_has_unload(NULL)) { pseudo_reinit_libpseudo(); } else { pseudo_dropenv(); } } return fn(arg); }
/* spawn server */ static int client_spawn_server(void) { int status; FILE *fp; char * pseudo_pidfile; if ((server_pid = fork()) != 0) { if (server_pid == -1) { pseudo_diag("couldn't fork server: %s\n", strerror(errno)); return 1; } pseudo_debug(4, "spawned server, pid %d\n", server_pid); /* wait for the child process to terminate, indicating server * is ready */ waitpid(server_pid, &status, 0); server_pid = -2; pseudo_pidfile = pseudo_localstatedir_path(PSEUDO_PIDFILE); fp = fopen(pseudo_pidfile, "r"); if (fp) { if (fscanf(fp, "%d", &server_pid) != 1) { pseudo_debug(1, "Opened server PID file, but didn't get a pid.\n"); } fclose(fp); } else { pseudo_debug(1, "no pid file (%s): %s\n", pseudo_pidfile, strerror(errno)); } pseudo_debug(2, "read new pid file: %d\n", server_pid); free(pseudo_pidfile); /* at this point, we should have a new server_pid */ return 0; } else { char *base_args[] = { NULL, NULL, NULL }; char **argv; char *option_string = pseudo_get_value("PSEUDO_OPTS"); int args; int fd; pseudo_new_pid(); base_args[0] = pseudo_bindir_path("pseudo"); base_args[1] = "-d"; if (option_string) { char *s; int arg; /* count arguments in PSEUDO_OPTS, starting at 2 * for pseudo/-d/NULL, plus one for the option string. * The number of additional arguments may be less * than the number of spaces, but can't be more. */ args = 4; for (s = option_string; *s; ++s) if (*s == ' ') ++args; argv = malloc(args * sizeof(char *)); argv[0] = base_args[0]; argv[1] = base_args[1]; arg = 2; while ((s = strsep(&option_string, " ")) != NULL) { if (*s) { argv[arg++] = strdup(s); } } argv[arg] = 0; } else { argv = base_args; } /* close any higher-numbered fds which might be open, * such as sockets. We don't have to worry about 0 and 1; * the server closes them already, and more importantly, * they can't have been opened or closed without us already * having spawned a server... The issue is just socket() * calls which could result in fds being left open, and those * can't overwrite fds 0-2 unless we closed them... * * No, really. It works. */ for (fd = 3; fd < 1024; ++fd) { if (fd != pseudo_util_debug_fd) close(fd); } /* and now, execute the server */ pseudo_set_value("PSEUDO_RELOADED", "YES"); pseudo_setupenv(); pseudo_dropenv(); /* drop PRELINK_LIBRARIES */ pseudo_debug(4, "calling execv on %s\n", argv[0]); execv(argv[0], argv); pseudo_diag("critical failure: exec of pseudo daemon failed: %s\n", strerror(errno)); exit(1); } }