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