]> git.meshlink.io Git - catta/blob - avahi-daemon/main.c
* rename the configuration variables register_xxx and announce_xxx to publish_xxx
[catta] / avahi-daemon / main.c
1 /* $Id$ */
2
3 /***
4   This file is part of avahi.
5  
6   avahi is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation; either version 2.1 of the
9   License, or (at your option) any later version.
10  
11   avahi is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14   Public License for more details.
15  
16   You should have received a copy of the GNU Lesser General Public
17   License along with avahi; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <getopt.h>
27 #include <string.h>
28 #include <signal.h>
29
30 #include <libdaemon/dfork.h>
31 #include <libdaemon/dsignal.h>
32 #include <libdaemon/dlog.h>
33 #include <libdaemon/dpid.h>
34
35 #include <avahi-core/core.h>
36 #include <avahi-core/log.h>
37
38 #include "main.h"
39 #include "simple-protocol.h"
40 #include "dbus-protocol.h"
41 #include "static-services.h"
42
43 AvahiServer *avahi_server = NULL;
44
45 typedef enum {
46     DAEMON_RUN,
47     DAEMON_KILL,
48     DAEMON_VERSION,
49     DAEMON_HELP
50 } DaemonCommand;
51
52 typedef struct {
53     AvahiServerConfig server_config;
54     DaemonCommand command;
55     gboolean daemonize;
56     gchar *config_file;
57     gboolean enable_dbus;
58 } DaemonConfig;
59
60 static void server_callback(AvahiServer *s, AvahiServerState state, gpointer userdata) {
61     g_assert(s);
62
63     if (state == AVAHI_SERVER_RUNNING) {
64         avahi_log_info("Server startup complete.  Host name is <%s>", avahi_server_get_host_name_fqdn(s));
65         static_service_add_to_server();
66     } else if (state == AVAHI_SERVER_COLLISION) {
67         gchar *n;
68
69         static_service_remove_from_server();
70         
71         n = avahi_alternative_host_name(avahi_server_get_host_name(s));
72         avahi_log_warn("Host name conflict, retrying with <%s>", n);
73         avahi_server_set_host_name(s, n);
74         g_free(n);
75     }
76 }
77
78 static void help(FILE *f, const gchar *argv0) {
79     fprintf(f,
80             "%s [options]\n"
81             "    -h --help        Show this help\n"
82             "    -D --daemonize   Daemonize after startup\n"
83             "    -k --kill        Kill a running daemon\n"
84             "    -V --version     Show version\n"
85             "    -f --file=FILE   Load the specified configuration file instead of the default\n",
86             argv0);
87 }
88
89 static gint parse_command_line(DaemonConfig *config, int argc, char *argv[]) {
90     gint c;
91     
92     static const struct option const long_options[] = {
93         { "help",      no_argument,       NULL, 'h' },
94         { "daemonize", no_argument,       NULL, 'D' },
95         { "kill",      no_argument,       NULL, 'k' },
96         { "version",   no_argument,       NULL, 'V' },
97         { "file",      required_argument, NULL, 'f' },
98     };
99
100     g_assert(config);
101
102     opterr = 0;
103     while ((c = getopt_long(argc, argv, "hDkVf:", long_options, NULL)) >= 0) {
104
105         switch(c) {
106             case 'h':
107                 config->command = DAEMON_HELP;
108                 break;
109             case 'D':
110                 config->daemonize = TRUE;
111                 break;
112             case 'k':
113                 config->command = DAEMON_KILL;
114                 break;
115             case 'V':
116                 config->command = DAEMON_VERSION;
117                 break;
118             case 'f':
119                 g_free(config->config_file);
120                 config->config_file = g_strdup(optarg);
121                 break;
122             default:
123                 fprintf(stderr, "Invalid command line argument: %c\n", c);
124                 return -1;
125         }
126     }
127
128     if (optind < argc) {
129         fprintf(stderr, "Too many arguments\n");
130         return -1;
131     }
132         
133     return 0;
134 }
135
136 static gboolean is_yes(const gchar *s) {
137     g_assert(s);
138     
139     return *s == 'y' || *s == 'Y';
140 }
141
142 static gint load_config_file(DaemonConfig *config) {
143     int r = -1;
144     GKeyFile *f = NULL;
145     GError *err = NULL;
146     gchar **groups = NULL, **g, **keys = NULL;
147
148     g_assert(config);
149     
150     f = g_key_file_new();
151     
152     if (!g_key_file_load_from_file(f, config->config_file ? config->config_file : AVAHI_CONFIG_FILE, G_KEY_FILE_NONE, &err)) {
153         fprintf(stderr, "Unable to read config file: %s\n", err->message);
154         goto finish;
155     }
156
157     groups = g_key_file_get_groups(f, NULL);
158
159     for (g = groups; *g; g++) {
160         if (g_strcasecmp(*g, "server") == 0) {
161             gchar **k;
162             
163             keys = g_key_file_get_keys(f, *g, NULL, NULL);
164
165             for (k = keys; *k; k++) {
166                 if (g_strcasecmp(*k, "host-name") == 0) {
167                     g_free(config->server_config.host_name);
168                     config->server_config.host_name = g_strdup(g_key_file_get_string(f, *g, *k, NULL));
169                 } else if (g_strcasecmp(*k, "domain-name") == 0) {
170                     g_free(config->server_config.domain_name);
171                     config->server_config.domain_name = g_strdup(g_key_file_get_string(f, *g, *k, NULL));
172                 } else if (g_strcasecmp(*k, "use-ipv4") == 0)
173                     config->server_config.use_ipv4 = is_yes(g_key_file_get_string(f, *g, *k, NULL));
174                 else if (g_strcasecmp(*k, "use-ipv6") == 0)
175                     config->server_config.use_ipv6 = is_yes(g_key_file_get_string(f, *g, *k, NULL));
176                 else if (g_strcasecmp(*k, "check-response-ttl") == 0)
177                     config->server_config.check_response_ttl = is_yes(g_key_file_get_string(f, *g, *k, NULL));
178                 else if (g_strcasecmp(*k, "use-iff-running") == 0)
179                     config->server_config.use_iff_running = is_yes(g_key_file_get_string(f, *g, *k, NULL));
180                 else if (g_strcasecmp(*k, "enable-dbus") == 0)
181                     config->enable_dbus = is_yes(g_key_file_get_string(f, *g, *k, NULL));
182                 else {
183                     fprintf(stderr, "Invalid configuration key \"%s\" in group \"%s\"\n", *k, *g);
184                     goto finish;
185                 }
186             }
187             
188         } else if (g_strcasecmp(*g, "publish") == 0) {
189             gchar **k;
190             
191             keys = g_key_file_get_keys(f, *g, NULL, NULL);
192
193             for (k = keys; *k; k++) {
194                 if (g_strcasecmp(*k, "publish-addresses") == 0)
195                     config->server_config.publish_addresses = is_yes(g_key_file_get_string(f, *g, *k, NULL));
196                 else if (g_strcasecmp(*k, "publish-hinfo") == 0)
197                     config->server_config.publish_hinfo = is_yes(g_key_file_get_string(f, *g, *k, NULL));
198                 else if (g_strcasecmp(*k, "publish-workstation") == 0)
199                     config->server_config.publish_workstation = is_yes(g_key_file_get_string(f, *g, *k, NULL));
200                 else if (g_strcasecmp(*k, "publish-domain") == 0)
201                     config->server_config.publish_domain = is_yes(g_key_file_get_string(f, *g, *k, NULL));
202                 else {
203                     fprintf(stderr, "Invalid configuration key \"%s\" in group \"%s\"\n", *k, *g);
204                     goto finish;
205                 }
206             }
207
208         } else if (g_strcasecmp(*g, "reflector") == 0) {
209             gchar **k;
210             
211             keys = g_key_file_get_keys(f, *g, NULL, NULL);
212
213             for (k = keys; *k; k++) {
214                 if (g_strcasecmp(*k, "enable-reflector") == 0)
215                     config->server_config.enable_reflector = is_yes(g_key_file_get_string(f, *g, *k, NULL));
216                 else if (g_strcasecmp(*k, "reflect-ipv") == 0)
217                     config->server_config.reflect_ipv = is_yes(g_key_file_get_string(f, *g, *k, NULL));
218                 else {
219                     fprintf(stderr, "Invalid configuration key \"%s\" in group \"%s\"\n", *k, *g);
220                     goto finish;
221                 }
222             }
223     
224         } else {
225             fprintf(stderr, "Invalid configuration file group \"%s\".\n", *g);
226             goto finish;
227         }
228     }
229
230     r = 0;
231
232 finish:
233
234     g_strfreev(groups);
235     g_strfreev(keys);
236
237     if (err)
238         g_error_free (err);
239
240     if (f)
241         g_key_file_free(f);
242     
243     return r;
244 }
245
246 static void log_function(AvahiLogLevel level, const gchar *txt) {
247
248     static const int const log_level_map[] = {
249         LOG_ERR,
250         LOG_WARNING,
251         LOG_NOTICE,
252         LOG_INFO,
253         LOG_DEBUG
254     };
255     
256     g_assert(level < AVAHI_LOG_LEVEL_MAX);
257     g_assert(txt);
258
259     daemon_log(log_level_map[level], "%s", txt);
260 }
261
262 static gint run_server(DaemonConfig *config) {
263     GMainLoop *loop = NULL;
264     gint r = -1;
265
266     g_assert(config);
267     
268     loop = g_main_loop_new(NULL, FALSE);
269     
270     if (simple_protocol_setup(NULL) < 0)
271         goto finish;
272     
273 #ifdef ENABLE_DBUS
274     if (config->enable_dbus)
275         if (dbus_protocol_setup(loop) < 0)
276             goto finish;
277 #endif
278     
279     if (!(avahi_server = avahi_server_new(NULL, &config->server_config, server_callback, NULL)))
280         goto finish;
281     
282     static_service_load();
283
284     if (config->daemonize) {
285         daemon_retval_send(0);
286         r = 0;
287     }
288     
289     g_main_loop_run(loop);
290
291
292 finish:
293     
294     static_service_remove_from_server();
295     static_service_free_all();
296     
297     simple_protocol_shutdown();
298
299 #ifdef ENABLE_DBUS
300     if (config->enable_dbus)
301         dbus_protocol_shutdown();
302 #endif
303
304     if (avahi_server)
305         avahi_server_free(avahi_server);
306     
307     if (loop)
308         g_main_loop_unref(loop);
309
310     if (r != 0 && config->daemonize)
311         daemon_retval_send(0);
312     
313     return r;
314 }
315
316 int main(int argc, char *argv[]) {
317     gint r = 255;
318     DaemonConfig config;
319     const gchar *argv0;
320     gboolean wrote_pid_file = FALSE;
321
322     avahi_set_log_function(log_function);
323     
324     avahi_server_config_init(&config.server_config);
325     config.command = DAEMON_RUN;
326     config.daemonize = FALSE;
327     config.config_file = NULL;
328     config.enable_dbus = TRUE;
329
330     if ((argv0 = strrchr(argv[0], '/')))
331         argv0++;
332     else
333         argv0 = argv[0];
334
335     daemon_pid_file_ident = daemon_log_ident = (char *) argv0;
336     
337     if (parse_command_line(&config, argc, argv) < 0)
338         goto finish;
339
340     if (load_config_file(&config) < 0)
341         goto finish;
342
343     if (config.command == DAEMON_HELP) {
344         help(stdout, argv0);
345         r = 0;
346     } else if (config.command == DAEMON_VERSION) {
347         printf("%s "PACKAGE_VERSION"\n", argv0);
348
349     } else if (config.command == DAEMON_KILL) {
350         if (daemon_pid_file_kill_wait(SIGTERM, 5) < 0) {
351             avahi_log_warn("Failed to kill daemon");
352             goto finish;
353         }
354
355         r = 0;
356         
357     } else if (config.command == DAEMON_RUN) {
358         pid_t pid;
359         
360         if ((pid = daemon_pid_file_is_running()) >= 0) {
361             avahi_log_error("Daemon already running on PID %u", pid);
362             goto finish;
363         }
364
365         if (config.daemonize) {
366
367             daemon_retval_init();
368             
369             if ((pid = daemon_fork()) < 0)
370                 goto finish;
371             else if (pid != 0) {
372                 int ret;
373                 /** Parent **/
374
375                 if ((ret = daemon_retval_wait(20)) < 0) {
376                     avahi_log_error("Could not recieve return value from daemon process.");
377                     goto finish;
378                 }
379
380                 r = ret;
381                 goto finish;
382             }
383
384             /* Child */
385         }
386
387         if (daemon_pid_file_create() < 0) {
388             avahi_log_error("Failed to create PID file.");
389             daemon_retval_send(1);
390             goto finish;
391         } else
392             wrote_pid_file = TRUE;
393
394         if (run_server(&config) == 0)
395             r = 0;
396     }
397         
398 finish:
399
400     if (config.daemonize)
401         daemon_retval_done();
402
403     avahi_server_config_free(&config.server_config);
404     g_free(config.config_file);
405
406     if (wrote_pid_file)
407         daemon_pid_file_remove();
408     
409     return r;
410 }