static pid_t spawn_ppp(struct cw_channel *chan, const char *argv[]) { /* Start by forking */ pid_t pid; #if defined(HAVE_WORKING_FORK) pid = fork(); #else pid = vfork(); #endif if (pid) return pid; dup2(chan->fds[0], STDIN_FILENO); int i; int max_fds = get_max_fds(); for (i=STDERR_FILENO + 1; i < max_fds; i++) close(i); /* Restore original signal handlers */ for (i=0; i<NSIG; i++) signal(i, SIG_DFL); /* Finally launch PPP */ execv(PPP_EXEC, (char * const *)argv); fprintf(stderr, "Failed to exec pppd!: %s\n", strerror(errno)); exit(1); }
/* Close all file descriptors starting with descriptor FIRST. If EXCEPT is not NULL, it is expected to be a list of file descriptors which shall not be closed. This list shall be sorted in ascending order with the end marked by -1. */ void close_all_fds (int first, int *except) { int max_fd = get_max_fds (); int fd, i, except_start; if (except) { except_start = 0; for (fd=first; fd < max_fd; fd++) { for (i=except_start; except[i] != -1; i++) { if (except[i] == fd) { /* If we found the descriptor in the exception list we can start the next compare run at the next index because the exception list is ordered. */ except_start = i + 1; break; } } if (except[i] == -1) close (fd); } } else { for (fd=first; fd < max_fd; fd++) close (fd); } gpg_err_set_errno (0); }
tcpdemux::tcpdemux():outdir("."),flow_counter(0),packet_counter(0), xreport(0),pwriter(0),max_open_flows(),max_fds(get_max_fds()-NUM_RESERVED_FDS), flow_map(),open_flows(),saved_flow_map(), saved_flows(),start_new_connections(false),opt(),fs() { }
static pid_t spawn_ppp( struct ast_channel *chan, const char *argv[], int argc) { /* Start by forking */ pid_t pid = fork(); if (pid) return pid; close(0); int i; int max_fds = get_max_fds(); for (i=STDERR_FILENO + 1; i < max_fds; i++) close(i); /* Restore original signal handlers */ for (i=0; i<NSIG; i++) signal(i, SIG_DFL); /* Finally launch PPP */ execv(PPP_EXEC, (char * const *)argv); fprintf(stderr, "Failed to exec pppd!: %s\n", strerror(errno)); exit(1); }
tcpdemux::tcpdemux(): #ifdef HAVE_SQLITE3 db(),insert_flow(), #endif outdir("."),flow_counter(0),packet_counter(0), xreport(0),pwriter(0),max_open_flows(),max_fds(get_max_fds()-NUM_RESERVED_FDS), flow_map(),open_flows(),saved_flow_map(), saved_flows(),start_new_connections(false),opt(),fs() { }
/* Starts a subprocess with the arguments in the null-terminated argv[] array. * argv[0] is used as the name of the process. Searches the PATH environment * variable to find the program to execute. * * All file descriptors are closed before executing the subprocess, except for * fds 0, 1, and 2 and the 'n_keep_fds' fds listed in 'keep_fds'. Also, any of * the 'n_null_fds' fds listed in 'null_fds' are replaced by /dev/null. * * Returns 0 if successful, otherwise a positive errno value indicating the * error. If successful, '*pp' is assigned a new struct process that may be * used to query the process's status. On failure, '*pp' is set to NULL. */ int process_start(char **argv, const int keep_fds[], size_t n_keep_fds, const int null_fds[], size_t n_null_fds, struct process **pp) { sigset_t oldsigs; pid_t pid; int error; *pp = NULL; COVERAGE_INC(process_start); error = process_prestart(argv); if (error) { return error; } block_sigchld(&oldsigs); pid = fork(); if (pid < 0) { unblock_sigchld(&oldsigs); VLOG_WARN("fork failed: %s", strerror(errno)); return errno; } else if (pid) { /* Running in parent process. */ *pp = process_register(argv[0], pid); unblock_sigchld(&oldsigs); return 0; } else { /* Running in child process. */ int fd_max = get_max_fds(); int fd; fatal_signal_fork(); unblock_sigchld(&oldsigs); for (fd = 0; fd < fd_max; fd++) { if (is_member(fd, null_fds, n_null_fds)) { /* We can't use get_null_fd() here because we might have * already closed its fd. */ int nullfd = open("/dev/null", O_RDWR); dup2(nullfd, fd); close(nullfd); } else if (fd >= 3 && !is_member(fd, keep_fds, n_keep_fds)) { close(fd); } } execvp(argv[0], argv); fprintf(stderr, "execvp(\"%s\") failed: %s\n", argv[0], strerror(errno)); _exit(1); } }
tcpdemux::tcpdemux():outdir("."),flow_counter(0),packet_counter(0), xreport(0),max_fds(10),flow_map(),start_new_connections(false), openflows(), opt(),fs() { /* Find out how many files we can have open safely...subtract 4 for * stdin, stdout, stderr, and the packet filter; one for breathing * room (we open new files before closing old ones), and one more to * be safe. */ max_fds = get_max_fds() - NUM_RESERVED_FDS; }
/* Returns an array with all currently open file descriptors. The end of the array is marked by -1. The caller needs to release this array using the *standard free* and not with xfree. This allow the use of this fucntion right at startup even before libgcrypt has been initialized. Returns NULL on error and sets ERRNO accordingly. */ int * get_all_open_fds (void) { int *array; size_t narray; int fd, max_fd, idx; #ifndef HAVE_STAT array = calloc (1, sizeof *array); if (array) array[0] = -1; #else /*HAVE_STAT*/ struct stat statbuf; max_fd = get_max_fds (); narray = 32; /* If you change this change also t-exechelp.c. */ array = calloc (narray, sizeof *array); if (!array) return NULL; /* Note: The list we return is ordered. */ for (idx=0, fd=0; fd < max_fd; fd++) if (!(fstat (fd, &statbuf) == -1 && errno == EBADF)) { if (idx+1 >= narray) { int *tmp; narray += (narray < 256)? 32:256; tmp = realloc (array, narray * sizeof *array); if (!tmp) { free (array); return NULL; } array = tmp; } array[idx++] = fd; } array[idx] = -1; #endif /*HAVE_STAT*/ return array; }
/* Initialize our structures */ void init_flow_state() { int i; /* Find out how many files we can have open safely...subtract 4 for * stdin, stdout, stderr, and the packet filter; one for breathing * room (we open new files before closing old ones), and one more to * be safe. */ max_fds = get_max_fds() - NUM_RESERVED_FDS; fd_ring = MALLOC(flow_state_t *, max_fds); for (i = 0; i < max_fds; i++) fd_ring[i] = NULL; for (i = 0; i < HASH_SIZE; i++) flow_hash[i] = NULL; next_slot = -1; current_time = 0; }
int main(int argc, char *argv[]) { if (argc == 1) print_usage(); int in_guard_mode = 0; int dump_core = 0; int children_instance = 0; char *run_as_user = NULL; // parse args int c = -1; extern char *optarg; extern int optopt; const char *opt = ":gvu:Cs:ep:h"; while((c = getopt(argc, argv, opt)) != -1) { switch (c) { case 'v': // version fprintf(stderr, "\033[0;32m%s %s\033[0m\n", SVC_EDITION, BIN_V); return 0; case 'g': in_guard_mode = 1; break; case 'u': run_as_user = optarg; break; case 'C': dump_core = 1; break; case 'e': children_instance = 1; break; case 'p': break; case ':': fprintf(stderr, "\n\033[0;35mOption -%c requires an operand\033[0m\n", optopt); case 'h': default: print_usage(); } } const int max_clients = 1024*4; set_max_fds(max_clients); g_max_fds = get_max_fds(); if (run_as_user && runas(run_as_user) != 0) { fprintf(stderr, "\033[0;35mSudo to %s error!\033[0m\n", run_as_user); return -1; } if (dump_core && dump_corefile() != 0) { fprintf(stderr, "\033[0;35mSet dump corefile error!\033[0m\n"); return -1; } if (in_guard_mode) { if (children_instance == 0) guard_process(g_svc_name, argc, argv); clean_fds(); }else output_pid(g_svc_name); //= child process child_sig_handle(); sys::r = new reactor(); if (sys::r->open(max_clients, max_clients + 16) != 0) { fprintf(stderr, "Error: reactor - open failed!\n"); return -1; } if (sys::init_svc() != 0) { fprintf(stderr, "Error: init_svc - init failed!\n"); return -1; } s_log->rinfo("launch ok! max fds:%d", g_max_fds); e_log->rinfo("launch ok! max fds:%d", g_max_fds); // reactor event loop sys::r->run_reactor_event_loop(); return 1; }
/* That is a very crude test. To do a proper test we would need to fork a test process and best return information by some other means than file descriptors. */ static void test_close_all_fds (void) { int max_fd = get_max_fds (); int *array; int fd; int initial_count, count, n; #if 0 char buffer[100]; snprintf (buffer, sizeof buffer, "/bin/ls -l /proc/%d/fd", (int)getpid ()); system (buffer); #endif printf ("max. file descriptors: %d\n", max_fd); array = xget_all_open_fds (); print_open_fds (array); for (initial_count=n=0; array[n] != -1; n++) initial_count++; free (array); /* Some dups to get more file descriptors and close one. */ dup (1); dup (1); fd = dup (1); dup (1); close (fd); array = xget_all_open_fds (); if (verbose) print_open_fds (array); for (count=n=0; array[n] != -1; n++) count++; if (count != initial_count+3) { fprintf (stderr, "%s:%d: dup or close failed\n", __FILE__, __LINE__); exit (1); } free (array); /* Close the non standard ones. */ close_all_fds (3, NULL); /* Get a list to check whether they are all closed. */ array = xget_all_open_fds (); if (verbose) print_open_fds (array); for (count=n=0; array[n] != -1; n++) count++; if (count > initial_count) { fprintf (stderr, "%s:%d: not all files were closed\n", __FILE__, __LINE__); exit (1); } initial_count = count; free (array); /* Now let's check the realloc we use. We do this and the next tests only if we are allowed to open enought descriptors. */ if (get_max_fds () > 32) { int except[] = { 20, 23, 24, -1 }; for (n=initial_count; n < 31; n++) dup (1); array = xget_all_open_fds (); if (verbose) print_open_fds (array); free (array); for (n=0; n < 5; n++) { dup (1); array = xget_all_open_fds (); if (verbose) print_open_fds (array); free (array); } /* Check whether the except list works. */ close_all_fds (3, except); array = xget_all_open_fds (); if (verbose) print_open_fds (array); for (count=n=0; array[n] != -1; n++) count++; free (array); if (count != initial_count + DIM(except)-1) { fprintf (stderr, "%s:%d: close_all_fds failed\n", __FILE__, __LINE__); exit (1); } } }
/* Starts the process whose arguments are given in the null-terminated array * 'argv' and waits for it to exit. On success returns 0 and stores the * process exit value (suitable for passing to process_status_msg()) in * '*status'. On failure, returns a positive errno value and stores 0 in * '*status'. * * If 'stdout_log' is nonnull, then the subprocess's output to stdout (up to a * limit of PROCESS_MAX_CAPTURE bytes) is captured in a memory buffer, which * when this function returns 0 is stored as a null-terminated string in * '*stdout_log'. The caller is responsible for freeing '*stdout_log' (by * passing it to free()). When this function returns an error, '*stdout_log' * is set to NULL. * * If 'stderr_log' is nonnull, then it is treated like 'stdout_log' except * that it captures the subprocess's output to stderr. */ int process_run_capture(char **argv, char **stdout_log, char **stderr_log, int *status) { struct stream s_stdout, s_stderr; sigset_t oldsigs; pid_t pid; int error; COVERAGE_INC(process_run_capture); if (stdout_log) { *stdout_log = NULL; } if (stderr_log) { *stderr_log = NULL; } *status = 0; error = process_prestart(argv); if (error) { return error; } error = stream_open(&s_stdout); if (error) { return error; } error = stream_open(&s_stderr); if (error) { stream_close(&s_stdout); return error; } block_sigchld(&oldsigs); pid = fork(); if (pid < 0) { int error = errno; unblock_sigchld(&oldsigs); VLOG_WARN("fork failed: %s", strerror(error)); stream_close(&s_stdout); stream_close(&s_stderr); *status = 0; return error; } else if (pid) { /* Running in parent process. */ struct process *p; p = process_register(argv[0], pid); unblock_sigchld(&oldsigs); close(s_stdout.fds[1]); close(s_stderr.fds[1]); while (!process_exited(p)) { stream_read(&s_stdout); stream_read(&s_stderr); stream_wait(&s_stdout); stream_wait(&s_stderr); process_wait(p); poll_block(); } stream_read(&s_stdout); stream_read(&s_stderr); if (stdout_log) { *stdout_log = ds_steal_cstr(&s_stdout.log); } if (stderr_log) { *stderr_log = ds_steal_cstr(&s_stderr.log); } stream_close(&s_stdout); stream_close(&s_stderr); *status = process_status(p); process_destroy(p); return 0; } else { /* Running in child process. */ int max_fds; int i; fatal_signal_fork(); unblock_sigchld(&oldsigs); dup2(get_null_fd(), 0); dup2(s_stdout.fds[1], 1); dup2(s_stderr.fds[1], 2); max_fds = get_max_fds(); for (i = 3; i < max_fds; i++) { close(i); } execvp(argv[0], argv); fprintf(stderr, "execvp(\"%s\") failed: %s\n", argv[0], strerror(errno)); exit(EXIT_FAILURE); } }