Пример #1
0
char* service_call (struct service srv, char** default_envp) {
  int pipefd[2];
  if (pipe (pipefd) != 0) {
    perror ("pipe");
  }
  int child;
  if ((child = fork ()) == 0) {
    close (pipefd[0]);
    close (1);
    if (dup2 (pipefd[1], 1) == -1) {
      perror ("dup2");
    }
    // char* service_argv_dummy[] = { NULL, "hello", "world", NULL };
    char* service_argv_dummy[] = {NULL, NULL};
    char** service_argv = service_argv_dummy;
    service_argv[0] = srv.binpath;
    char** service_envp = default_envp;
    // TODO: Devise ways to:
    //       - start,
    //       - stop,
    //       - restart,
    //       - status
    //       on a service.
    if (access (srv.confpath, F_OK) == 0) {
      struct serviceconf* sc = parse_conf_file (srv.confpath);
      service_envp = envp_dup_update_or_add (
          service_envp,
          strl_cons (str_concat ("CLOVESOCKET=", srv.sockpath), NULL));
      service_envp = envp_dup_update_or_add (service_envp, sc->envs);
      // TODO: Make sure this is working properly.
      //       Apparently the order of a duplicate env vars is different
      //       between Darwin and Linux.
      if (sc->interpretter) {
        service_argv[0] = srv.binpath;
        service_argv = argv_dup_add (service_argv, sc->interpretter);
        char* interpretter = service_argv[0];
        execve (interpretter, service_argv, service_envp);
        exit (3);
      }
    }

    if (execve (srv.binpath, service_argv, service_envp) == -1) {
      perror ("execve");
      exit (3);
    }
  }
  close (pipefd[1]);
  printf ("waiting for %s ...\n", srv.name);
  // TODO: have a time out.
  char* buf = malloc (128);  // TODO: Fix hardcoded size.
  // TODO: Fix hardcoded size.
  if (read (pipefd[0], buf, 127) < 0) {
    perror ("(read) could not communicate with the service");
    exit (1);
  }
  buf[127] = 0;  // TODO: Fix hardcoded size.
  printf ("%s says: %s", srv.name, buf);
  close (pipefd[0]);
  return buf;
}
Пример #2
0
static int config_check()
{
    if (!str_empty(robot.conf_file))
    {
        if (!parse_conf_file(robot.conf_file)) return 0;
    }
    else
    {
        fprintf(stderr, "Please input configure file!!!!\n");
        return 0;
    }
    if (conf_lookup(&robot.conf, str_from("QQ")).type != CONF_VALUE_TYPE_STRING || conf_lookup(&robot.conf, str_from("PASSWORD")).type != CONF_VALUE_TYPE_STRING)
    {
        fprintf(stderr, "Invalid QQ or PASSWORD type!!!!\n");
        return 0;
    }
    if (str_empty(conf_lookup(&robot.conf, str_from("DB_HOST")).string))
    {
        fprintf(stdout, "Warning: Unset DB_HOST variable, the default value is 127.0.0.1!!!!\n");
        fflush(stdout);
        conf_append_strs(&robot.conf, "DB_HOST", "127.0.0.1");
    }
    if (str_empty(conf_lookup(&robot.conf, str_from("DB_NAME")).string))
    {
        fprintf(stdout, "Warning: Unset DB_NAME variable, the default value is qqrobot!!!!\n");
        fflush(stdout);
        conf_append_strs(&robot.conf, "DB_NAME", "qqrobot");
    }
    return 1;
}
Пример #3
0
/*
 * Parse arguments.
 */
int parse_options(int argc, char **argv)
{
    int i = 0, j = 0, ret;
    char *conf_file = NULL;

    for (i = 1; i < argc; ++i) {
        if (argv[i][0] == '-') {
            if (!strcasecmp("-help", argv[i])) {
                print_help(argv[0]);
                exit(0);
            } else if (!strcasecmp("-config", argv[i])) {
                i++;
                conf_file = argv[i];
            } else {
                j = 0;
                while (options[j].name != NULL) {
                    if (!strcasecmp(options[j].name, argv[i] + 1)) {
                        ++i;
                        options[j].value = stralloc(argv[i]);
                        break;
                    } else {
                        ++j;
                    }
                }
                if (options[j].name == NULL) {
                    log_msg(LOG_ERR, "unknown option: %s", argv[i]);
                    return -1;
                }
            } /* end if(!strcasecmp()) */
        } else {
            print_help(argv[0]);
            exit(0);
        } /* end if(argv) */
    } /* end for () */
    if (conf_file != NULL) {
        ret = parse_conf_file(conf_file);
        if (ret) {
            log_msg(LOG_ERR, "can't read config file: %s", conf_file);
            return -1;
        }
    } else {
        if (parse_conf_file(DEFAULT_CONF_FILE) == -1)
            parse_conf_file("csync.conf");
    }
    return 0;
}
Пример #4
0
/* Parse .conf file and setup routes */
static void read_conf_file(const char *conf_file)
{
	if (access(conf_file, R_OK)) {
		smclog(LOG_WARNING, errno, "Failed loading %s", conf_file);
		return;
	}

	if (parse_conf_file(conf_file))
		smclog(LOG_WARNING, errno, "Failed reading %s", conf_file);
}
Пример #5
0
int main(int argc, char **argv)
{
	if (argc != 2) {
		fprintf(stderr, "Usage: %s conf-file\n", argv[0]);
		return 1;
	}

	struct conf_info conf_info = parse_conf_file(argv[1]);
	specialize_template(conf_info);
	
	return 0;
}
Пример #6
0
int main(int argc, char **argv) {
	int listenfd, port, ret;
	struct horse *horses;
	unsigned int horse_num, pperh;	
	pthread_mutex_t mutex, mfinished, mbank, mcur_run, mhb, mnr;
	pthread_cond_t cond;
	pthread_barrier_t barrier;		
	struct service service;

	if (argc != 3) {
		usage(argv[0]);
		exit(EXIT_FAILURE);
	}

	// parse port
	port = atoi(argv[1]);

	listenfd = init_socket(port);
	_listen(listenfd, LISTENQ);

	init_sync(&mutex, &cond, &mfinished, &mbank, &mcur_run, &mhb, &mnr);	

	ret = parse_conf_file(argv[2], &horses, &horse_num, &pperh, &mutex, &cond, &barrier, &service);

	if (ret)
		goto clean;	
	
	if (!pperh || pperh > MAX_RACE_NUM) {
		fprintf(stderr, "races per hour %u should be more than 0 and less than %d\n", pperh, MAX_RACE_NUM + 1);
		goto clean;
	}

	init_signals();	
	srand(time(NULL));	
	init_service(&service, &mfinished, &mbank, &mcur_run, &mhb, &mnr, (unsigned int)(60 * 60 / pperh));	

	server_work(listenfd, &cond, &service, horses, horse_num);
	
clean:
	// cleaning
	clean(&mutex, &cond, &mfinished, &mbank, &mcur_run, &mhb, &mnr, horses, listenfd);

	return EXIT_SUCCESS;
}
Пример #7
0
int main(int argc, char** argv)
{
	Properties props;
	if (argc >= 2)
	{
		int j = 1; /* First option to parse in argv[] */
		char *configfile = NULL;

		/* Handle special options --help and --version */
		if (strcmp(argv[1], "-v") == 0 || strcmp(argv[1], "--version") == 0)
			version();
		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0)
			usage();

		/* First argument is the config file name? */
		if (argv[j][0] != '-' || argv[j][1] != '-')
		{
			configfile = argv[j++];
			if (!parse_conf_file(configfile, props, " "))
			{
				printf("Error: Failed to parse conf file:%s\n", configfile);
				return -1;
			}
		}
	} else
	{
		printf(
				"Warning: no config file specified, using the default config. In order to specify a config file use %s /path/to/ardb.conf\n",
				argv[0]);
	}
	signal_setting();
	ArdbServerConfig cfg;
	if(0 != ArdbServer::ParseConfig(props, cfg))
	{
		return -1;
	}
	SelectedDBEngineFactory engine(props);
	ArdbServer server(engine);
	server.Start(props);
	return 0;
}
Пример #8
0
static int
config_init(void)
{
	dictionary *conf;

	conf = open_conf_file(NULL);
	if (conf==NULL) {
		PRINT("cannot parse configure file.");
		return (CSF_ERR);
	}

	parse_conf_file(conf, "server", conf_int_array, conf_str_array);

	main_conf.cp_ops = get_comm_proto(main_conf.server_protocol);

	if (main_conf.cp_ops == NULL)
		CRIT("UNKNOWN COMMUNICATION PROTOCOL!");
	    
	close_conf_file(conf);

	return (CSF_OK);
}
Пример #9
0
int
main(void)
{
	char command[COMMAND_MAX + 1];
	int timestamp=0;
	struct conf_str_config conf_str_array[] = {
		{"command", command}, 
		{0, 0}
	};
	struct conf_int_config conf_int_array[] = {
		{"timestamp", &timestamp},
		{0,0} 
	};
	dictionary	*conf;
	char buf[] = "[command]\r\n\ncommand=\"ls\"\r\ntimestamp=11111\r\n";
	conf = open_conf_mem(buf, strlen(buf));
	if (conf == NULL) {
		fprintf(stderr,"errror");
	}
	parse_conf_file(conf, "command", conf_int_array, conf_str_array);
	close_conf_file(conf);
	printf("%s\n%d\n", command,timestamp);
}
Пример #10
0
int
main (int argc, char **argv)
{
  int quit = 0;

#if defined(__GLIBC__)
  setup_signal_handlers ();
#endif

  /* command line/config options */
  verify_global_config (argc, argv);
  parse_conf_file (&argc, &argv);
  parse_cmd_line (argc, argv);

  /* initialize storage */
  init_storage ();
  /* setup to use the current locale */
  set_locale ();

#ifdef HAVE_LIBGEOIP
  init_geoip ();
#endif

  /* init logger */
  logger = init_log ();
  set_signal_data (logger);

  /* init parsing spinner */
  parsing_spinner = new_gspinner ();
  parsing_spinner->process = &logger->process;

  /* outputting to stdout */
  if (conf.output_html) {
    ui_spinner_create (parsing_spinner);
    goto out;
  }

  /* init curses */
  set_input_opts ();
  if (conf.no_color || has_colors () == FALSE) {
    conf.color_scheme = NO_COLOR;
    conf.no_color = 1;
  } else {
    start_color ();
  }
  init_colors ();
  init_windows (&header_win, &main_win);
  set_curses_spinner (parsing_spinner);

  /* configuration dialog */
  if (isatty (STDIN_FILENO) && (conf.log_format == NULL || conf.load_conf_dlg)) {
    refresh ();
    quit = render_confdlg (logger, parsing_spinner);
  }
  /* straight parsing */
  else {
    ui_spinner_create (parsing_spinner);
  }

out:

  /* main processing event */
  time (&start_proc);
  if (conf.load_from_disk)
    set_general_stats ();
  else if (!quit && parse_log (&logger, NULL, -1))
    FATAL ("Error while processing file");

  logger->offset = logger->process;

  /* no valid entries to process from the log */
  if (logger->process == 0)
    FATAL ("Nothing valid to process.");

  /* init reverse lookup thread */
  gdns_init ();
  parse_initial_sort ();
  allocate_holder ();

  end_spinner ();
  time (&end_proc);

  /* stdout */
  if (conf.output_html)
    standard_output ();
  /* curses */
  else
    curses_output ();

  /* clean */
  house_keeping ();

  return EXIT_SUCCESS;
}
Пример #11
0
int
main(int argc, char **argv)
{
	char *p;
	int optc;

	verbose = 1;
	readcache = 1;
	*outmkname = *outcfname = *execfname = '\0';

	path_make = getenv("MAKE");
	if (path_make == NULL || *path_make == '\0')
		path_make = "make";

	p = getenv("MAKEOBJDIRPREFIX");
	if (p == NULL || *p == '\0')
		objprefix = "/usr/obj"; /* default */
	else
		if ((objprefix = strdup(p)) == NULL)
			out_of_memory();

	while((optc = getopt(argc, argv, "lh:m:c:e:p:foq")) != -1) {
		switch(optc) {
		case 'f':
			readcache = 0;
			break;
		case 'o':
			makeobj = 1;
			break;
		case 'q':
			verbose = 0;
			break;

		case 'm':
			strlcpy(outmkname, optarg, sizeof(outmkname));
			break;
		case 'p':
			if ((objprefix = strdup(optarg)) == NULL)
				out_of_memory();
			break;

		case 'h':
			strlcpy(outhdrname, optarg, sizeof(outhdrname));
			break;
		case 'c':
			strlcpy(outcfname, optarg, sizeof(outcfname));
			break;
		case 'e':
			strlcpy(execfname, optarg, sizeof(execfname));
			break;

		case 'l':
			list_mode++;
			verbose = 0;
			break;

		case '?':
		default:
			usage();
		}
	}

	argc -= optind;
	argv += optind;

	if (argc != 1)
		usage();

	/*
	 * generate filenames
	 */

	strlcpy(infilename, argv[0], sizeof(infilename));

	/* confname = `basename infilename .conf` */

	if ((p=strrchr(infilename, '/')) != NULL)
		strlcpy(confname, p + 1, sizeof(confname));
	else
		strlcpy(confname, infilename, sizeof(confname));

	if ((p=strrchr(confname, '.')) != NULL && !strcmp(p, ".conf"))
		*p = '\0';

	if (!*outmkname)
		snprintf(outmkname, sizeof(outmkname), "%s.mk", confname);
	if (!*outcfname)
		snprintf(outcfname, sizeof(outcfname), "%s.c", confname);
	if (!*execfname)
		snprintf(execfname, sizeof(execfname), "%s", confname);

	snprintf(cachename, sizeof(cachename), "%s.cache", confname);
	snprintf(tempfname, sizeof(tempfname), "%s/crunchgen_%sXXXXXX",
	getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP, confname);

	parse_conf_file();
	if (list_mode)
		exit(goterror);

	gen_outputs();

	exit(goterror);
}
Пример #12
0
/*
 * Read the configuration file (descriptor fd) and place all
 * services found there in the configuration.
 */
void parse_conf_file( int fd, struct configuration *confp, const char *filename)
{
    pset_h                   sconfs       = CNF_SERVICE_CONFS( confp ) ;
    struct service_config   *default_config   = CNF_DEFAULTS( confp ) ;
    boolean_e                found_defaults   = NO ;
    struct service_config    default_default_config ;
    const char              *func      = "parse_conf_file" ;
    int                      incfd;

    line_count = 0 ;
    current_file = filename;
    CLEAR( default_default_config ) ;

    for ( ;; )
    {
        entry_e   entry_type ;
        char      *service_name  = NULL;

        /*
         * if find_next_entry is successful, service_name
         * will point to malloc'ed memory
         */
        entry_type = find_next_entry( fd, &service_name ) ;
        switch ( entry_type )
        {
        case INCLUDE_ENTRY:
        {
            int saved_line_count = line_count;
            incfd = open(service_name, O_RDONLY);
            if( incfd < 0 ) {
                parsemsg( LOG_ERR, func,
                          "Unable to open included configuration file: %s",
                          service_name);
                break;
            }
            parsemsg( LOG_DEBUG,func,
                      "Reading included configuration file: %s",service_name);
            parse_conf_file(incfd, confp, service_name);
            /*
             * parse_conf_file eventually calls Srdline, try Sclosing it
             * to unmmap memory.
             */
            Sclose(incfd);
            /* Restore since we've returned from included file */
            current_file = filename;
            line_count = saved_line_count;
        }
        break;
        case INCLUDEDIR_ENTRY:
        {
            int saved_line_count = line_count;
            handle_includedir(service_name, confp);
            current_file = filename;
            line_count = saved_line_count;
        }
        break;
        case SERVICE_ENTRY:
            get_service_entry( fd, sconfs, service_name, default_config ) ;
            break ;
        case DEFAULTS_ENTRY:
            if ( found_defaults == YES )
            {
                parsemsg( LOG_ERR, func,
                          "only 1 defaults entry is allowed. This entry will be ignored" ) ;
                skip_entry( fd ) ;
            }
            else if ( parse_entry( DEFAULTS_ENTRY, fd,
                                   default_config ) == OK ) {
                found_defaults = YES ;
                /*
                 * We must check bind_address to see if it was deferred.
                 */
                if (SC_SPECIFIED( default_config, A_BIND) &&
                        SC_BIND_ADDR(default_config) == NULL)
                    M_CLEAR( default_config->sc_specified_attributes, A_BIND ) ;
            }
            break ;

        case BAD_ENTRY:
            skip_entry( fd ) ;
            break ;

        case NO_ENTRY:
            return ;
        }
        if (service_name)
            free(service_name);
    }
}
Пример #13
0
int 
main(int argc, char *argv[])
{
	char           *p;
	int             optc;
	extern int      optind;
	extern char    *optarg;

	verbose = 1;
	readcache = 1;
	*outmkname = *outcfname = *execfname = '\0';

	if (argc > 0)
		progname = argv[0];

	while ((optc = getopt(argc, argv, "m:c:e:fqD:EL:O:")) != -1) {
		switch (optc) {
		case 'f':
			readcache = 0;
			break;
		case 'q':
			verbose = 0;
			break;

		case 'm':
			if (strlcpy(outmkname, optarg, sizeof(outmkname)) >=
			    sizeof(outmkname))
				usage();
			break;
		case 'c':
			if (strlcpy(outcfname, optarg, sizeof(outcfname)) >=
			    sizeof(outcfname))
				usage();
			break;
		case 'e':
			if (strlcpy(execfname, optarg, sizeof(execfname)) >=
			    sizeof(execfname))
				usage();
			break;

		case 'D':
			if (strlcpy(topdir, optarg, sizeof(topdir)) >= sizeof(topdir))
				usage();
			break;
		case 'E':
			elf_names = 1;
			break;
		case 'L':
			if (strlen(optarg) >= MAXPATHLEN)
				usage();
			add_string(&libdirs, optarg);
			break;
		case 'O':
			if (strlcpy(objdir, optarg, sizeof(objdir)) >=
			    sizeof(objdir))
				usage();
			break;
		default:
			usage();
		}
	}

	argc -= optind;
	argv += optind;

	if (argc != 1)
		usage();

	if (libdirs == NULL)
		add_string(&libdirs, "/usr/lib");
	/*
         * generate filenames
         */

	if (strlcpy(infilename, argv[0], sizeof(infilename)) >=
	    sizeof(infilename))
		usage();

	/* confname = `basename infilename .conf` */

	if ((p = strrchr(infilename, '/')) != NULL)
		strlcpy(confname, p + 1, sizeof confname);
	else
		strlcpy(confname, infilename, sizeof confname);
	if ((p = strrchr(confname, '.')) != NULL && !strcmp(p, ".conf"))
		*p = '\0';

	if (!*outmkname)
		snprintf(outmkname, sizeof(outmkname), "%s.mk", confname);
	if (!*outcfname)
		snprintf(outcfname, sizeof(outcfname), "%s.c", confname);
	if (!*execfname)
		snprintf(execfname, sizeof(execfname), "%s", confname);
	snprintf(cachename, sizeof(cachename), "%s.cache", confname);

	parse_conf_file();
	gen_outputs();

	exit(goterror);
}
Пример #14
0
static int lp_config_init()
{
    /* default */
    lp_configs.log_level          = 3;
    lp_configs.max_threads        = 128;
    lp_configs.task_manager_num   = 1;
    lp_configs.ldap_num           = 4;
    lp_configs.mysql_num          = 8;
    lp_configs.thread_stack_size  = 2 * 1024;
    lp_configs.max_connections    = 2 * 1024;
    lp_configs.listening_ip       = NULL;
    lp_configs.listening_port     = 389;
    lp_configs.timeout            = 30;

    /* read configure file */
    struct conf_int_config log_conf[] = {
        {"log_level", &lp_configs.log_level},
        {0, 0}
    };

    struct conf_str_config server_str_conf[] = {
        {"listening", lp_configs.listening_ip},
        {0, 0}
    };
    
    struct conf_int_config  server_int_conf[] = {
        {"port", &lp_configs.listening_port},
        {"max_connections", &lp_configs.max_connections},
        {"timeout", &lp_configs.timeout},
        {0, 0}
    };

    int thread_stack_size = 0;
    struct conf_int_config thread_conf[] = {
        {"max_threads", &lp_configs.max_threads},
        {"thread_stack_size", &thread_stack_size},
        {"task_manager_num", &lp_configs.task_manager_num},
        {"ldap_num", &lp_configs.ldap_num},
        {"mysql_num", &lp_configs.mysql_num},
        {0, 0}
    };

    dictionary *conf = NULL;
    char *conf_file = (lp_config_file) ? lp_config_file : LP_CONF_FILE;
    conf = open_conf_file(conf_file);
    if (conf == NULL) {
        stk_log_error("read configure file failed! Use Default config!!");
        /* stack size in KBytes */
        lp_configs.thread_stack_size *= 1024;
        __show_all_config();
        /* DEBUG use LP_ERR, release use LP_OK */
        return LP_OK;
    }

    parse_conf_file(conf, "thread", thread_conf, NULL);
    /* stack size in KBytes */
    lp_configs.thread_stack_size = (thread_stack_size == 0 ?
            lp_configs.thread_stack_size : thread_stack_size ) * 1024;

    parse_conf_file(conf, "server", server_int_conf, server_str_conf);
    parse_conf_file(conf, "log", log_conf, NULL);

    __show_all_config();

    return LP_OK;
}
Пример #15
0
int
main (int argc, char **argv)
{
  int quit = 0;

#if defined(__GLIBC__)
  setup_signal_handlers ();
#endif

  /* command line/config options */
  verify_global_config (argc, argv);
  parse_conf_file (&argc, &argv);
  parse_cmd_line (argc, argv);

  /* initialize storage */
  init_storage ();
  /* setup to use the current locale */
  set_locale ();

#ifdef HAVE_LIBGEOIP
  init_geoip ();
#endif

  /* init logger */
  logger = init_log ();
  /* init parsing spinner */
  parsing_spinner = new_gspinner ();
  parsing_spinner->process = &logger->process;

  /* outputting to stdout */
  if (conf.output_html) {
    ui_spinner_create (parsing_spinner);
    goto out;
  }

  /* init curses */
  set_input_opts ();
  if (conf.no_color || has_colors () == FALSE) {
    conf.color_scheme = NO_COLOR;
    conf.no_color = 1;
  } else {
    start_color ();
  }
  init_colors ();
  init_windows (&header_win, &main_win);
  set_curses_spinner (parsing_spinner);

  /* configuration dialog */
  if (isatty (STDIN_FILENO) && (conf.log_format == NULL || conf.load_conf_dlg)) {
    refresh ();
    quit = verify_format (logger, parsing_spinner);
  }
  /* straight parsing */
  else {
    ui_spinner_create (parsing_spinner);
  }

out:

  /* main processing event */
  time (&start_proc);
  if (conf.load_from_disk)
    set_general_stats ();
  else if (!quit && parse_log (&logger, NULL, -1))
    FATAL ("Error while processing file");

  logger->offset = logger->process;

  /* no valid entries to process from the log */
  if ((logger->process == 0) || (logger->process == logger->invalid))
    FATAL ("Nothing valid to process.");

  /* init reverse lookup thread */
  gdns_init ();
  parse_initial_sort ();
  allocate_holder ();

  end_spinner ();
  time (&end_proc);

  /* stdout */
  if (conf.output_html) {
    /* CSV */
    if (conf.output_format && strcmp ("csv", conf.output_format) == 0)
      output_csv (logger, holder);
    /* JSON */
    else if (conf.output_format && strcmp ("json", conf.output_format) == 0)
      output_json (logger, holder);
    /* HTML */
    else
      output_html (logger, holder);
  }
  /* curses */
  else {
    allocate_data ();
    if (!conf.skip_term_resolver)
      gdns_thread_create ();

    render_screens ();
    get_keys ();

    attroff (COLOR_PAIR (COL_WHITE));
    /* restore tty modes and reset
     * terminal into non-visual mode */
    endwin ();
  }
  /* clean */
  house_keeping ();

  return EXIT_SUCCESS;
}
Пример #16
0
int acpid_main(int argc UNUSED_PARAM, char **argv)
{
	int nfd;
	int opts;
	struct pollfd *pfd;
	const char *opt_dir = "/etc/acpi";
	const char *opt_input = "/dev/input/event";
	const char *opt_logfile = "/var/log/acpid.log";
	const char *opt_action = "/etc/acpid.conf";
	const char *opt_map = "/etc/acpi.map";
#if ENABLE_FEATURE_PIDFILE
	const char *opt_pidfile = "/var/run/acpid.pid";
#endif

	INIT_G();

	opt_complementary = "df:e--e";
	opts = getopt32(argv, "c:de:fl:a:M:" IF_FEATURE_PIDFILE("p:") IF_FEATURE_ACPID_COMPAT("g:m:s:S:v"),
		&opt_dir, &opt_input, &opt_logfile, &opt_action, &opt_map
		IF_FEATURE_PIDFILE(, &opt_pidfile)
		IF_FEATURE_ACPID_COMPAT(, NULL, NULL, NULL, NULL)
	);

	if (!(opts & OPT_f)) {
		/* No -f "Foreground", we go to background */
		bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv);
	}

	if (!(opts & OPT_d)) {
		/* No -d "Debug", we log to log file.
		 * This includes any output from children.
		 */
		xmove_fd(xopen(opt_logfile, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO);
		xdup2(STDOUT_FILENO, STDERR_FILENO);
		/* Also, acpid's messages (but not children) will go to syslog too */
		openlog(applet_name, LOG_PID, LOG_DAEMON);
		logmode = LOGMODE_SYSLOG | LOGMODE_STDIO;
	}
	/* else: -d "Debug", log is not redirected */

	parse_conf_file(opt_action);
	parse_map_file(opt_map);

	xchdir(opt_dir);

	bb_signals((1 << SIGCHLD), SIG_IGN);
	bb_signals(BB_FATAL_SIGS, record_signo);

	pfd = NULL;
	nfd = 0;
	while (1) {
		int fd;
		char *dev_event;

		dev_event = xasprintf((opts & OPT_e) ? "%s" : "%s%u", opt_input, nfd);
		fd = open(dev_event, O_RDONLY | O_NONBLOCK);
		if (fd < 0) {
			if (nfd == 0)
				bb_simple_perror_msg_and_die(dev_event);
			break;
		}
		free(dev_event);
		pfd = xrealloc_vector(pfd, 1, nfd);
		pfd[nfd].fd = fd;
		pfd[nfd].events = POLLIN;
		nfd++;
	}

	write_pidfile(opt_pidfile);

	while (safe_poll(pfd, nfd, -1) > 0) {
		int i;
		for (i = 0; i < nfd; i++) {
			const char *event;

			if (!(pfd[i].revents & POLLIN)) {
				if (pfd[i].revents == 0)
					continue; /* this fd has nothing */

				/* Likely POLLERR, POLLHUP, POLLNVAL.
				 * Do not listen on this fd anymore.
				 */
				close(pfd[i].fd);
				nfd--;
				for (; i < nfd; i++)
					pfd[i].fd = pfd[i + 1].fd;
				break; /* do poll() again */
			}

			event = NULL;
			if (option_mask32 & OPT_e) {
				char *buf;
				int len;

				buf = xmalloc_reads(pfd[i].fd, NULL);
				/* buf = "button/power PWRB 00000080 00000000" */
				len = strlen(buf) - 9;
				if (len >= 0)
					buf[len] = '\0';
				event = find_action(NULL, buf);
				free(buf);
			} else {
				struct input_event ev;

				if (sizeof(ev) != full_read(pfd[i].fd, &ev, sizeof(ev)))
					continue;

				if (ev.value != 1 && ev.value != 0)
					continue;

				event = find_action(&ev, NULL);
			}
			if (!event)
				continue;
			// spawn event handler
			process_event(event);
		}
	}

	if (ENABLE_FEATURE_CLEAN_UP) {
		while (nfd--)
			close(pfd[nfd].fd);
		free(pfd);
	}
	remove_pidfile(opt_pidfile);

	return EXIT_SUCCESS;
}