void impl::stream_capture::connect_child(const int fd) { ::close(m_pipefds[0]); m_pipefds[0] = -1; if (m_pipefds[1] != fd) { safe_dup(m_pipefds[1], fd); } m_pipefds[1] = -1; }
/// Helper function for fork(). /// /// Please note: if you update this function to change the return type or to /// raise different errors, do not forget to update fork() accordingly. /// /// \param stdout_file The name of the file in which to store the stdout. /// If this has the magic value /dev/stdout, then the parent's stdout is /// reused without applying any redirection. /// \param stderr_file The name of the file in which to store the stderr. /// If this has the magic value /dev/stderr, then the parent's stderr is /// reused without applying any redirection. /// /// \return In the case of the parent, a new child object returned as a /// dynamically-allocated object because children classes are unique and thus /// noncopyable. In the case of the child, a NULL pointer. /// /// \throw process::system_error If the call to fork(2) fails. std::auto_ptr< process::child > process::child::fork_files_aux(const fs::path& stdout_file, const fs::path& stderr_file) { std::cout.flush(); std::cerr.flush(); std::auto_ptr< signals::interrupts_inhibiter > inhibiter( new signals::interrupts_inhibiter); pid_t pid = detail::syscall_fork(); if (pid == -1) { inhibiter.reset(NULL); // Unblock signals. throw process::system_error("fork(2) failed", errno); } else if (pid == 0) { inhibiter.reset(NULL); // Unblock signals. #if !defined(__minix) ::setpgid(::getpid(), ::getpid()); #endif /* !defined(__minix) */ try { if (stdout_file != fs::path("/dev/stdout")) { const int stdout_fd = open_for_append(stdout_file); safe_dup(stdout_fd, STDOUT_FILENO); ::close(stdout_fd); } if (stderr_file != fs::path("/dev/stderr")) { const int stderr_fd = open_for_append(stderr_file); safe_dup(stderr_fd, STDERR_FILENO); ::close(stderr_fd); } } catch (const system_error& e) { std::cerr << F("Failed to set up subprocess: %s\n") % e.what(); std::abort(); } return std::auto_ptr< process::child >(NULL); } else { LD(F("Spawned process %s: stdout=%s, stderr=%s") % pid % stdout_file % stderr_file); signals::add_pid_to_kill(pid); inhibiter.reset(NULL); // Unblock signals. return std::auto_ptr< process::child >( new process::child(new impl(pid, NULL))); } }
void impl::stream_redirect_path::connect_child(const int fd) { const int aux = ::open(m_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644); if (aux == -1) throw system_error(IMPL_NAME "::stream_redirect_path::connect_child", "Could not create " + m_path.str(), errno); else safe_dup(aux, fd); }
/// Helper function for fork(). /// /// Please note: if you update this function to change the return type or to /// raise different errors, do not forget to update fork() accordingly. /// /// \return In the case of the parent, a new child object returned as a /// dynamically-allocated object because children classes are unique and thus /// noncopyable. In the case of the child, a NULL pointer. /// /// \throw process::system_error If the calls to pipe(2) or fork(2) fail. std::auto_ptr< process::child > process::child::fork_capture_aux(void) { std::cout.flush(); std::cerr.flush(); int fds[2]; if (detail::syscall_pipe(fds) == -1) throw process::system_error("pipe(2) failed", errno); std::auto_ptr< signals::interrupts_inhibiter > inhibiter( new signals::interrupts_inhibiter); pid_t pid = detail::syscall_fork(); if (pid == -1) { inhibiter.reset(NULL); // Unblock signals. ::close(fds[0]); ::close(fds[1]); throw process::system_error("fork(2) failed", errno); } else if (pid == 0) { inhibiter.reset(NULL); // Unblock signals. #if !defined(__minix) ::setpgid(::getpid(), ::getpid()); #endif /* !defined(__minix) */ try { ::close(fds[0]); safe_dup(fds[1], STDOUT_FILENO); safe_dup(fds[1], STDERR_FILENO); ::close(fds[1]); } catch (const system_error& e) { std::cerr << F("Failed to set up subprocess: %s\n") % e.what(); std::abort(); } return std::auto_ptr< process::child >(NULL); } else { ::close(fds[1]); LD(F("Spawned process %s: stdout and stderr inherited") % pid); signals::add_pid_to_kill(pid); inhibiter.reset(NULL); // Unblock signals. return std::auto_ptr< process::child >( new process::child(new impl(pid, new process::ifdstream(fds[0])))); } }
static atf_error_t child_connect(const stream_prepare_t *sp, int procfd) { atf_error_t err; const int type = atf_process_stream_type(sp->m_sb); if (type == atf_process_stream_type_capture) { close(sp->m_pipefds[0]); err = safe_dup(sp->m_pipefds[1], procfd); } else if (type == atf_process_stream_type_connect) { if (dup2(sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd) == -1) err = atf_libc_error(errno, "Cannot connect descriptor %d to %d", sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd); else err = atf_no_error(); } else if (type == atf_process_stream_type_inherit) { err = atf_no_error(); } else if (type == atf_process_stream_type_redirect_fd) { err = safe_dup(sp->m_sb->m_fd, procfd); } else if (type == atf_process_stream_type_redirect_path) { int aux = open(atf_fs_path_cstring(sp->m_sb->m_path), O_WRONLY | O_CREAT | O_TRUNC, 0644); if (aux == -1) err = atf_libc_error(errno, "Could not create %s", atf_fs_path_cstring(sp->m_sb->m_path)); else { err = safe_dup(aux, procfd); if (atf_is_error(err)) close(aux); } } else { UNREACHABLE; err = atf_no_error(); } return err; }
void process::set_output_error( const std::string &out_file ) { _stdout.reset(); _stderr.reset(); if ( _fdout >= 0 ) ::close( _fdout ); if ( _fderr >= 0 ) ::close( _fderr ); _fdout = ::open( out_file.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0644 ); if ( _fdout < 0 ) throw_errno( "opening process output/error ({0})", out_file ); _fderr = safe_dup( _fdout ); }
/* * -- do_config * * Apply the configuration on the map. It expects each useful line to * start with a known keyword. Note the unconventional return values. * It returns NULL if successful or an error string in case of error. * */ static char * do_config(struct _como * m, int argc, char *argv[]) { static char errstr[1024]; static int scope = CTX_GLOBAL; /* scope of current keyword */ static module_t * mdl = NULL; /* module currently open */ static int node_id = 0; /* current node */ static alias_t * alias = NULL; /* alias currently open */ keyword_t *t; /* * run some checks on the token (i.e., that it exists * and that we have all the arguments it needs). */ t = match_token(argv[0], keywords); if (t == NULL) { sprintf(errstr, "unknown token \"%s\"\n", argv[0]); return errstr; } if (argc < t->nargs) { sprintf(errstr, "\"%s\", requires at least %d arguments\n", argv[0], t->nargs); return errstr; } /* * Check if the keyword is ok in the current scope. */ if (!(t->scope & scope)) { sprintf(errstr, "\"%s\" out of scope\n", argv[0]); return errstr; } /* * configuration actions */ switch (t->action) { case TOK_DBDIR: if (m->cli_args.dbdir_set == 0) { safe_dup(&m->dbdir, argv[1]); } break; case TOK_QUERYPORT: if (m->cli_args.query_port_set == 0 || node_id > 0) { m->node[node_id].query_port = atoi(argv[1]); } break; case TOK_DESCRIPTION: if (scope == CTX_MODULE) safe_dup(&mdl->description, argv[1]); else safe_dup(&alias->description, argv[1]); break; case TOK_END: if (scope == CTX_MODULE) { /* * "end" of a module configuration. run some checks depending * on context to make sure that all mandatory fields are there * and set default values */ if (check_module(m, mdl)) { remove_module(m, mdl); scope = CTX_GLOBAL; break; } if (m->runmode == RUNMODE_INLINE) m->inline_mdl = mdl; logmsg(LOGUI, "... module%s %s [%d][%d] ", (mdl->running == RUNNING_ON_DEMAND) ? " on-demand" : "", mdl->name, mdl->node, mdl->priority); logmsg(LOGUI, " filter %s; out %s (%uMB)\n", mdl->filter_str, mdl->output, mdl->streamsize/(1024*1024)); } else if (scope == CTX_VIRTUAL) { /* * we are done with this virtual node. let's go back to * the master node (i.e. node_id == 0) */ node_id = 0; } scope = CTX_GLOBAL; break; case TOK_FILTER: if (scope == CTX_MODULE) safe_dup(&mdl->filter_str, argv[1]); else if (scope == CTX_VIRTUAL) safe_dup(&m->node[node_id].filter_str, argv[1]); break; case TOK_HASHSIZE: mdl->ex_hashsize = mdl->ca_hashsize = atoi(argv[1]); break; case TOK_SOURCE: if (scope == CTX_MODULE) { safe_dup(&mdl->source, argv[1]); } else { safe_dup(&m->node[node_id].source, argv[1]); } break; case TOK_LIBRARYDIR: if (m->cli_args.libdir_set == 0) { safe_dup(&m->libdir, argv[1]); } break; case TOK_LOGFLAGS: if (m->cli_args.logflags_set == 0) { m->logflags = set_flags(0, argv[1]); } break; case TOK_MEMSIZE: /* this keyword can be used in two contexts */ if (m->cli_args.mem_size_set == 0) { m->mem_size = atoi(argv[1]); } break; case TOK_MODULE: if (scope == CTX_GLOBAL) { int node = (m->runmode == RUNMODE_INLINE? -1 : 0); mdl = new_module(m, argv[1], node, -1); scope = CTX_MODULE; /* change scope */ } else { safe_dup(&alias->module, argv[1]); } break; case TOK_MODULE_MAX: m->module_max = atoi(argv[1]); m->modules = safe_realloc(m->modules, sizeof(module_t)*m->module_max); break; case TOK_OUTPUT: safe_dup(&mdl->output, argv[1]); break; case TOK_SNIFFER: add_sniffer(m, argv[1], argv[2], argc > 3 ? argv[3] : NULL); break; case TOK_STREAMSIZE: mdl->streamsize = parse_size(argv[1]); break; case TOK_MAXFILESIZE: m->maxfilesize = parse_size(argv[1]); if (m->maxfilesize > 1024*1024*1024) { m->maxfilesize = DEFAULT_FILESIZE; sprintf(errstr, "'filesize' should be < 1GB --> set to %dMB\n", (int)(m->maxfilesize / (1024*1024))); return errstr; } break; case TOK_ARGS: /* copy the arguments. one line may have multiple arguments * starting from argv[1]. that's why we pass the pointer to * argv[1] and reduce argc by one. */ if (scope == CTX_MODULE) mdl->args = copy_args(mdl->args, &argv[1], argc - 1); else if (scope == CTX_VIRTUAL) m->node[node_id].args = copy_args(m->node->args, &argv[1], argc-1); else if (scope == CTX_ALIAS) { alias->args = copy_args(alias->args, &argv[1], argc - 1); alias->ac += argc - 1; } break; case TOK_ARGSFILE: if (scope == CTX_MODULE) { mdl->args = copy_args_from_file(mdl->args, argv[1], NULL); } else if (scope == CTX_VIRTUAL) { m->node[node_id].args = copy_args_from_file(m->node[node_id].args, argv[1], NULL); } else if (scope == CTX_ALIAS) { int count; alias->args = copy_args_from_file(alias->args, argv[1], &count); alias->ac += count; } break; case TOK_PRIORITY: mdl->priority = atoi(argv[1]); break; case TOK_RUNNING: mdl->running = (strcmp(argv[1], "on-demand") == 0) ? RUNNING_ON_DEMAND : RUNNING_NORMAL; break; case TOK_NAME: safe_dup(&m->node[node_id].name, argv[1]); break; case TOK_LOCATION: safe_dup(&m->node[node_id].location, argv[1]); break; case TOK_TYPE: safe_dup(&m->node[node_id].type, argv[1]); break; case TOK_COMMENT: safe_dup(&m->node[node_id].comment, argv[1]); break; case TOK_VIRTUAL: m->node = safe_realloc(m->node, (m->node_count + 1) * sizeof(node_t)); node_id = m->node_count; bzero(&m->node[node_id], sizeof(node_t)); safe_dup(&m->node[node_id].name, argv[1]); m->node[node_id].location = strdup("Unknown"); m->node[node_id].type = strdup("Unknown"); m->node_count++; scope = CTX_VIRTUAL; break; case TOK_ALIAS: alias = safe_calloc(1, sizeof(alias_t)); safe_dup(&alias->name, argv[1]); alias->next = m->aliases; m->aliases = alias; scope = CTX_ALIAS; break; case TOK_ASNFILE: safe_dup(&m->asnfile, argv[1]); break; case TOK_LIVE_THRESH: m->live_thresh = TIME2TS(0, atoi(argv[1])); break; default: sprintf(errstr, "unknown keyword %s\n", argv[0]); return errstr; } return NULL; }
/* * -- configure * * do a first pass of the command line parameters to find all * configuration files. the options in those files are processed * before any other command line parameter. command line will * overwrite any other configuration, as well as the last config * file will overwrite previous config files. * */ void configure(struct _como * m, int argc, char ** argv) { cli_args_t cli_args; int config_file_exists; int c, i, j; DIR *d; if (m->cli_args.done_flag == 0) { parse_cmdline(&cli_args, argc, argv); if (cli_args.logflags != -1) { m->logflags = cli_args.logflags; m->cli_args.logflags_set = 1; } if (cli_args.dbdir != NULL) { safe_dup(&m->dbdir, cli_args.dbdir); m->cli_args.dbdir_set = 1; } if (cli_args.libdir != NULL) { safe_dup(&m->libdir, cli_args.libdir); m->cli_args.libdir_set = 1; } if (cli_args.query_port != -1) { m->node->query_port = cli_args.query_port; m->cli_args.query_port_set = 1; } if (cli_args.mem_size != 0) { m->mem_size = cli_args.mem_size; m->cli_args.mem_size_set = 1; } m->exit_when_done = cli_args.exit_when_done; } m->runmode = cli_args.runmode; m->inline_fd = (m->runmode == RUNMODE_INLINE) ? 1 /* stdout */ : -1; m->debug = cli_args.debug; /* * build list of config files */ config_file_exists = 0; for (c = 0; c < cli_args.cfg_files_count; c++) { config_file_exists = 1; parse_cfgfile(m, cli_args.cfg_files[c]); } if (!config_file_exists && m->runmode != RUNMODE_INLINE) parse_cfgfile(m, DEFAULT_CFGFILE); /* add default config file */ if (m->runmode == RUNMODE_INLINE) { char *conf_argv[2]; m->exit_when_done = 1; if (cli_args.sniffer != NULL) { add_sniffer(m, cli_args.sniffer, NULL, NULL); } /* prepare the arguments for do_config() */ conf_argv[0] = "module"; conf_argv[1] = cli_args.module; do_config(m, 2, conf_argv); if (cli_args.module_args != NULL) { conf_argv[0] = "args"; conf_argv[1] = cli_args.module_args; do_config(m, 2, conf_argv); } if (cli_args.filter != NULL) { conf_argv[0] = "filter"; conf_argv[1] = cli_args.filter; do_config(m, 2, conf_argv); } conf_argv[0] = "end"; do_config(m, 1, conf_argv); } /* * now look into the virtual nodes and replicate * all modules that have been found in the config file(s) * * these new modules will have the same name but will be * running the additional filter associated with the virtual * node and save data in the virtual node dbdir. * * XXX all virtual nodes will be running on demand and * the source is defined in the configuration (or assumed to * be a trace module). later there shouldn't be a need * for defining the source module anyway... * */ for (i = 0, j = m->module_last; i <= j; i++) { module_t * orig; int node_id; orig = &m->modules[i]; for (node_id = 1; node_id < m->node_count; node_id++) { module_t * mdl; char * nm; /* create a new module and copy it from new module */ mdl = copy_module(m, orig, node_id, -1, m->node[node_id].args); mdl->running = RUNNING_ON_DEMAND; /* append node id to module's output file */ asprintf(&nm, "%s-%d", mdl->output, mdl->node); safe_dup(&mdl->output, nm); free(nm); /* add the node filter to the module filter */ if (m->node[node_id].filter_str) { char * flt; if (!strcmp(mdl->filter_str, "all")) asprintf(&flt, "%s", m->node[node_id].filter_str); else asprintf(&flt,"(%s) and (%s)", m->node[node_id].filter_str, mdl->filter_str); mdl->filter_str = flt; /* FIXME: possible leak */ } /* add the node arguments to the module arguments */ if (m->node[node_id].args) { int k; for (k = 0; m->node[node_id].args[k]; k++) { /* * XXX we copy one argument at a time to avoid * having to count them first. FIX THIS */ mdl->args = copy_args(mdl->args, &m->node[node_id].args[k], 1); } } logmsg(LOGUI, "... module%s %s [%d][%d] ", (mdl->running == RUNNING_ON_DEMAND) ? " on-demand" : "", mdl->name, mdl->node, mdl->priority); logmsg(LOGUI, " filter %s; out %s (%uMB)\n", mdl->filter_str, mdl->output, mdl->streamsize/(1024*1024)); if (mdl->description != NULL) logmsg(LOGUI, " -- %s\n", mdl->description); } } /* * open the dbdir for all nodes (virtual ones included) */ if (m->runmode == RUNMODE_NORMAL) { if (m->dbdir == NULL) panicx("missing db-path"); d = opendir(m->dbdir); if (d == NULL) createdir(m->dbdir); else closedir(d); } /* * process the AS file */ asn_readfile(m->asnfile); }
void impl::stream_redirect_fd::connect_child(const int fd) { safe_dup(m_fd, fd); }
void impl::stream_connect::connect_child(const int fd __attribute__((__unused__))) { safe_dup(m_tgt_fd, m_src_fd); }
/* * -- do_config * * Apply the configuration on the map. It expects each useful line to * start with a known keyword. Note the unconventional return values. * It returns NULL if successful or an error string in case of error. * */ static char * do_config(struct _como * m, int argc, char *argv[]) { static char errstr[1024]; static int scope = CTX_GLOBAL; /* scope of current keyword */ static module_t * mdl = NULL; /* module currently open */ keyword_t *t; /* * run some checks on the token (i.e., that it exists * and that we have all the arguments it needs). */ t = match_token(argv[0], keywords); if (t == NULL) { sprintf(errstr, "unknown token \"%s\"\n", argv[0]); return errstr; } if (argc < t->nargs) { sprintf(errstr, "\"%s\", requires at least %d arguments\n", argv[0], t->nargs); return errstr; } /* * Check if the keyword is ok in the current scope. */ if (!(t->scope & scope)) { sprintf(errstr, "\"%s\" out of scope\n", argv[0]); return errstr; } /* * configuration actions */ switch (t->action) { case TOK_BASEDIR: safe_dup(&m->basedir, argv[1]); break; case TOK_QUERYPORT: m->node->query_port = atoi(argv[1]); break; case TOK_DESCRIPTION: safe_dup(&mdl->description, argv[1]); break; case TOK_END: if (scope == CTX_MODULE) { /* * "end" of a module configuration. run some checks depending * on context to make sure that all mandatory fields are there * and set default values */ if (check_module(m, mdl)) { remove_module(m, mdl); scope = CTX_GLOBAL; break; } if (m->running == INLINE) m->inline_mdl = mdl; logmsg(LOGUI, "... module%s %s [%d][%d] ", (mdl->running == RUNNING_ON_DEMAND) ? " on-demand" : "", mdl->name, mdl->node, mdl->priority); logmsg(LOGUI, " filter %s; out %s (%uMB)\n", mdl->filter_str, mdl->output, mdl->streamsize/(1024*1024)); if (mdl->description != NULL) logmsg(LOGUI, " -- %s\n", mdl->description); scope = CTX_GLOBAL; } else if (scope == CTX_VIRTUAL) { /* * we are done with this virtual node. let's recover * the master node (associated with the global context) */ node_t *p, *q; for (p = m->node, q = NULL; p->id != 0; q = p, p = p->next) ; if (q) { /* the master node is not at the head of the list. * move it there. */ q->next = p->next; p->next = m->node; m->node = p; } scope = CTX_GLOBAL; } break; case TOK_FILTER: if (scope == CTX_MODULE) safe_dup(&mdl->filter_str, argv[1]); else if (scope == CTX_VIRTUAL) safe_dup(&m->node->filter_str, argv[1]); break; case TOK_HASHSIZE: mdl->ex_hashsize = mdl->ca_hashsize = atoi(argv[1]); break; case TOK_SOURCE: safe_dup(&mdl->source, argv[1]); break; case TOK_LIBRARYDIR: safe_dup(&m->libdir, argv[1]); break; case TOK_LOGFLAGS: m->logflags = set_flags(0, argv[1]); break; case TOK_MEMSIZE: /* this keyword can be used in two contexts */ m->mem_size = atoi(argv[1]); if (m->mem_size <= 0 || m->mem_size > 512) { sprintf(errstr, "invalid memory size %d, range is 1..512\n", m->mem_size); return errstr; } break; case TOK_MODULE: mdl = new_module(m, argv[1], (m->running == INLINE? -1 : 0), -1); scope = CTX_MODULE; /* change scope */ break; case TOK_MODULE_MAX: m->module_max = atoi(argv[1]); m->modules = safe_realloc(m->modules, sizeof(module_t)*m->module_max); break; case TOK_OUTPUT: safe_dup(&mdl->output, argv[1]); break; case TOK_SNIFFER: add_sniffer(m, argv[1], argv[2], argc > 3 ? argv[3] : NULL); break; case TOK_STREAMSIZE: mdl->streamsize = parse_size(argv[1]); break; case TOK_MAXFILESIZE: m->maxfilesize = parse_size(argv[1]); if (m->maxfilesize > 1024*1024*1024) { m->maxfilesize = DEFAULT_FILESIZE; sprintf(errstr, "'filesize' should be < 1GB --> set to %dMB\n", m->maxfilesize / (1024*1024)); return errstr; } break; case TOK_ARGS: do { int i,j; if (mdl->args == NULL) { mdl->args = safe_calloc(argc, sizeof(char *)); j = 0; } else { /* * we need to add the current list of optional arguments * to the list we already have. first, count how many we * have got so far and then reallocate memory accordingly */ for (j = 0; mdl->args[j]; j++) ; mdl->args = safe_realloc(mdl->args, (argc + j) * sizeof(char*)); } for (i = 1; i < argc; i++) mdl->args[i+j-1] = safe_strdup(argv[i]); /* * Last position is set to null to be able to know * when args finish from the modules */ mdl->args[i+j-1] = NULL; } while (0); break; case TOK_ARGSFILE: do { FILE *auxfp; char line[512]; int j; /* open the file */ auxfp = fopen(argv[1], "r"); if (auxfp == NULL) { sprintf(errstr, "opening file %s: %s\n", argv[1], strerror(errno)); return errstr; } /* count the number of arguments we already have */ for (j = 0; mdl->args[j]; j++) ; /* read each line in the file and parse it again */ /* XXX we reallocate mdl->args for each line in the file. * this should be done better in a less expensive way. */ while (fgets(line, sizeof(line), auxfp)) { j++; mdl->args = safe_realloc(mdl->args, j * sizeof(char *)); mdl->args[j - 1] = safe_strdup(line); } /* add the last NULL pointer */ mdl->args = safe_realloc(mdl->args, (j + 1) * sizeof(char *)); mdl->args[j] = NULL; fclose(auxfp); } while (0); break; case TOK_PRIORITY: mdl->priority = atoi(argv[1]); break; case TOK_RUNNING: mdl->running = (strcmp(argv[1], "on-demand") == 0) ? RUNNING_ON_DEMAND : RUNNING_NORMAL; break; case TOK_NAME: safe_dup(&m->node->name, argv[1]); break; case TOK_LOCATION: safe_dup(&m->node->location, argv[1]); break; case TOK_TYPE: safe_dup(&m->node->type, argv[1]); break; case TOK_COMMENT: safe_dup(&m->node->comment, argv[1]); break; case TOK_VIRTUAL: do { node_t * node; node = safe_calloc(1, sizeof(struct _node)); node->id = m->node_count; safe_dup(&node->name, argv[1]); node->next = m->node; m->node = node; m->node_count++; scope = CTX_VIRTUAL; } while (0); break; default: sprintf(errstr, "unknown keyword %s\n", argv[0]); return errstr; } return NULL; }
/* * -- configure * * do a first pass of the command line parameters to find all * configuration files. the options in those files are processed * before any other command line parameter. command line will * overwrite any other configuration, as well as the last config * file will overwrite previous config files. * */ void configure(struct _como * m, int argc, char ** argv) { static cli_args_t cli_args; int config_file_exists; int c, i, j; DIR *d; if (cli_args.done == 0) { parse_cmdline(&cli_args, argc, argv); } m->running = cli_args.running; /* * build list of config files */ config_file_exists = 0; for (c = 0; c < cli_args.cfg_files_count; c++) { config_file_exists = 1; parse_cfgfile(m, cli_args.cfg_files[c]); } if (!config_file_exists && m->running == NORMAL) parse_cfgfile(m, DEFAULT_CFGFILE); /* add default config file */ /* use cli args to override cfg file settings */ if (cli_args.basedir != NULL) safe_dup(&m->basedir, cli_args.basedir); if (cli_args.libdir != NULL) safe_dup(&m->libdir, cli_args.libdir); if (cli_args.query_port != -1) m->node->query_port = cli_args.query_port; if (cli_args.mem_size != 0) m->mem_size = cli_args.mem_size; if (cli_args.logflags != -1) m->logflags = cli_args.logflags; m->debug = cli_args.debug; if (m->running == INLINE) { char *conf_argv[2]; if (cli_args.sniffer != NULL) { add_sniffer(m, cli_args.sniffer, NULL, NULL); } /* prepare the arguments for do_config() */ conf_argv[0] = "module"; conf_argv[1] = cli_args.module; do_config(m, 2, conf_argv); if (cli_args.module_args != NULL) { conf_argv[0] = "args"; conf_argv[1] = cli_args.module_args; do_config(m, 2, conf_argv); } if (cli_args.filter != NULL) { conf_argv[0] = "filter"; conf_argv[1] = cli_args.filter; do_config(m, 2, conf_argv); } conf_argv[0] = "end"; do_config(m, 1, conf_argv); } /* * now look into the virtual nodes and replicate * all modules that have been found in the config file(s) * * these new modules will have the same name but will be * running the additional filter associated with the virtual * node and save data in the virtual node basedir. */ for (i = 0, j = m->module_last; i <= j; i++) { node_t * node; module_t * orig; orig = &m->modules[i]; for (node = m->node; node; node = node->next) { module_t * mdl; char * nm; if (node->id == 0) break; /* master node. nothing to do */ /* create a new module and copy it from new module */ mdl = copy_module(m, orig, node->id, -1, NULL); /* append node id to module's output file */ asprintf(&nm, "%s-%d", mdl->output, mdl->node); safe_dup(&mdl->output, nm); free(nm); /* add the node filter to the module filter */ if (node->filter_str) { char * flt; if (!strcmp(mdl->filter_str, "all")) asprintf(&flt, "%s", node->filter_str); else asprintf(&flt,"(%s) and (%s)", node->filter_str, mdl->filter_str); mdl->filter_str = flt; /* FIXME: possible leak */ } logmsg(LOGUI, "... module %s [%d][%d] ", mdl->name, mdl->node, mdl->priority); logmsg(LOGUI, " filter %s; out %s (%uMB)\n", mdl->filter_str, mdl->output, mdl->streamsize/(1024*1024)); if (mdl->description != NULL) logmsg(LOGUI, " -- %s\n", mdl->description); } } /* * open the basedir for all nodes (virtual ones included) */ if (m->basedir == NULL) panicx("missing basedir"); d = opendir(m->basedir); if (d == NULL) createdir(m->basedir); else closedir(d); }
void process::execute( const std::string &exe, const std::vector<std::string> &args ) { try { _id = fork(); if ( _id == -1 ) throw_errno( "process fork" ); if ( _id == 0 ) { // The forked process try { // Close/dup the appriopriate I/O. if ( _fdin >= 0 ) safe_dup( _fdin, STDIN_FILENO ); if ( _fdout >= 0 ) safe_dup( _fdout, STDOUT_FILENO ); if ( _fderr >= 0 ) safe_dup( _fderr, STDERR_FILENO ); // Close all other files. struct rlimit lim; if ( getrlimit( RLIMIT_NOFILE, &lim ) < 0 ) throw_errno( "getting number of file (creating process)" ); for ( int f = 0; f < int(lim.rlim_cur); ++f ) { if ( f != STDIN_FILENO && f != STDOUT_FILENO && f != STDERR_FILENO ) ::close( f ); } // Create the argument list std::vector<char *> cargs; cargs.reserve( args.size() + 2 ); cargs.push_back( const_cast<char *>( exe.c_str() ) ); for ( auto &a: args ) cargs.push_back( const_cast<char *>( a.c_str() ) ); cargs.push_back( nullptr ); // Execute! ::execvp( cargs[0], &cargs[0] ); throw_errno( "failed to exec {0}", exe ); } catch ( std::exception &e ) { base::print_exception( std::cerr, e ); } exit( -1 ); } else { std::unique_lock<std::mutex> lock( the_mutex ); if ( the_processes.empty() ) { std::thread collector( []( void ) { collect_zombies(); } ); collector.detach(); } the_processes[_id] = this; } } catch ( ... ) { throw_add( "creating process {0}", exe ); } }