Exemple #1
0
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;
}
Exemple #2
0
/// 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)));
    }
}
Exemple #3
0
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);
}
Exemple #4
0
/// 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]))));
    }
}
Exemple #5
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;
}
Exemple #6
0
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 );
}
Exemple #7
0
/*
 * -- 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;
}
Exemple #8
0
/*
 * -- 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);
}
Exemple #9
0
void
impl::stream_redirect_fd::connect_child(const int fd)
{
    safe_dup(m_fd, fd);
}
Exemple #10
0
void
impl::stream_connect::connect_child(const int fd __attribute__((__unused__)))
{
    safe_dup(m_tgt_fd, m_src_fd);
}
Exemple #11
0
/*
 * -- 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;
}
Exemple #12
0
/*
 * -- 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);
}
Exemple #13
0
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 );
	}
}