return;
for (j = s->monitor->interfaces; j; j = j->interface_next)
- if (j != i && (s->config.ipv_reflect || j->protocol == i->protocol))
+ if (j != i && (s->config.reflect_ipv || j->protocol == i->protocol))
avahi_interface_post_response(j, r, flush_cache, NULL, TRUE);
}
return;
for (j = s->monitor->interfaces; j; j = j->interface_next)
- if (j != i && (s->config.ipv_reflect || j->protocol == i->protocol)) {
+ if (j != i && (s->config.reflect_ipv || j->protocol == i->protocol)) {
/* Post the query to other networks */
avahi_interface_post_query(j, k, TRUE);
return;
for (j = s->monitor->interfaces; j; j = j->interface_next)
- if (j != i && (s->config.ipv_reflect || j->protocol == i->protocol))
+ if (j != i && (s->config.reflect_ipv || j->protocol == i->protocol))
avahi_interface_post_probe(j, r, TRUE);
}
for (j = s->monitor->interfaces; j; j = j->interface_next)
if (avahi_interface_relevant(j) &&
j != i &&
- (s->config.ipv_reflect || j->protocol == i->protocol)) {
+ (s->config.reflect_ipv || j->protocol == i->protocol)) {
if (j->protocol == AF_INET && s->fd_legacy_unicast_ipv4 >= 0) {
avahi_send_dns_packet_ipv4(s->fd_legacy_unicast_ipv4, j->hardware->index, p, NULL, 0);
g_assert(s);
- if (!s->config.register_hinfo || s->hinfo_entry_group)
+ if (!s->config.publish_hinfo || s->hinfo_entry_group)
return;
s->hinfo_entry_group = avahi_entry_group_new(s, avahi_host_rr_entry_group_callback, NULL);
static void register_browse_domain(AvahiServer *s) {
g_assert(s);
- if (!s->config.announce_domain || s->browse_domain_entry_group)
+ if (!s->config.publish_domain || s->browse_domain_entry_group)
return;
s->browse_domain_entry_group = avahi_entry_group_new(s, NULL, NULL);
g_assert(c);
memset(c, 0, sizeof(AvahiServerConfig));
- c->register_hinfo = TRUE;
- c->register_addresses = TRUE;
c->use_ipv6 = TRUE;
c->use_ipv4 = TRUE;
c->host_name = NULL;
c->domain_name = NULL;
c->check_response_ttl = TRUE;
- c->announce_domain = TRUE;
+ c->publish_hinfo = TRUE;
+ c->publish_addresses = TRUE;
+ c->publish_workstation = TRUE;
+ c->publish_domain = TRUE;
c->use_iff_running = FALSE;
c->enable_reflector = FALSE;
- c->ipv_reflect = FALSE;
- c->register_workstation = TRUE;
+ c->reflect_ipv = FALSE;
return c;
}
#include <config.h>
#endif
+#include <getopt.h>
+#include <string.h>
+#include <signal.h>
+
+#include <libdaemon/dfork.h>
+#include <libdaemon/dsignal.h>
+#include <libdaemon/dlog.h>
+#include <libdaemon/dpid.h>
+
#include <avahi-core/core.h>
+#include <avahi-core/log.h>
#include "main.h"
#include "simple-protocol.h"
+#include "dbus-protocol.h"
#include "static-services.h"
AvahiServer *avahi_server = NULL;
+typedef enum {
+ DAEMON_RUN,
+ DAEMON_KILL,
+ DAEMON_VERSION,
+ DAEMON_HELP
+} DaemonCommand;
+
+typedef struct {
+ AvahiServerConfig server_config;
+ DaemonCommand command;
+ gboolean daemonize;
+ gchar *config_file;
+ gboolean enable_dbus;
+} DaemonConfig;
+
static void server_callback(AvahiServer *s, AvahiServerState state, gpointer userdata) {
g_assert(s);
if (state == AVAHI_SERVER_RUNNING) {
- g_message("Server startup complete. Host name is <%s>", avahi_server_get_host_name_fqdn(s));
+ avahi_log_info("Server startup complete. Host name is <%s>", avahi_server_get_host_name_fqdn(s));
static_service_add_to_server();
} else if (state == AVAHI_SERVER_COLLISION) {
gchar *n;
static_service_remove_from_server();
n = avahi_alternative_host_name(avahi_server_get_host_name(s));
- g_message("Host name conflict, retrying with <%s>", n);
+ avahi_log_warn("Host name conflict, retrying with <%s>", n);
avahi_server_set_host_name(s, n);
g_free(n);
}
static void help(FILE *f, const gchar *argv0) {
fprintf(f,
"%s [options]\n"
- " -h --help Show this help\n"
- " -D --daemon Daemonize after startup\n"
- " -k --kill Kill a running daemon\n"
- " -v --version Show version\n",
+ " -h --help Show this help\n"
+ " -D --daemonize Daemonize after startup\n"
+ " -k --kill Kill a running daemon\n"
+ " -V --version Show version\n"
+ " -f --file=FILE Load the specified configuration file instead of the default\n",
argv0);
}
-static gint parse_command_line(AvahiServerConfig *config, int argc, char *argv[]) {
+static gint parse_command_line(DaemonConfig *config, int argc, char *argv[]) {
+ gint c;
+
+ 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' },
+ };
- return 0;
-}
+ g_assert(config);
-static gint load_config_file(AvahiServerConfig *config) {
+ opterr = 0;
+ while ((c = getopt_long(argc, argv, "hDkVf:", long_options, NULL)) >= 0) {
+ switch(c) {
+ case 'h':
+ config->command = DAEMON_HELP;
+ break;
+ case 'D':
+ config->daemonize = TRUE;
+ break;
+ case 'k':
+ config->command = DAEMON_KILL;
+ break;
+ case 'V':
+ config->command = DAEMON_VERSION;
+ break;
+ case 'f':
+ g_free(config->config_file);
+ config->config_file = g_strdup(optarg);
+ break;
+ default:
+ fprintf(stderr, "Invalid command line argument: %c\n", c);
+ return -1;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr, "Too many arguments\n");
+ return -1;
+ }
+
return 0;
}
-int main(int argc, char *argv[]) {
- GMainLoop *loop = NULL;
- gint r = 255;
- AvahiServerConfig config;
+static gboolean is_yes(const gchar *s) {
+ g_assert(s);
+
+ return *s == 'y' || *s == 'Y';
+}
- avahi_server_config_init(&config);
+static gint load_config_file(DaemonConfig *config) {
+ int r = -1;
+ GKeyFile *f = NULL;
+ GError *err = NULL;
+ gchar **groups = NULL, **g, **keys = NULL;
- if (load_config_file(&config) < 0)
+ g_assert(config);
+
+ f = g_key_file_new();
+
+ if (!g_key_file_load_from_file(f, config->config_file ? config->config_file : AVAHI_CONFIG_FILE, G_KEY_FILE_NONE, &err)) {
+ fprintf(stderr, "Unable to read config file: %s\n", err->message);
goto finish;
+ }
- if (parse_command_line(&config, argc, argv) < 0)
- 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++) {
+ if (g_strcasecmp(*k, "host-name") == 0) {
+ g_free(config->server_config.host_name);
+ config->server_config.host_name = g_strdup(g_key_file_get_string(f, *g, *k, NULL));
+ } else if (g_strcasecmp(*k, "domain-name") == 0) {
+ g_free(config->server_config.domain_name);
+ config->server_config.domain_name = g_strdup(g_key_file_get_string(f, *g, *k, NULL));
+ } else if (g_strcasecmp(*k, "use-ipv4") == 0)
+ config->server_config.use_ipv4 = is_yes(g_key_file_get_string(f, *g, *k, NULL));
+ else if (g_strcasecmp(*k, "use-ipv6") == 0)
+ config->server_config.use_ipv6 = is_yes(g_key_file_get_string(f, *g, *k, NULL));
+ else if (g_strcasecmp(*k, "check-response-ttl") == 0)
+ config->server_config.check_response_ttl = is_yes(g_key_file_get_string(f, *g, *k, NULL));
+ else if (g_strcasecmp(*k, "use-iff-running") == 0)
+ config->server_config.use_iff_running = is_yes(g_key_file_get_string(f, *g, *k, NULL));
+ else if (g_strcasecmp(*k, "enable-dbus") == 0)
+ config->enable_dbus = is_yes(g_key_file_get_string(f, *g, *k, NULL));
+ else {
+ fprintf(stderr, "Invalid configuration key \"%s\" in group \"%s\"\n", *k, *g);
+ goto finish;
+ }
+ }
+
+ } else if (g_strcasecmp(*g, "publish") == 0) {
+ gchar **k;
+
+ keys = g_key_file_get_keys(f, *g, NULL, NULL);
+
+ for (k = keys; *k; k++) {
+ if (g_strcasecmp(*k, "publish-addresses") == 0)
+ config->server_config.publish_addresses = is_yes(g_key_file_get_string(f, *g, *k, NULL));
+ else if (g_strcasecmp(*k, "publish-hinfo") == 0)
+ config->server_config.publish_hinfo = is_yes(g_key_file_get_string(f, *g, *k, NULL));
+ else if (g_strcasecmp(*k, "publish-workstation") == 0)
+ config->server_config.publish_workstation = is_yes(g_key_file_get_string(f, *g, *k, NULL));
+ else if (g_strcasecmp(*k, "publish-domain") == 0)
+ config->server_config.publish_domain = is_yes(g_key_file_get_string(f, *g, *k, NULL));
+ else {
+ fprintf(stderr, "Invalid configuration key \"%s\" in group \"%s\"\n", *k, *g);
+ goto finish;
+ }
+ }
+
+ } else if (g_strcasecmp(*g, "reflector") == 0) {
+ gchar **k;
+
+ keys = g_key_file_get_keys(f, *g, NULL, NULL);
+
+ for (k = keys; *k; k++) {
+ if (g_strcasecmp(*k, "enable-reflector") == 0)
+ config->server_config.enable_reflector = is_yes(g_key_file_get_string(f, *g, *k, NULL));
+ else if (g_strcasecmp(*k, "reflect-ipv") == 0)
+ config->server_config.reflect_ipv = is_yes(g_key_file_get_string(f, *g, *k, NULL));
+ else {
+ fprintf(stderr, "Invalid configuration key \"%s\" in group \"%s\"\n", *k, *g);
+ goto finish;
+ }
+ }
- loop = g_main_loop_new(NULL, FALSE);
+ } else {
+ fprintf(stderr, "Invalid configuration file group \"%s\".\n", *g);
+ goto finish;
+ }
+ }
+
+ r = 0;
+
+finish:
+
+ g_strfreev(groups);
+ g_strfreev(keys);
+
+ 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 gint run_server(DaemonConfig *config) {
+ GMainLoop *loop = NULL;
+ gint r = -1;
+
+ g_assert(config);
+
+ loop = g_main_loop_new(NULL, FALSE);
+
if (simple_protocol_setup(NULL) < 0)
goto finish;
-
+
#ifdef ENABLE_DBUS
- if (dbus_protocol_setup (loop) < 0)
- goto finish;
+ if (config->enable_dbus)
+ if (dbus_protocol_setup(loop) < 0)
+ goto finish;
#endif
-
- if (!(avahi_server = avahi_server_new(NULL, &config, server_callback, NULL)))
+
+ if (!(avahi_server = avahi_server_new(NULL, &config->server_config, server_callback, NULL)))
goto finish;
-
+
static_service_load();
+ if (config->daemonize) {
+ daemon_retval_send(0);
+ r = 0;
+ }
+
g_main_loop_run(loop);
- r = 0;
-
-finish:
+finish:
+
static_service_remove_from_server();
static_service_free_all();
simple_protocol_shutdown();
#ifdef ENABLE_DBUS
- dbus_protocol_shutdown();
+ if (config->enable_dbus)
+ dbus_protocol_shutdown();
#endif
if (avahi_server)
if (loop)
g_main_loop_unref(loop);
- avahi_server_config_free(&config);
+ if (r != 0 && config->daemonize)
+ daemon_retval_send(0);
+
+ return r;
+}
+
+int main(int argc, char *argv[]) {
+ gint r = 255;
+ DaemonConfig config;
+ const gchar *argv0;
+ gboolean wrote_pid_file = FALSE;
+
+ avahi_set_log_function(log_function);
+
+ avahi_server_config_init(&config.server_config);
+ config.command = DAEMON_RUN;
+ config.daemonize = FALSE;
+ config.config_file = NULL;
+ config.enable_dbus = TRUE;
+
+ if ((argv0 = strrchr(argv[0], '/')))
+ argv0++;
+ else
+ argv0 = argv[0];
+ daemon_pid_file_ident = daemon_log_ident = (char *) argv0;
+
+ if (parse_command_line(&config, argc, argv) < 0)
+ goto finish;
+
+ if (load_config_file(&config) < 0)
+ goto finish;
+
+ if (config.command == DAEMON_HELP) {
+ help(stdout, argv0);
+ r = 0;
+ } else if (config.command == DAEMON_VERSION) {
+ printf("%s "PACKAGE_VERSION"\n", argv0);
+
+ } else if (config.command == DAEMON_KILL) {
+ if (daemon_pid_file_kill_wait(SIGTERM, 5) < 0) {
+ avahi_log_warn("Failed to kill daemon");
+ goto finish;
+ }
+
+ r = 0;
+
+ } else if (config.command == DAEMON_RUN) {
+ pid_t pid;
+
+ if ((pid = daemon_pid_file_is_running()) >= 0) {
+ avahi_log_error("Daemon already running on PID %u", pid);
+ goto finish;
+ }
+
+ if (config.daemonize) {
+
+ daemon_retval_init();
+
+ if ((pid = daemon_fork()) < 0)
+ goto finish;
+ else if (pid != 0) {
+ int ret;
+ /** Parent **/
+
+ if ((ret = daemon_retval_wait(20)) < 0) {
+ avahi_log_error("Could not recieve return value from daemon process.");
+ goto finish;
+ }
+
+ r = ret;
+ goto finish;
+ }
+
+ /* Child */
+ }
+
+ if (daemon_pid_file_create() < 0) {
+ avahi_log_error("Failed to create PID file.");
+ daemon_retval_send(1);
+ goto finish;
+ } else
+ wrote_pid_file = TRUE;
+
+ if (run_server(&config) == 0)
+ r = 0;
+ }
+
+finish:
+
+ if (config.daemonize)
+ daemon_retval_done();
+
+ avahi_server_config_free(&config.server_config);
+ g_free(config.config_file);
+
+ if (wrote_pid_file)
+ daemon_pid_file_remove();
+
return r;
}