]> git.meshlink.io Git - catta/blob - avahi-utils/avahi-browse.c
fix avahi-browse --help
[catta] / avahi-utils / avahi-browse.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 <stdlib.h>
27 #include <stdio.h>
28 #include <getopt.h>
29 #include <assert.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <net/if.h>
34 #include <locale.h>
35
36 #include <avahi-common/simple-watch.h>
37 #include <avahi-common/error.h>
38 #include <avahi-common/malloc.h>
39 #include <avahi-common/domain.h>
40 #include <avahi-common/llist.h>
41 #include <avahi-client/client.h>
42 #include <avahi-client/lookup.h>
43
44 #include "sigint.h"
45
46 #if defined(HAVE_GDBM) || defined(HAVE_DBM)
47 #include "stdb.h"
48 #endif
49
50 typedef enum {
51     COMMAND_HELP,
52     COMMAND_VERSION,
53     COMMAND_BROWSE_SERVICES,
54     COMMAND_BROWSE_ALL_SERVICES,
55     COMMAND_BROWSE_DOMAINS
56 #if defined(HAVE_GDBM) || defined(HAVE_DBM)
57     , COMMAND_DUMP_STDB
58 #endif
59 } Command;
60
61 typedef struct Config {
62     int verbose;
63     int terminate_on_all_for_now;
64     int terminate_on_cache_exhausted;
65     char *domain;
66     char *stype;
67     int ignore_local;
68     Command command;
69     int resolve;
70     int no_fail;
71 #if defined(HAVE_GDBM) || defined(HAVE_DBM)
72     int no_db_lookup;
73 #endif
74 } Config;
75
76 typedef struct ServiceInfo ServiceInfo;
77
78 struct ServiceInfo {
79     AvahiIfIndex interface;
80     AvahiProtocol protocol;
81     char *name, *type, *domain;
82
83     AvahiServiceResolver *resolver;
84     Config *config;
85
86     AVAHI_LLIST_FIELDS(ServiceInfo, info);
87 };
88
89 static AvahiSimplePoll *simple_poll = NULL;
90 static AvahiClient *client = NULL;
91 static int n_all_for_now = 0, n_cache_exhausted = 0, n_resolving = 0;
92 static AvahiStringList *browsed_types = NULL;
93 static ServiceInfo *services = NULL;
94 static int n_columns = 80;
95 static int browsing = 0;
96
97 static void check_terminate(Config *c) {
98
99     assert(n_all_for_now >= 0);
100     assert(n_cache_exhausted >= 0);
101     assert(n_resolving >= 0);
102     
103     if (n_all_for_now <= 0 && n_resolving <= 0) {
104
105         if (c->verbose) {
106             printf(": All for now\n");
107             n_all_for_now++; /* Make sure that this event is not repeated */
108         }
109         
110         if (c->terminate_on_all_for_now)
111             avahi_simple_poll_quit(simple_poll);
112     }
113     
114     if (n_cache_exhausted <= 0 && n_resolving <= 0) {
115
116         if (c->verbose) {
117             printf(": Cache exhausted\n");
118             n_cache_exhausted++; /* Make sure that this event is not repeated */
119         }
120         
121         if (c->terminate_on_cache_exhausted)
122             avahi_simple_poll_quit(simple_poll);
123     }
124 }
125
126 static ServiceInfo *find_service(AvahiIfIndex interface, AvahiProtocol protocol, const char *name, const char *type, const char *domain) {
127     ServiceInfo *i;
128
129     for (i = services; i; i = i->info_next)
130         if (i->interface == interface &&
131             i->protocol == protocol &&
132             strcasecmp(i->name, name) == 0 &&
133             avahi_domain_equal(i->type, type) &&
134             avahi_domain_equal(i->domain, domain))
135
136             return i;
137
138     return NULL;
139 }
140
141 static void print_service_line(Config *config, char c, AvahiIfIndex interface, AvahiProtocol protocol, const char *name, const char *type, const char *domain) {
142     char ifname[IF_NAMESIZE];
143
144 #if defined(HAVE_GDBM) || defined(HAVE_DBM)
145     if (!config->no_db_lookup)
146         type = stdb_lookup(type);
147 #endif
148     
149     printf("%c %4s %4s %-*s %-20s %s\n",
150            c,
151            interface != AVAHI_IF_UNSPEC ? if_indextoname(interface, ifname) : "n/a",
152            protocol != AVAHI_PROTO_UNSPEC ? avahi_proto_to_string(protocol) : "n/a", 
153            n_columns-35, name, type, domain);
154     fflush(stdout);
155 }
156
157 static void service_resolver_callback(
158     AvahiServiceResolver *r,
159     AvahiIfIndex interface,
160     AvahiProtocol protocol,
161     AvahiResolverEvent event,
162     const char *name,
163     const char *type,
164     const char *domain,
165     const char *host_name,
166     const AvahiAddress *a,
167     uint16_t port,
168     AvahiStringList *txt,
169     AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
170     void *userdata) {
171     
172     ServiceInfo *i = userdata;
173     
174     assert(r);
175     assert(i);
176
177     switch (event) {
178         case AVAHI_RESOLVER_FOUND: {
179             char address[AVAHI_ADDRESS_STR_MAX], *t;
180
181             avahi_address_snprint(address, sizeof(address), a);
182
183             t = avahi_string_list_to_string(txt);
184
185             print_service_line(i->config, '=', interface, protocol, name, type, domain);
186             
187             printf("   hostname = [%s]\n"
188                    "   address = [%s]\n"
189                    "   port = [%i]\n"
190                    "   txt = [%s]\n",
191                    host_name,
192                    address,
193                    port,
194                    t);
195             avahi_free(t);
196
197             break;
198         }
199
200         case AVAHI_RESOLVER_FAILURE:
201             
202             fprintf(stderr, "Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_client_errno(client)));
203             break;
204     }
205
206     
207     avahi_service_resolver_free(i->resolver);
208     i->resolver = NULL;
209
210     assert(n_resolving > 0);
211     n_resolving--;
212     check_terminate(i->config);
213     fflush(stdout);
214 }
215
216 static ServiceInfo *add_service(Config *c, AvahiIfIndex interface, AvahiProtocol protocol, const char *name, const char *type, const char *domain) {
217     ServiceInfo *i;
218
219     i = avahi_new(ServiceInfo, 1);
220
221     if (c->resolve) {
222         if (!(i->resolver = avahi_service_resolver_new(client, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, service_resolver_callback, i))) {
223             avahi_free(i);
224             fprintf(stderr, "Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_client_errno(client)));
225             return NULL;
226         }
227
228         n_resolving++;
229     } else
230         i->resolver = NULL;
231
232     i->interface = interface;
233     i->protocol = protocol;
234     i->name = avahi_strdup(name);
235     i->type = avahi_strdup(type);
236     i->domain = avahi_strdup(domain);
237     i->config = c;
238
239     AVAHI_LLIST_PREPEND(ServiceInfo, info, services, i);
240
241     return i;
242 }
243
244 static void remove_service(Config *c, ServiceInfo *i) {
245     assert(c);
246     assert(i);
247
248     AVAHI_LLIST_REMOVE(ServiceInfo, info, services, i);
249
250     if (i->resolver)
251         avahi_service_resolver_free(i->resolver);
252     
253     avahi_free(i->name);
254     avahi_free(i->type);
255     avahi_free(i->domain);
256     avahi_free(i);
257 }
258
259 static void service_browser_callback(
260     AvahiServiceBrowser *b,
261     AvahiIfIndex interface,
262     AvahiProtocol protocol,
263     AvahiBrowserEvent event,
264     const char *name,
265     const char *type,
266     const char *domain,
267     AvahiLookupResultFlags flags,
268     void *userdata) {
269
270     Config *c = userdata;
271     
272     assert(b);
273     assert(c);
274
275     switch (event) {
276         case AVAHI_BROWSER_NEW: {
277             if (c->ignore_local && (flags & AVAHI_LOOKUP_RESULT_LOCAL))
278                 break;
279
280             if (find_service(interface, protocol, name, type, domain))
281                 return;
282
283             add_service(c, interface, protocol, name, type, domain);
284
285             print_service_line(c, '+', interface, protocol, name, type, domain);
286             break;
287
288         }
289
290         case AVAHI_BROWSER_REMOVE: {
291             ServiceInfo *info;
292             
293             if (!(info = find_service(interface, protocol, name, type, domain)))
294                 return;
295
296             remove_service(c, info);
297             
298             print_service_line(c, '-', interface, protocol, name, type, domain);
299             break;
300         }
301             
302         case AVAHI_BROWSER_FAILURE:
303             fprintf(stderr, "service_browser failed: %s\n", avahi_strerror(avahi_client_errno(client)));
304             avahi_simple_poll_quit(simple_poll);
305             break;
306
307         case AVAHI_BROWSER_CACHE_EXHAUSTED:
308             n_cache_exhausted --;
309             check_terminate(c);
310             break;
311             
312         case AVAHI_BROWSER_ALL_FOR_NOW:
313             n_all_for_now --;
314             check_terminate(c);
315             break;
316     }
317 }
318
319 static void browse_service_type(Config *c, const char *stype, const char *domain) {
320     AvahiServiceBrowser *b;
321     AvahiStringList *i;
322     
323     assert(c);
324     assert(client);
325     assert(stype);
326
327     for (i = browsed_types; i; i = i->next)
328         if (avahi_domain_equal(stype, (char*) i->text))
329             return;
330
331     if (!(b = avahi_service_browser_new(
332               client,
333               AVAHI_IF_UNSPEC,
334               AVAHI_PROTO_UNSPEC,
335               stype,
336               domain,
337               0,
338               service_browser_callback,
339               c))) {
340
341         fprintf(stderr, "avahi_service_browser_new() failed: %s\n", avahi_strerror(avahi_client_errno(client)));
342         avahi_simple_poll_quit(simple_poll);
343     }
344
345     browsed_types = avahi_string_list_add(browsed_types, stype);
346
347     n_all_for_now++;
348     n_cache_exhausted++;
349 }
350
351 static void service_type_browser_callback(
352     AvahiServiceTypeBrowser *b,
353     AVAHI_GCC_UNUSED AvahiIfIndex interface,
354     AVAHI_GCC_UNUSED AvahiProtocol protocol,
355     AvahiBrowserEvent event,
356     const char *type,
357     const char *domain,
358     AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
359     void *userdata) {
360
361     Config *c = userdata;
362
363     assert(b);
364     assert(c);
365     
366     switch (event) {
367         
368         case AVAHI_BROWSER_NEW:
369             browse_service_type(c, type, domain);
370             break;
371
372         case AVAHI_BROWSER_REMOVE:
373             /* We're dirty and never remove the browser again */
374             break;
375
376         case AVAHI_BROWSER_FAILURE:
377             fprintf(stderr, "service_type_browser failed: %s\n", avahi_strerror(avahi_client_errno(client)));
378             avahi_simple_poll_quit(simple_poll);
379             break;
380             
381         case AVAHI_BROWSER_CACHE_EXHAUSTED:
382             n_cache_exhausted --;
383             check_terminate(c);
384             break;
385             
386         case AVAHI_BROWSER_ALL_FOR_NOW:
387             n_all_for_now --;
388             check_terminate(c);
389             break;
390     }
391 }
392
393 static void browse_all(Config *c) {
394     AvahiServiceTypeBrowser *b;
395     
396     assert(c);
397
398     if (!(b = avahi_service_type_browser_new(
399               client,
400               AVAHI_IF_UNSPEC,
401               AVAHI_PROTO_UNSPEC,
402               c->domain,
403               0,
404               service_type_browser_callback,
405               c))) {
406         
407         fprintf(stderr, "avahi_service_type_browser_new() failed: %s\n", avahi_strerror(avahi_client_errno(client)));
408         avahi_simple_poll_quit(simple_poll);
409     }
410
411     n_cache_exhausted++;
412     n_all_for_now++;
413 }
414
415 static void domain_browser_callback(
416     AvahiDomainBrowser *b,
417     AVAHI_GCC_UNUSED AvahiIfIndex interface,
418     AVAHI_GCC_UNUSED AvahiProtocol protocol,
419     AvahiBrowserEvent event,
420     const char *domain,
421     AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
422     void *userdata) {
423
424     Config *c = userdata;
425
426     assert(b);
427     assert(c);
428     
429     switch (event) {
430         
431         case AVAHI_BROWSER_NEW:
432         case AVAHI_BROWSER_REMOVE: {
433             char ifname[IF_NAMESIZE];
434             
435             printf("%c %4s %4s %s\n",
436                    event == AVAHI_BROWSER_NEW ? '+' : '-',
437                    interface != AVAHI_IF_UNSPEC ? if_indextoname(interface, ifname) : "n/a",
438                    protocol != AVAHI_PROTO_UNSPEC ? avahi_proto_to_string(protocol) : "n/a", 
439                    domain);
440             break;
441         }
442
443         case AVAHI_BROWSER_FAILURE:
444             fprintf(stderr, "domain_browser failed: %s\n", avahi_strerror(avahi_client_errno(client)));
445             avahi_simple_poll_quit(simple_poll);
446             break;
447             
448         case AVAHI_BROWSER_CACHE_EXHAUSTED:
449             n_cache_exhausted --;
450             check_terminate(c);
451             break;
452             
453         case AVAHI_BROWSER_ALL_FOR_NOW:
454             n_all_for_now --;
455             check_terminate(c);
456             break;
457     }
458 }
459
460 static void browse_domains(Config *c) {
461     AvahiDomainBrowser *b;
462
463     assert(c);
464
465     if (!(b = avahi_domain_browser_new(
466               client,
467               AVAHI_IF_UNSPEC,
468               AVAHI_PROTO_UNSPEC,
469               c->domain,
470               AVAHI_DOMAIN_BROWSER_BROWSE,
471               0,
472               domain_browser_callback,
473               c))) {
474
475         fprintf(stderr, "avahi_domain_browser_new() failed: %s\n", avahi_strerror(avahi_client_errno(client)));
476         avahi_simple_poll_quit(simple_poll);
477     }
478
479     n_cache_exhausted++;
480     n_all_for_now++;
481 }
482
483 static int start(Config *config) {
484
485     assert(!browsing);
486     
487     if (config->verbose) {
488         const char *version, *hn;
489         
490         if (!(version = avahi_client_get_version_string(client))) {
491             fprintf(stderr, "Failed to query version string: %s\n", avahi_strerror(avahi_client_errno(client)));
492             return -1;
493         }
494         
495         if (!(hn = avahi_client_get_host_name_fqdn(client))) {
496             fprintf(stderr, "Failed to query host name: %s\n", avahi_strerror(avahi_client_errno(client)));
497             return -1;
498         }
499         
500         fprintf(stderr, "Server version: %s; Host name: %s\n", version, hn);
501         
502         if (config->command == COMMAND_BROWSE_DOMAINS)
503             fprintf(stderr, "E Ifce Prot Domain\n");
504         else
505             fprintf(stderr, "E Ifce Prot %-*s %-20s Domain\n", n_columns-35, "Name", "Type");
506     }
507     
508     if (config->command == COMMAND_BROWSE_SERVICES)
509         browse_service_type(config, config->stype, config->domain);
510     else if (config->command == COMMAND_BROWSE_ALL_SERVICES)
511         browse_all(config);
512     else {
513         assert(config->command == COMMAND_BROWSE_DOMAINS);
514         browse_domains(config);
515     }
516
517     browsing = 1;
518     return 0;
519 }
520     
521 static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata) {
522     Config *config = userdata;
523
524     /* This function might be called when avahi_client_new() has not
525      * returned yet.*/
526     client = c;
527     
528     switch (state) {
529         case AVAHI_CLIENT_FAILURE:
530             
531             if (config->no_fail && avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED) {
532                 int error;
533
534                 /* We have been disconnected, so let reconnect */
535
536                 fprintf(stderr, "Disconnected, reconnecting ...\n");
537
538                 avahi_client_free(client);
539                 client = NULL;
540
541                 avahi_string_list_free(browsed_types);
542                 browsed_types = NULL;
543                 
544                 while (services)
545                     remove_service(config, services);
546
547                 browsing = 0;
548
549                 if (!(client = avahi_client_new(avahi_simple_poll_get(simple_poll), AVAHI_CLIENT_NO_FAIL, client_callback, config, &error))) {
550                     fprintf(stderr, "Failed to create client object: %s\n", avahi_strerror(error));
551                     avahi_simple_poll_quit(simple_poll);
552                 }
553
554             } else {
555                 fprintf(stderr, "Client failure, exiting: %s\n", avahi_strerror(avahi_client_errno(c)));
556                 avahi_simple_poll_quit(simple_poll);
557             }
558             
559             break;
560             
561         case AVAHI_CLIENT_S_REGISTERING:
562         case AVAHI_CLIENT_S_RUNNING:
563         case AVAHI_CLIENT_S_COLLISION:
564
565             if (!browsing)
566                 if (start(config) < 0)
567                     avahi_simple_poll_quit(simple_poll);
568
569             break;
570             
571         case AVAHI_CLIENT_CONNECTING:
572             
573             if (config->verbose)
574                 fprintf(stderr, "Waiting for daemon ...\n");
575
576             break;
577     }
578 }
579
580 static void help(FILE *f, const char *argv0) {
581     if (strstr(argv0, "domain"))
582         fprintf(f, "%s [options] \n\n", argv0);
583     else
584         fprintf(f,
585                 "%s [options] <service type>\n"
586                 "%s [options] -a\n"
587                 "%s [options] -D\n"
588 #if defined(HAVE_GDBM) || defined(HAVE_DBM)
589                 "%s [options] -b\n"
590 #endif
591                 "\n",
592 #if defined(HAVE_GDBM) || defined(HAVE_DBM)
593                 argv0,
594 #endif
595                 argv0, argv0, argv0);
596
597             fprintf(f, 
598             "    -h --help            Show this help\n"
599             "    -V --version         Show version\n"
600             "    -D --browse-domains  Browse for browsing domains instead of services\n"
601             "    -a --all             Show all services, regardless of the type\n"
602             "    -d --domain=DOMAIN   The domain to browse in\n"
603             "    -v --verbose         Enable verbose mode\n"
604             "    -t --terminate       Terminate after dumping a more or less complete list\n"
605             "    -c --cache           Terminate after dumping all entries from the cache\n"
606             "    -l --ignore-local    Ignore local services\n"
607             "    -r --resolve         Resolve services found\n"
608             "    -f --no-fail         Don't fail if the daemon is not available\n"
609 #if defined(HAVE_GDBM) || defined(HAVE_DBM)
610             "    -k --no-db-lookup    Don't lookup service types\n"
611             "    -b --dump-db         Dump service type database\n"        
612 #endif
613             );
614 }
615
616 static int parse_command_line(Config *c, const char *argv0, int argc, char *argv[]) {
617     int o;
618
619     static const struct option long_options[] = {
620         { "help",           no_argument,       NULL, 'h' },
621         { "version",        no_argument,       NULL, 'V' },
622         { "browse-domains", no_argument,       NULL, 'D' },
623         { "domain",         required_argument, NULL, 'd' },
624         { "all",            no_argument,       NULL, 'a' },
625         { "verbose",        no_argument,       NULL, 'v' },
626         { "terminate",      no_argument,       NULL, 't' },
627         { "cache",          no_argument,       NULL, 'c' },
628         { "ignore-local",   no_argument,       NULL, 'l' },
629         { "resolve",        no_argument,       NULL, 'r' },
630         { "no-fail",        no_argument,       NULL, 'f' },
631 #if defined(HAVE_GDBM) || defined(HAVE_DBM)
632         { "no-db-lookup",   no_argument,       NULL, 'k' },
633         { "dump-db",        no_argument,       NULL, 'b' },
634 #endif
635         { NULL, 0, NULL, 0 }
636     };
637
638     assert(c);
639
640     c->command = strstr(argv0, "domain") ? COMMAND_BROWSE_DOMAINS : COMMAND_BROWSE_SERVICES;
641     c->verbose =
642         c->terminate_on_cache_exhausted =
643         c->terminate_on_all_for_now =
644         c->ignore_local =
645         c->resolve =
646         c->no_fail = 0;
647     c->domain = c->stype = NULL;
648
649 #if defined(HAVE_GDBM) || defined(HAVE_DBM)
650     c->no_db_lookup = 0;
651 #endif
652     
653     while ((o = getopt_long(argc, argv, "hVd:avtclrDf"
654 #if defined(HAVE_GDBM) || defined(HAVE_DBM)
655                             "kb"
656 #endif
657                             , long_options, NULL)) >= 0) {
658
659         switch(o) {
660             case 'h':
661                 c->command = COMMAND_HELP;
662                 break;
663             case 'V':
664                 c->command = COMMAND_VERSION;
665                 break;
666             case 'a':
667                 c->command = COMMAND_BROWSE_ALL_SERVICES;
668                 break;
669             case 'D':
670                 c->command = COMMAND_BROWSE_DOMAINS;
671                 break;
672             case 'd':
673                 avahi_free(c->domain);
674                 c->domain = avahi_strdup(optarg);
675                 break;
676             case 'v':
677                 c->verbose = 1;
678                 break;
679             case 't':
680                 c->terminate_on_all_for_now = 1;
681                 break;
682             case 'c':
683                 c->terminate_on_cache_exhausted = 1;
684                 break;
685             case 'l':
686                 c->ignore_local = 1;
687                 break;
688             case 'r':
689                 c->resolve = 1;
690                 break;
691             case 'f':
692                 c->no_fail = 1;
693                 break;
694 #if defined(HAVE_GDBM) || defined(HAVE_DBM)
695             case 'k':
696                 c->no_db_lookup = 1;
697                 break;
698             case 'b':
699                 c->command = COMMAND_DUMP_STDB;
700                 break;
701 #endif
702             default:
703                 return -1;
704         }
705     }
706
707     if (c->command == COMMAND_BROWSE_SERVICES) {
708         if (optind >= argc) {
709             fprintf(stderr, "Too few arguments\n");
710             return -1;
711         }
712
713         c->stype = avahi_strdup(argv[optind]);
714         optind++;
715     }
716     
717     if (optind < argc) {
718         fprintf(stderr, "Too many arguments\n");
719         return -1;
720     }
721         
722     return 0;
723 }
724
725 int main(int argc, char *argv[]) {
726     int ret = 1, error;
727     Config config;
728     const char *argv0;
729     char *ec;
730
731     setlocale(LC_ALL, "");
732
733     if ((argv0 = strrchr(argv[0], '/')))
734         argv0++;
735     else
736         argv0 = argv[0];
737
738     if ((ec = getenv("COLUMNS")))
739         n_columns = atoi(ec);
740
741     if (n_columns < 40)
742         n_columns = 40;
743     
744     if (parse_command_line(&config, argv0, argc, argv) < 0)
745         goto fail;
746
747     switch (config.command) {
748         case COMMAND_HELP:
749             help(stdout, argv0);
750             ret = 0;
751             break;
752             
753         case COMMAND_VERSION:
754             printf("%s "PACKAGE_VERSION"\n", argv0);
755             ret = 0;
756             break;
757
758         case COMMAND_BROWSE_SERVICES:
759         case COMMAND_BROWSE_ALL_SERVICES:
760         case COMMAND_BROWSE_DOMAINS:
761             
762             if (!(simple_poll = avahi_simple_poll_new())) {
763                 fprintf(stderr, "Failed to create simple poll object.\n");
764                 goto fail;
765             }
766             
767             if (sigint_install(simple_poll) < 0)
768                 goto fail;
769             
770             if (!(client = avahi_client_new(avahi_simple_poll_get(simple_poll), config.no_fail ? AVAHI_CLIENT_NO_FAIL : 0, client_callback, &config, &error))) {
771                 fprintf(stderr, "Failed to create client object: %s\n", avahi_strerror(error));
772                 goto fail;
773             }
774             
775             avahi_simple_poll_loop(simple_poll);
776             ret = 0;
777             break;
778
779 #if defined(HAVE_GDBM) || defined(HAVE_DBM)
780         case COMMAND_DUMP_STDB: {
781             char *t;
782             stdb_setent();
783
784             while ((t = stdb_getent())) {
785                 if (config.no_db_lookup)
786                     printf("%s\n", t);
787                 else
788                     printf("%s\n", stdb_lookup(t));
789             }
790             
791             ret = 0;
792             break;
793         }
794 #endif
795     }
796     
797     
798 fail:
799
800     while (services)
801         remove_service(&config, services);
802
803     if (client)
804         avahi_client_free(client);
805
806     sigint_uninstall();
807     
808     if (simple_poll)
809         avahi_simple_poll_free(simple_poll);
810
811     avahi_free(config.domain);
812     avahi_free(config.stype);
813
814     avahi_string_list_free(browsed_types);
815
816 #if defined(HAVE_GDBM) || defined(HAVE_DBM)
817     stdb_shutdown();
818 #endif    
819
820     return ret;
821 }