+static void help(FILE *f, const gchar *argv0) {
+ fprintf(f,
+ "%s [options]\n"
+ " -h --help Show this help\n"
+ " -D --daemonize Daemonize after startup\n"
+ " -k --kill Kill a running daemon\n"
+ " -r --reload Request a running daemon to reload static services\n"
+ " -c --check Return 0 if a daemon is already running\n"
+ " -V --version Show version\n"
+ " -f --file=FILE Load the specified configuration file instead of\n"
+ " "AVAHI_CONFIG_FILE"\n",
+ argv0);
+}
+
+static gint parse_command_line(DaemonConfig *c, int argc, char *argv[]) {
+ gint o;
+
+ static const struct option const long_options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "daemonize", no_argument, NULL, 'D' },
+ { "kill", no_argument, NULL, 'k' },
+ { "version", no_argument, NULL, 'V' },
+ { "file", required_argument, NULL, 'f' },
+ { "reload", no_argument, NULL, 'r' },
+ { "check", no_argument, NULL, 'c' },
+ };
+
+ g_assert(c);
+
+ opterr = 0;
+ while ((o = getopt_long(argc, argv, "hDkVf:rc", long_options, NULL)) >= 0) {
+
+ switch(o) {
+ case 'h':
+ c->command = DAEMON_HELP;
+ break;
+ case 'D':
+ c->daemonize = TRUE;
+ break;
+ case 'k':
+ c->command = DAEMON_KILL;
+ break;
+ case 'V':
+ c->command = DAEMON_VERSION;
+ break;
+ case 'f':
+ g_free(c->config_file);
+ c->config_file = g_strdup(optarg);
+ break;
+ case 'r':
+ c->command = DAEMON_RELOAD;
+ break;
+ case 'c':
+ c->command = DAEMON_CHECK;
+ break;
+ default:
+ fprintf(stderr, "Invalid command line argument: %c\n", o);
+ return -1;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr, "Too many arguments\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static gboolean is_yes(const gchar *s) {
+ g_assert(s);
+
+ return *s == 'y' || *s == 'Y';
+}
+
+static gint load_config_file(DaemonConfig *c) {
+ int r = -1;
+ GKeyFile *f = NULL;
+ GError *err = NULL;
+ gchar **groups = NULL, **g, **keys = NULL, *v = NULL;
+
+ g_assert(c);
+
+ f = g_key_file_new();
+ g_key_file_set_list_separator(f, ',');
+
+ if (!g_key_file_load_from_file(f, c->config_file ? c->config_file : AVAHI_CONFIG_FILE, G_KEY_FILE_NONE, &err)) {
+ fprintf(stderr, "Unable to read config file: %s\n", err->message);
+ goto finish;
+ }
+
+ groups = g_key_file_get_groups(f, NULL);
+
+ for (g = groups; *g; g++) {
+ if (g_strcasecmp(*g, "server") == 0) {
+ gchar **k;
+
+ keys = g_key_file_get_keys(f, *g, NULL, NULL);
+
+ for (k = keys; *k; k++) {
+
+ v = g_key_file_get_value(f, *g, *k, NULL);
+
+ if (g_strcasecmp(*k, "host-name") == 0) {
+ g_free(c->server_config.host_name);
+ c->server_config.host_name = v;
+ v = NULL;
+ } else if (g_strcasecmp(*k, "domain-name") == 0) {
+ g_free(c->server_config.domain_name);
+ c->server_config.domain_name = v;
+ v = NULL;
+ } else if (g_strcasecmp(*k, "use-ipv4") == 0)
+ c->server_config.use_ipv4 = is_yes(v);
+ else if (g_strcasecmp(*k, "use-ipv6") == 0)
+ c->server_config.use_ipv6 = is_yes(v);
+ else if (g_strcasecmp(*k, "check-response-ttl") == 0)
+ c->server_config.check_response_ttl = is_yes(v);
+ else if (g_strcasecmp(*k, "use-iff-running") == 0)
+ c->server_config.use_iff_running = is_yes(v);
+ else if (g_strcasecmp(*k, "enable-dbus") == 0)
+ c->enable_dbus = is_yes(v);
+ else if (g_strcasecmp(*k, "drop-root") == 0)
+ c->drop_root = is_yes(v);
+ else {
+ fprintf(stderr, "Invalid configuration key \"%s\" in group \"%s\"\n", *k, *g);
+ goto finish;
+ }
+
+ g_free(v);
+ v = NULL;
+ }
+
+ g_strfreev(keys);
+ keys = NULL;
+
+ } else if (g_strcasecmp(*g, "publish") == 0) {
+ gchar **k;
+
+ keys = g_key_file_get_keys(f, *g, NULL, NULL);
+
+ for (k = keys; *k; k++) {
+
+ v = g_key_file_get_string(f, *g, *k, NULL);
+
+ if (g_strcasecmp(*k, "publish-addresses") == 0)
+ c->server_config.publish_addresses = is_yes(v);
+ else if (g_strcasecmp(*k, "publish-hinfo") == 0)
+ c->server_config.publish_hinfo = is_yes(v);
+ else if (g_strcasecmp(*k, "publish-workstation") == 0)
+ c->server_config.publish_workstation = is_yes(v);
+ else if (g_strcasecmp(*k, "publish-domain") == 0)
+ c->server_config.publish_domain = is_yes(v);
+ else if (g_strcasecmp(*k, "publish-resolv-conf-dns-servers") == 0)
+ c->publish_resolv_conf = is_yes(v);
+ else if (g_strcasecmp(*k, "publish-dns-servers") == 0) {
+ g_strfreev(c->publish_dns_servers);
+ c->publish_dns_servers = g_key_file_get_string_list(f, *g, *k, NULL, NULL);
+ } else {
+ fprintf(stderr, "Invalid configuration key \"%s\" in group \"%s\"\n", *k, *g);
+ goto finish;
+ }
+
+ g_free(v);
+ v = NULL;
+ }
+
+ g_strfreev(keys);
+ keys = NULL;
+
+ } else if (g_strcasecmp(*g, "reflector") == 0) {
+ gchar **k;
+
+ keys = g_key_file_get_keys(f, *g, NULL, NULL);
+
+ for (k = keys; *k; k++) {
+
+ v = g_key_file_get_string(f, *g, *k, NULL);
+
+ if (g_strcasecmp(*k, "enable-reflector") == 0)
+ c->server_config.enable_reflector = is_yes(v);
+ else if (g_strcasecmp(*k, "reflect-ipv") == 0)
+ c->server_config.reflect_ipv = is_yes(v);
+ else {
+ fprintf(stderr, "Invalid configuration key \"%s\" in group \"%s\"\n", *k, *g);
+ goto finish;
+ }
+
+ g_free(v);
+ v = NULL;
+ }
+
+ g_strfreev(keys);
+ keys = NULL;
+
+ } else {
+ fprintf(stderr, "Invalid configuration file group \"%s\".\n", *g);
+ goto finish;
+ }
+ }
+
+ r = 0;
+
+finish:
+
+ g_strfreev(groups);
+ g_strfreev(keys);
+ g_free(v);
+
+ if (err)
+ g_error_free (err);
+
+ if (f)
+ g_key_file_free(f);
+
+ return r;
+}
+
+static void log_function(AvahiLogLevel level, const gchar *txt) {
+
+ static const int const log_level_map[] = {
+ LOG_ERR,
+ LOG_WARNING,
+ LOG_NOTICE,
+ LOG_INFO,
+ LOG_DEBUG
+ };
+
+ g_assert(level < AVAHI_LOG_LEVEL_MAX);
+ g_assert(txt);
+
+ daemon_log(log_level_map[level], "%s", txt);
+}
+
+static void dump(const gchar *text, gpointer userdata) {
+ avahi_log_info("%s", text);
+}
+
+static gboolean signal_callback(GIOChannel *source, GIOCondition condition, gpointer data) {
+ gint sig;
+ GMainLoop *loop = data;
+
+ g_assert(source);
+ g_assert(loop);
+
+ if ((sig = daemon_signal_next()) <= 0) {
+ avahi_log_error("daemon_signal_next() failed");
+ return FALSE;
+ }