int multi_server_drain(void) { const char *myname = "multi_server_drain"; int fd; switch (fork()) { /* Try again later. */ case -1: return (-1); /* Finish existing clients in the background, then terminate. */ case 0: (void) msg_cleanup((MSG_CLEANUP_FN) 0); event_fork(); for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) { event_disable_readwrite(fd); (void) close(fd); /* Play safe - don't reuse this file number. */ if (DUP2(STDIN_FILENO, fd) < 0) msg_warn("%s: dup2(%d, %d): %m", myname, STDIN_FILENO, fd); } var_use_limit = 1; return (0); /* Let the master start a new process. */ default: exit(0); } }
void HELPER(gvec_ors)(void *d, void *a, uint64_t b, uint32_t desc) { intptr_t oprsz = simd_oprsz(desc); vec64 vecb = (vec64)DUP2(b); intptr_t i; for (i = 0; i < oprsz; i += sizeof(vec64)) { *(vec64 *)(d + i) = *(vec64 *)(a + i) | vecb; } clear_high(d, oprsz, desc); }
static void save_endp(ARGV *argv) { int ttl; int fd; if (argv->argc != 5 || (ttl = atoi(argv->argv[1])) <= 0 || (fd = atoi(argv->argv[4])) <= 0) { msg_error("usage: save_endp ttl endpoint endp_props fd"); return; } if (DUP2(0, fd) < 0) msg_fatal("dup2(0, %d): %m", fd); scache_save_endp(scache, ttl, argv->argv[2], argv->argv[3], fd); }
int gtm_pipe(char *command, pipe_type pt) { int pfd[2], child, parent; int dup2_res; pid_t child_pid; parent = (int)pt; child = 1 - parent; if (0 > pipe(pfd)) { PERROR("pipe : "); return -2; } if(-1 == (child_pid = fork())) { PERROR("fork : "); return -1; } else if (0 == child_pid) { /* child process */ close(pfd[parent]); DUP2(pfd[child], child, dup2_res); close(pfd[child]); /* * we should have used exec instead of SYSTEM. * Earlier it was followed by exit(0), which calls exit_handler. * So both child and parent will do exit handling. This can make ref_cnt < 0, or, * it can release semaphores, which we should not rlease until parent exists. * So we just call _exit(0) */ SYSTEM(command); _exit(0); /* just exit from here */ } else { /* parent process */ pipe_child = child_pid; close(pfd[child]); return pfd[parent]; } assert(FALSE); /* It should never get here, just to keep compiler happy. */ return -3; }
int gtm_pipe(char *command, pipe_type pt) { int pfd[2], child, parent; int dup2_res, rc; pid_t child_pid; parent = (int)pt; child = 1 - parent; if (0 > pipe(pfd)) { PERROR("pipe : "); return -2; } if (-1 == (child_pid = fork())) /* BYPASSOK: we exit immediately, no FORK_CLEAN needed */ { PERROR("fork : "); return -1; } else if (0 == child_pid) { /* child process */ CLOSEFILE_RESET(pfd[parent], rc); /* resets "pfd[parent]" to FD_INVALID */ DUP2(pfd[child], child, dup2_res); CLOSEFILE_RESET(pfd[child], rc); /* resets "pfd[child]" to FD_INVALID */ /* We should have used exec instead of SYSTEM. Earlier it was followed by exit(0), which calls exit_handler. * So both child and parent will do exit handling. This can make ref_cnt < 0, or, it can release semaphores, * which we should not release until parent exists. So we just call _exit(0). Add the do nothing if to * keep compiler happy since exiting anyway. */ if (-1 == SYSTEM(command)); _exit(0); /* just exit from here */ } else { /* parent process */ pipe_child = child_pid; CLOSEFILE_RESET(pfd[child], rc); /* resets "pfd[child]" to FD_INVALID */ return pfd[parent]; } assert(FALSE); /* It should never get here, just to keep compiler happy. */ return -3; }
int gtm_pipe(char *command, pipe_type pt) { int pfd[2], child, parent; int dup2_res, rc; pid_t child_pid; parent = (int)pt; child = 1 - parent; if (0 > pipe(pfd)) { PERROR("pipe : "); return -2; } FORK(child_pid); if (-1 == child_pid) { PERROR("fork : "); return -1; } else if (0 == child_pid) { /* child process */ CLOSEFILE_RESET(pfd[parent], rc); /* resets "pfd[parent]" to FD_INVALID */ DUP2(pfd[child], child, dup2_res); CLOSEFILE_RESET(pfd[child], rc); /* resets "pfd[child]" to FD_INVALID */ /* We should have used exec instead of SYSTEM. Earlier it was followed by exit(EXIT_SUCCESS), which calls * exit_handler. So both child and parent will do exit handling. This can make ref_cnt < 0, or, it can release * semaphores, which we should not release until parent exists. So we just call _exit(EXIT_SUCCESS). Add the do * nothing if to keep compiler happy since exiting anyway. */ rc = SYSTEM(command); _exit(EXIT_SUCCESS); /* just exit from here */ } else { /* parent process */ pipe_child = child_pid; CLOSEFILE_RESET(pfd[child], rc); /* resets "pfd[child]" to FD_INVALID */ return pfd[parent]; } }
void master_spawn(MASTER_SERV *serv) { const char *myname = "master_spawn"; MASTER_PROC *proc; MASTER_PID pid; int n; static unsigned master_generation = 0; static VSTRING *env_gen = 0; if (master_child_table == 0) master_child_table = binhash_create(0); if (env_gen == 0) env_gen = vstring_alloc(100); /* * Sanity checks. The master_avail module is supposed to know what it is * doing. */ if (!MASTER_LIMIT_OK(serv->max_proc, serv->total_proc)) msg_panic("%s: at process limit %d", myname, serv->total_proc); if (serv->avail_proc > 0) msg_panic("%s: processes available: %d", myname, serv->avail_proc); if (serv->flags & MASTER_FLAG_THROTTLE) msg_panic("%s: throttled service: %s", myname, serv->path); /* * Create a child process and connect parent and child via the status * pipe. */ master_generation += 1; switch (pid = fork()) { /* * Error. We're out of some essential resource. Best recourse is to * try again later. */ case -1: msg_warn("%s: fork: %m -- throttling", myname); master_throttle(serv); return; /* * Child process. Redirect child stdin/stdout to the parent-child * connection and run the requested command. Leave child stderr * alone. Disable exit handlers: they should be executed by the * parent only. * * When we reach the process limit on a public internet service, we * create stress-mode processes until the process count stays below * the limit for some amount of time. See master_avail_listen(). */ case 0: msg_cleanup((void (*) (void)) 0); /* disable exit handler */ closelog(); /* avoid filedes leak */ if (master_flow_pipe[0] <= MASTER_FLOW_READ) msg_fatal("%s: flow pipe read descriptor <= %d", myname, MASTER_FLOW_READ); if (DUP2(master_flow_pipe[0], MASTER_FLOW_READ) < 0) msg_fatal("%s: dup2: %m", myname); if (close(master_flow_pipe[0]) < 0) msg_fatal("close %d: %m", master_flow_pipe[0]); if (master_flow_pipe[1] <= MASTER_FLOW_WRITE) msg_fatal("%s: flow pipe read descriptor <= %d", myname, MASTER_FLOW_WRITE); if (DUP2(master_flow_pipe[1], MASTER_FLOW_WRITE) < 0) msg_fatal("%s: dup2: %m", myname); if (close(master_flow_pipe[1]) < 0) msg_fatal("close %d: %m", master_flow_pipe[1]); close(serv->status_fd[0]); /* status channel */ if (serv->status_fd[1] <= MASTER_STATUS_FD) msg_fatal("%s: status file descriptor collision", myname); if (DUP2(serv->status_fd[1], MASTER_STATUS_FD) < 0) msg_fatal("%s: dup2 status_fd: %m", myname); (void) close(serv->status_fd[1]); for (n = 0; n < serv->listen_fd_count; n++) { if (serv->listen_fd[n] <= MASTER_LISTEN_FD + n) msg_fatal("%s: listen file descriptor collision", myname); if (DUP2(serv->listen_fd[n], MASTER_LISTEN_FD + n) < 0) msg_fatal("%s: dup2 listen_fd %d: %m", myname, serv->listen_fd[n]); (void) close(serv->listen_fd[n]); } vstring_sprintf(env_gen, "%s=%o", MASTER_GEN_NAME, master_generation); if (putenv(vstring_str(env_gen)) < 0) msg_fatal("%s: putenv: %m", myname); if (serv->stress_param_val && serv->stress_expire_time > event_time()) serv->stress_param_val[0] = CONFIG_BOOL_YES[0]; execvp(serv->path, serv->args->argv); msg_fatal("%s: exec %s: %m", myname, serv->path); /* NOTREACHED */ /* * Parent. Fill in a process member data structure and set up links * between child and process. Say this process has become available. * If this service has a wakeup timer that is turned on only when the * service is actually used, turn on the wakeup timer. */ default: if (msg_verbose) msg_info("spawn command %s; pid %d", serv->path, pid); proc = (MASTER_PROC *) mymalloc(sizeof(MASTER_PROC)); proc->serv = serv; proc->pid = pid; proc->gen = master_generation; proc->use_count = 0; proc->avail = 0; binhash_enter(master_child_table, (void *) &pid, sizeof(pid), (void *) proc); serv->total_proc++; master_avail_more(serv, proc); if (serv->flags & MASTER_FLAG_CONDWAKE) { serv->flags &= ~MASTER_FLAG_CONDWAKE; master_wakeup_init(serv); if (msg_verbose) msg_info("start conditional timer for %s", serv->name); } return; } }
int repl_log_init(repl_log_file_t log_type, int *log_fd, int *stats_fd, char *log, char *stats_log) { /* Open the log file */ char log_file_name[MAX_FN_LEN + 1], *err_code; int tmp_fd; int save_errno; int stdout_status, stderr_status; error_def(ERR_REPLLOGOPN); error_def(ERR_TEXT); if (*log == '\0') return(EREPL_LOGFILEOPEN); strcpy(log_file_name, log); if (log_type == REPL_STATISTICS_LOG) { if (strcmp(log_file_name, stats_log) != 0) strcpy(log_file_name, stats_log); else { *stats_fd = *log_fd; return(SS_NORMAL); } } OPENFILE3(log_file_name, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, tmp_fd); if (tmp_fd < 0) { if (log_type == REPL_GENERAL_LOG && *log_fd == -1 || *stats_fd == -1) { save_errno = ERRNO; err_code = STRERROR(save_errno); send_msg(VARLSTCNT(8) ERR_REPLLOGOPN, 6, LEN_AND_STR(log_file_name), LEN_AND_STR(err_code), LEN_AND_STR(NULL_DEVICE)); strcpy(log_file_name, NULL_DEVICE); if (log_type == REPL_GENERAL_LOG) strcpy(log, log_file_name); else strcpy(stats_log, log_file_name); OPENFILE(log_file_name, O_RDWR, tmp_fd); /* Should not fail */ } else { save_errno = ERRNO; err_code = STRERROR(save_errno); gtm_putmsg(VARLSTCNT(8) ERR_REPLLOGOPN, 6, LEN_AND_STR(log_file_name), LEN_AND_STR(err_code), (log_type == REPL_GENERAL_LOG) ? strlen(log) : strlen(stats_log), (log_type == REPL_GENERAL_LOG) ? log : stats_log); return(EREPL_LOGFILEOPEN); } } if (log_type == REPL_GENERAL_LOG) { int dup2_res; /* Duplicate stdout and stderr onto log file */ DUP2(tmp_fd, 1, stdout_status); if (stdout_status >= 0) { DUP2(tmp_fd, 2, stderr_status); if (stderr_status < 0) { save_errno = ERRNO; if (*log_fd != -1) { DUP2(*log_fd, 1, dup2_res); /* Restore old log file */ DUP2(*log_fd, 2, dup2_res); } } } else { save_errno = ERRNO; if (*log_fd != -1) DUP2(*log_fd, 1, dup2_res); /* Restore old log file */ } if (stdout_status >= 0 && stderr_status >= 0) { if (*log_fd != -1) close(*log_fd); *log_fd = tmp_fd; } else { err_code = STRERROR(save_errno); gtm_putmsg(VARLSTCNT(10) ERR_REPLLOGOPN, 6, LEN_AND_STR(log_file_name), LEN_AND_STR(err_code), (log_type == REPL_GENERAL_LOG) ? strlen(log) : strlen(stats_log), (log_type == REPL_GENERAL_LOG) ? log : stats_log, ERR_TEXT, 2, RTS_ERROR_LITERAL("Error in dup2")); } } else { if (*stats_fd != -1) close(*stats_fd); *stats_fd = tmp_fd; } return(SS_NORMAL); }