Пример #1
0
config_t *cfg_open(const char *path)
{

	FILE *file = NULL;
	config_t *config = (config_t*)malloc(sizeof(config_t));

	if (config == NULL)
	{
		return NULL;
	}

	if (path == NULL || path[0] == 0)
	{
		config_init(config);
		return config;
	}

	file = fopen(path,"r");

	if (file == NULL)
	{
		config_init(config);
		return config;
	}

	// Not initializing produces a crash
	config_init(config);

	if (config_read(config,file) != CONFIG_TRUE)
	{
#ifdef DEBUG
		if (config_error_type(config) == CONFIG_ERR_FILE_IO)
		{
			printf("Error opening configuration file.\n");
		}
		else
		{
			printf("Error parsing configuration file.\n");
			printf("Line: %d\n", config_error_line(config));
			printf("Text: %s\n", config_error_text(config));
		}
#endif
		// Destroy the config and initialize a new one
		config_destroy(config);
		config_init(config);
	}

	fclose(file);

	config_set_tab_width(config,0);

	return config;

}
Пример #2
0
/**
 * Re-reads configuration from the given file
 */
int read_config() {
	config_t cfg;
	config_init(&cfg);

	if (config_read_file(&cfg, conf.config_file) == CONFIG_FALSE) {
		if (config_error_type(&cfg) == CONFIG_ERR_FILE_IO) {
			log_error("Configuration file not found: %s", conf.config_file);
			config_destroy(&cfg);
			return -1;
		}
		log_error("%s:%d - %s", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
		config_destroy(&cfg);
		return -1;
	}

	int intVal;
	const char* charVal;
	if (config_lookup_int(&cfg, "num_connections", &intVal) == CONFIG_TRUE) {
		conf.num_connections = intVal;
	}
	if (config_lookup_int(&cfg, "report_freq", &intVal) == CONFIG_TRUE) {
		conf.report_freq = intVal;
	}
	if (config_lookup_int(&cfg, "packet_size", &intVal) == CONFIG_TRUE) {
		if (intVal > MAXPACKET) {
			log_error("packet_size: %d exceeds maximal packet size (%d)", intVal, MAXPACKET);
			config_destroy(&cfg);
			return -1;
		}
		conf.packet_size = intVal;
	}
	if (config_lookup_int(&cfg, "packets_count", &intVal) == CONFIG_TRUE) {
		conf.packets_count = intVal;
	}
	if (config_lookup_string(&cfg, "reports_dir", &charVal) == CONFIG_TRUE) {
		free(conf.reports_dir);
		conf.reports_dir = strdup(charVal);
	}
	if (config_lookup_string(&cfg, "hosts_file", &charVal) == CONFIG_TRUE) {
		free(conf.hosts_file);
		conf.hosts_file = strdup(charVal);
	}
	if (config_lookup_string(&cfg, "log_file", &charVal) == CONFIG_TRUE) {
		free(conf.log_file);
		conf.log_file = strdup(charVal);
	}
	config_destroy(&cfg);

	if (read_hosts() == -1) {
		return -1;
	}

	return 0;
}
Пример #3
0
int parse_options(int argc, char **argv) {
  // there are potential memory leaks here -- it's called a second time, previously allocated strings will dangle.
  char *raw_service_name = NULL; /* Used to pick up the service name before possibly expanding it */
  char *stuffing = NULL; /* used for picking up the stuffing option */
  signed char c;      /* used for argument parsing */
  int i = 0;          /* used for tracking options */
  poptContext optCon; /* context for parsing command-line options */
  struct poptOption optionsTable[] = {
      {"verbose", 'v', POPT_ARG_NONE, NULL, 'v', NULL},
      {"disconnectFromOutput", 'D', POPT_ARG_NONE, NULL, 0, NULL},
      {"reconnectToOutput", 'R', POPT_ARG_NONE, NULL, 0, NULL},
      {"kill", 'k', POPT_ARG_NONE, NULL, 0, NULL},
      {"daemon", 'd', POPT_ARG_NONE, &config.daemonise, 0, NULL},
      {"configfile", 'c', POPT_ARG_STRING, &config.configfile, 0, NULL},
      {"statistics", 0, POPT_ARG_NONE, &config.statistics_requested, 0, NULL},
      {"version", 'V', POPT_ARG_NONE, NULL, 0, NULL},
      {"port", 'p', POPT_ARG_INT, &config.port, 0, NULL},
      {"name", 'a', POPT_ARG_STRING, &raw_service_name, 0, NULL},
      {"output", 'o', POPT_ARG_STRING, &config.output_name, 0, NULL},
      {"on-start", 'B', POPT_ARG_STRING, &config.cmd_start, 0, NULL},
      {"on-stop", 'E', POPT_ARG_STRING, &config.cmd_stop, 0, NULL},
      {"wait-cmd", 'w', POPT_ARG_NONE, &config.cmd_blocking, 0, NULL},
      {"mdns", 'm', POPT_ARG_STRING, &config.mdns_name, 0, NULL},
      {"latency", 'L', POPT_ARG_INT, &config.userSuppliedLatency, 0, NULL},
      {"AirPlayLatency", 'A', POPT_ARG_INT, &config.AirPlayLatency, 0, NULL},
      {"iTunesLatency", 'i', POPT_ARG_INT, &config.iTunesLatency, 0, NULL},
      {"forkedDaapdLatency", 0, POPT_ARG_INT, &config.ForkedDaapdLatency, 0, NULL},
      {"stuffing", 'S', POPT_ARG_STRING, &stuffing, 'S', NULL},
      {"resync", 'r', POPT_ARG_INT, &config.resyncthreshold, 0, NULL},
      {"timeout", 't', POPT_ARG_INT, &config.timeout, 't', NULL},
      {"password", 0, POPT_ARG_STRING, &config.password, 0, NULL},
      {"tolerance", 0, POPT_ARG_INT, &config.tolerance, 0, NULL},
#ifdef CONFIG_METADATA
      {"metadata-pipename", 'M', POPT_ARG_STRING, &config.metadata_pipename, 'M', NULL},
      {"get-coverart", 'g', POPT_ARG_NONE, &config.get_coverart, 'g', NULL},
#endif
      POPT_AUTOHELP
      {NULL, 0, 0, NULL, 0}};

// we have to parse the command line arguments to look for a config file
  int optind;
  optind = argc;
  int j;
  for (j = 0; j < argc; j++)
    if (strcmp(argv[j], "--") == 0)
      optind = j;

  optCon = poptGetContext(NULL, optind, (const char **)argv, optionsTable, 0);
  poptSetOtherOptionHelp(optCon, "[OPTIONS]* ");
  
   /* Now do options processing just to get a debug level */
  debuglev = 0;
  while ((c = poptGetNextOpt(optCon)) >= 0) {
    switch (c) {
    case 'v':
      debuglev++;
      break;
    }
  }
  if (c < -1) {
    die("%s: %s", poptBadOption(optCon, POPT_BADOPTION_NOALIAS), poptStrerror(c));
  }

  config_setting_t *setting;
  const char *str=0;
  int value=0;
  
  debug(1,"Looking for the configuration file \"%s\".",config.configfile);
  
  config_init(&config_file_stuff);
  
  char *config_file_real_path = realpath(config.configfile, NULL);
  if (config_file_real_path==NULL) {
    debug(2,"Can't resolve the configuration file \"%s\".",config.configfile);
  } else {
    debug(2, "Looking for configuration file at full path \"%s\"", config_file_real_path);
    /* Read the file. If there is an error, report it and exit. */
    if (config_read_file(&config_file_stuff, config_file_real_path)) {
      // make config.cfg point to it
      config.cfg = &config_file_stuff;
      /* Get the Service Name. */
      if (config_lookup_string(config.cfg, "general.name", &str)) {
        raw_service_name = (char *)str;
      }

      /* Get the Daemonize setting. */
      if (config_lookup_string(config.cfg, "general.daemonize", &str)) {
        if (strcasecmp(str, "no") == 0)
          config.daemonise = 0;
        else if (strcasecmp(str, "yes") == 0)
          config.daemonise = 1;
        else
          die("Invalid daemonize option choice \"%s\". It should be \"yes\" or \"no\"");
      }

      /* Get the mdns_backend setting. */
      if (config_lookup_string(config.cfg, "general.mdns_backend", &str))
        config.mdns_name = (char *)str;

      /* Get the output_backend setting. */
      if (config_lookup_string(config.cfg, "general.output_backend", &str))
        config.output_name = (char *)str;

      /* Get the port setting. */
      if (config_lookup_int(config.cfg, "general.port", &value)) {
        if ((value < 0) || (value > 65535))
          die("Invalid port number  \"%sd\". It should be between 0 and 65535, default is 5000",
              value);
        else
          config.port = value;
      }

      /* Get the udp port base setting. */
      if (config_lookup_int(config.cfg, "general.udp_port_base", &value)) {
        if ((value < 0) || (value > 65535))
          die("Invalid port number  \"%sd\". It should be between 0 and 65535, default is 6001",
              value);
        else
          config.udp_port_base = value;
      }

      /* Get the udp port range setting. This is number of ports that will be tried for free ports , starting at the port base. Only three ports are needed. */
      if (config_lookup_int(config.cfg, "general.udp_port_range", &value)) {
        if ((value < 0) || (value > 65535))
          die("Invalid port range  \"%sd\". It should be between 0 and 65535, default is 100",
              value);
        else
          config.udp_port_range = value;
      }

      /* Get the password setting. */
      if (config_lookup_string(config.cfg, "general.password", &str))
        config.password = (char *)str;

      if (config_lookup_string(config.cfg, "general.interpolation", &str)) {
        if (strcasecmp(str, "basic") == 0)
          config.packet_stuffing = ST_basic;
        else if (strcasecmp(str, "soxr") == 0)
          config.packet_stuffing = ST_soxr;
        else
          die("Invalid interpolation option choice \"%s\". It should be \"basic\" or \"soxr\"");
      }

      /* Get the statistics setting. */
      if (config_lookup_string(config.cfg, "general.statistics", &str)) {
        if (strcasecmp(str, "no") == 0)
          config.statistics_requested = 0;
        else if (strcasecmp(str, "yes") == 0)
          config.statistics_requested = 1;
        else
          die("Invalid statistics option choice \"%s\". It should be \"yes\" or \"no\"");
      }

      /* Get the drift tolerance setting. */
      if (config_lookup_int(config.cfg, "general.drift", &value))
        config.tolerance = value;

      /* Get the resync setting. */
      if (config_lookup_int(config.cfg, "general.resync_threshold", &value))
        config.resyncthreshold = value;

      /* Get the verbosity setting. */
      if (config_lookup_int(config.cfg, "general.log_verbosity", &value)) {
        if ((value >= 0) && (value <= 3))
          debuglev = value;
        else
          die("Invalid log verbosity setting option choice \"%d\". It should be between 0 and 3, "
              "inclusive.",
              value);
      }

      /* Get the ignore_volume_control setting. */
      if (config_lookup_string(config.cfg, "general.ignore_volume_control", &str)) {
        if (strcasecmp(str, "no") == 0)
          config.ignore_volume_control = 0;
        else if (strcasecmp(str, "yes") == 0)
          config.ignore_volume_control = 1;
        else
          die("Invalid ignore_volume_control option choice \"%s\". It should be \"yes\" or \"no\"");
      }

      /* Get the playback_mode setting */
       if (config_lookup_string(config.cfg, "general.playback_mode", &str)) {
        if (strcasecmp(str, "stereo") == 0)
          config.playback_mode = ST_stereo;
        else if (strcasecmp(str, "mono") == 0)
          config.playback_mode = ST_mono;
        else
          die("Invalid playback_mode choice \"%s\". It should be \"stereo\" (default) or \"mono\"");
      }

      /* Get the regtype -- the service type and protocol, separated by a dot. Default is "_raop._tcp" */
      if (config_lookup_string(config.cfg, "general.regtype", &str))
        config.regtype = strdup(str);
     

      /* Get the volume range, in dB, that should be used If not set, it means you just use the range set by the mixer. */
      if (config_lookup_int(config.cfg, "general.volume_range_db", &value)) {
        if ((value < 30) || (value > 150))
          die("Invalid volume range  \"%sd\". It should be between 30 and 150 dB. Zero means use the mixer's native range",
              value);
        else
          config.volume_range_db = value;
      }

/* Get the default latency. Deprecated! */
      if (config_lookup_int(config.cfg, "latencies.default", &value))
        config.userSuppliedLatency = value;

      /* Get the itunes latency. Deprecated! */
      if (config_lookup_int(config.cfg, "latencies.itunes", &value))
        config.iTunesLatency = value;

      /* Get the AirPlay latency. Deprecated! */
      if (config_lookup_int(config.cfg, "latencies.airplay", &value))
        config.AirPlayLatency = value;

      /* Get the forkedDaapd latency. Deprecated! */
      if (config_lookup_int(config.cfg, "latencies.forkedDaapd", &value))
        config.ForkedDaapdLatency = value;

  #ifdef CONFIG_METADATA
      /* Get the metadata setting. */
      if (config_lookup_string(config.cfg, "metadata.enabled", &str)) {
        if (strcasecmp(str, "no") == 0)
          config.metadata_enabled = 0;
        else if (strcasecmp(str, "yes") == 0)
          config.metadata_enabled = 1;
        else
          die("Invalid metadata enabled option choice \"%s\". It should be \"yes\" or \"no\"");
      }

      if (config_lookup_string(config.cfg, "metadata.include_cover_art", &str)) {
        if (strcasecmp(str, "no") == 0)
          config.get_coverart = 0;
        else if (strcasecmp(str, "yes") == 0)
          config.get_coverart = 1;
        else
          die("Invalid metadata include_cover_art option choice \"%s\". It should be \"yes\" or "
              "\"no\"");
      }

      if (config_lookup_string(config.cfg, "metadata.pipe_name", &str)) {
        config.metadata_pipename = (char *)str;
      }

      if (config_lookup_string(config.cfg, "metadata.socket_address", &str)) {
        config.metadata_sockaddr = (char *)str;
      }
      if (config_lookup_int(config.cfg, "metadata.socket_port", &value)) {
        config.metadata_sockport = value;
      }
      config.metadata_sockmsglength = 500;
      if (config_lookup_int(config.cfg, "metadata.socket_msglength", &value)) {
        config.metadata_sockmsglength = value < 500 ? 500 : value > 65000 ? 65000 : value;
      }
      if (config_lookup_int(config.cfg, "metadata.pipe_timeout", &value)) {
      
        if ((value < 1) || (value > 150000))
          die("Invalid timeout range  \"%sd\". It should be in the range 1 to 150,000 milliseconds.",
              value);
        else
          config.metadata_pipe_timeout = value;
      }

  #endif

      if (config_lookup_string(config.cfg, "sessioncontrol.run_this_before_play_begins", &str)) {
        config.cmd_start = (char *)str;
      }

      if (config_lookup_string(config.cfg, "sessioncontrol.run_this_after_play_ends", &str)) {
        config.cmd_stop = (char *)str;
      }

      if (config_lookup_string(config.cfg, "sessioncontrol.wait_for_completion", &str)) {
        if (strcasecmp(str, "no") == 0)
          config.cmd_blocking = 0;
        else if (strcasecmp(str, "yes") == 0)
          config.cmd_blocking = 1;
        else
          die("Invalid session control wait_for_completion option choice \"%s\". It should be "
              "\"yes\" or \"no\"");
      }

      if (config_lookup_string(config.cfg, "sessioncontrol.allow_session_interruption", &str)) {
        config.dont_check_timeout = 0; // this is for legacy -- only set by -t 0
        if (strcasecmp(str, "no") == 0)
          config.allow_session_interruption = 0;
        else if (strcasecmp(str, "yes") == 0)
          config.allow_session_interruption = 1;
        else
          die("Invalid session control allow_interruption option choice \"%s\". It should be \"yes\" "
              "or \"no\"");
      }

      if (config_lookup_int(config.cfg, "sessioncontrol.session_timeout", &value)) {
        config.timeout = value;
        config.dont_check_timeout = 0; // this is for legacy -- only set by -t 0
      }

    } else {
      if (config_error_type(&config_file_stuff) == CONFIG_ERR_FILE_IO)
        debug(1, "Error reading configuration file \"%s\": \"%s\".",
              config_error_file(&config_file_stuff), config_error_text(&config_file_stuff));
      else {
        die("Line %d of the configuration file \"%s\":\n%s", config_error_line(&config_file_stuff),
            config_error_file(&config_file_stuff), config_error_text(&config_file_stuff));
      }
    }
    free(config_file_real_path);
  }

// now, do the command line options again, but this time do them fully -- it's a unix convention that command line
// arguments have precedence over configuration file settings.

  optind = argc;
  for (j = 0; j < argc; j++)
    if (strcmp(argv[j], "--") == 0)
      optind = j;

  optCon = poptGetContext(NULL, optind, (const char **)argv, optionsTable, 0);
  poptSetOtherOptionHelp(optCon, "[OPTIONS]* ");

  /* Now do options processing, get portname */
  int tdebuglev = 0;
  while ((c = poptGetNextOpt(optCon)) >= 0) {
    switch (c) {
    case 'v':
      tdebuglev++;
      break;
    case 't':
      if (config.timeout == 0) {
        config.dont_check_timeout = 1;
        config.allow_session_interruption = 1;
      } else {
        config.dont_check_timeout = 0;
        config.allow_session_interruption = 0;
      }
      break;
#ifdef CONFIG_METADATA
    case 'M':
      config.metadata_enabled = 1;
      break;
    case 'g':
      if (config.metadata_enabled == 0)
        die("If you want to get cover art, you must also select the --metadata-pipename option.");
      break;
#endif
    case 'S':
      if (strcmp(stuffing, "basic") == 0)
        config.packet_stuffing = ST_basic;
      else if (strcmp(stuffing, "soxr") == 0)
#ifdef HAVE_LIBSOXR
        config.packet_stuffing = ST_soxr;
#else
        die("soxr option not available -- this version of shairport-sync was built without libsoxr "
            "support");
#endif
      else
        die("Illegal stuffing option \"%s\" -- must be \"basic\" or \"soxr\"", stuffing);
      break;
    }
  }
Пример #4
0
odesys_t *
odesys_parse_cfg_from_buffer_ctor (const char *buffer)
/* Parse the buffer and return an odesys_t object fully initialized
   and ready to use. */
{
  config_t cfg;
  odesys_t *odesys = NULL;
  molecule_t *molecule = NULL;
  laser_collection_t *lasers = NULL;

  /* Parse configurtion file into a libconfig config_t object. */
  config_init (&cfg);

  if (config_read_string (&cfg, buffer) == CONFIG_FALSE)
    {
      switch (config_error_type (&cfg))
	{
	case CONFIG_ERR_PARSE:
	  fprintf (stderr, "Error in configuration at line %d\n",
		   config_error_line (&cfg));
	  fprintf (stderr, "Error was: \"%s\"\n", config_error_text (&cfg));
	  return NULL;
	default:
	  fprintf (stderr, "Unknown error in parsing configuration.\n");
	  return NULL;
	}
    }

  /* Parse the config_t object. */
  molecule = molecule_cfg_parse_ctor (&cfg);
  if (molecule == NULL)
    {
      fprintf (stderr,
	       "Failed to parse molecule information from configuration file.\n");
      config_destroy (&cfg);
      return NULL;
    }

  lasers = laser_collection_cfg_parse_ctor (&cfg);
  if (lasers == NULL)
    {
      fprintf (stderr,
	       "Failed to parse laser information from configuration file.\n");
      molecule->dtor (molecule);
      config_destroy (&cfg);
      return NULL;
    }

  odesys = odesys_ctor (molecule, lasers);
  if (odesys == NULL)
    {
      fprintf (stderr, "Failed to initialize odesys.\n");
      molecule->dtor (molecule);
      laser_collection_dtor (lasers);
      config_destroy (&cfg);
      return NULL;
    }

  if (odesys_cfg_parse (odesys, &cfg) < 0)
    {
      fprintf (stderr, "%s %d: Failed to parse odesys information.\n",
	       __func__, __LINE__);
      odesys_dtor (odesys);
      config_destroy (&cfg);
      return NULL;
    }

  config_destroy (&cfg);

  return odesys;
}
Пример #5
0
// TODO: error handling
// TODO: better exit point handling
// (freeing resources for valgrind-cleanliness is too tedious at the moment)
void options_parse(int argc, char * argv[], struct Options * options) {
	int opt;
	// modified when config is loaded on the command line
	config_t config;
	config_init(&config);
	set_default_config(&config);

	// only to used for -g: print default config
	config_t config_default;
	config_init(&config_default);
	set_default_config(&config_default);

	// -i flag should only print options after all other
	// command line arguments have been applied
	bool print_options = false;

	while (-1 != (opt = getopt(argc, argv, OPTSTR))) {
		switch (opt) {
			case 'c':
				config_set_auto_convert(&config, CONFIG_TRUE);

				if (CONFIG_FALSE == config_read_file(&config, optarg)) {
					// failure reporting
					fprintf(stderr, "Failed to use config file '%s'!\n", optarg);
					switch (config_error_type(&config)) {
						case CONFIG_ERR_NONE:
							fprintf(stderr, "\tno error reported\n"
									"\t(This might be a libconfig problem.)\n");
							break;
						case CONFIG_ERR_FILE_IO:
							fprintf(stderr, "\tfile I/O error\n");
							break;
						case CONFIG_ERR_PARSE:
							fprintf(stderr, "\tparse error on line %d:\n"
									"\t%s\n",
									config_error_line(&config),
									config_error_text(&config));
							break;
						default:
							fprintf(stderr, "\tunknown error\n"
									"\t(A new libconfig version might have introduced"
									" new kinds of warnings.)\n");
					}
				}
				break;
			case 'g':
				config_write(&config_default, stdout);
				// be valgrind-clean
				config_destroy(&config_default);
				config_destroy(&config);
				exit(EXIT_SUCCESS);
				break;
			case 'i':
				print_options = true;
				break;
			default: /* '?' 'h' */
				options_help(*argv);
				// be valgrind-clean
				config_destroy(&config_default);
				config_destroy(&config);
				exit(EXIT_FAILURE);
		}
	}

	config2options(&config, options);
	// be valgrind-clean
	config_destroy(&config_default);
	config_destroy(&config);

	if (print_options)
		options_print(stderr, "", options);
}