Home | History | Annotate | Download | only in avahi-utils
      1 /***
      2   This file is part of avahi.
      3 
      4   avahi is free software; you can redistribute it and/or modify it
      5   under the terms of the GNU Lesser General Public License as
      6   published by the Free Software Foundation; either version 2.1 of the
      7   License, or (at your option) any later version.
      8 
      9   avahi is distributed in the hope that it will be useful, but WITHOUT
     10   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     11   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
     12   Public License for more details.
     13 
     14   You should have received a copy of the GNU Lesser General Public
     15   License along with avahi; if not, write to the Free Software
     16   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
     17   USA.
     18 ***/
     19 
     20 #ifdef HAVE_CONFIG_H
     21 #include <config.h>
     22 #endif
     23 
     24 #include <stdlib.h>
     25 #include <stdio.h>
     26 #include <getopt.h>
     27 #include <assert.h>
     28 #include <string.h>
     29 #include <sys/types.h>
     30 #include <sys/socket.h>
     31 #include <net/if.h>
     32 #include <locale.h>
     33 
     34 #include <avahi-common/simple-watch.h>
     35 #include <avahi-common/error.h>
     36 #include "avahi-common/avahi-malloc.h"
     37 #include <avahi-common/domain.h>
     38 #include <avahi-common/llist.h>
     39 #include <avahi-common/i18n.h>
     40 #include <avahi-client/client.h>
     41 #include <avahi-client/lookup.h>
     42 
     43 #include "sigint.h"
     44 
     45 typedef enum {
     46     COMMAND_UNSPEC,
     47     COMMAND_HELP,
     48     COMMAND_VERSION,
     49     COMMAND_RESOLVE_HOST_NAME,
     50     COMMAND_RESOLVE_ADDRESS
     51 } Command;
     52 
     53 typedef struct Config {
     54     int verbose;
     55     Command command;
     56     AvahiProtocol proto;
     57 } Config;
     58 
     59 static AvahiSimplePoll *simple_poll = NULL;
     60 static AvahiClient *client = NULL;
     61 
     62 static int n_resolving = 0;
     63 
     64 static void host_name_resolver_callback(
     65     AvahiHostNameResolver *r,
     66     AVAHI_GCC_UNUSED AvahiIfIndex interface,
     67     AVAHI_GCC_UNUSED AvahiProtocol protocol,
     68     AvahiResolverEvent event,
     69     const char *name,
     70     const AvahiAddress *a,
     71     AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
     72     AVAHI_GCC_UNUSED void *userdata) {
     73 
     74     assert(r);
     75 
     76     switch (event) {
     77         case AVAHI_RESOLVER_FOUND: {
     78             char address[AVAHI_ADDRESS_STR_MAX];
     79 
     80             avahi_address_snprint(address, sizeof(address), a);
     81 
     82             printf("%s\t%s\n", name, address);
     83 
     84             break;
     85         }
     86 
     87         case AVAHI_RESOLVER_FAILURE:
     88 
     89             fprintf(stderr, _("Failed to resolve host name '%s': %s\n"), name, avahi_strerror(avahi_client_errno(client)));
     90             break;
     91     }
     92 
     93 
     94     avahi_host_name_resolver_free(r);
     95 
     96     assert(n_resolving > 0);
     97     n_resolving--;
     98 
     99     if (n_resolving <= 0)
    100         avahi_simple_poll_quit(simple_poll);
    101 }
    102 
    103 static void address_resolver_callback(
    104     AvahiAddressResolver *r,
    105     AVAHI_GCC_UNUSED AvahiIfIndex interface,
    106     AVAHI_GCC_UNUSED AvahiProtocol protocol,
    107     AvahiResolverEvent event,
    108     const AvahiAddress *a,
    109     const char *name,
    110     AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
    111     AVAHI_GCC_UNUSED void *userdata) {
    112 
    113     char address[AVAHI_ADDRESS_STR_MAX];
    114     assert(r);
    115 
    116     avahi_address_snprint(address, sizeof(address), a);
    117 
    118     switch (event) {
    119         case AVAHI_RESOLVER_FOUND:
    120 
    121             printf("%s\t%s\n", address, name);
    122             break;
    123 
    124         case AVAHI_RESOLVER_FAILURE:
    125 
    126             fprintf(stderr, _("Failed to resolve address '%s': %s\n"), address, avahi_strerror(avahi_client_errno(client)));
    127             break;
    128     }
    129 
    130 
    131     avahi_address_resolver_free(r);
    132 
    133     assert(n_resolving > 0);
    134     n_resolving--;
    135 
    136     if (n_resolving <= 0)
    137         avahi_simple_poll_quit(simple_poll);
    138 }
    139 
    140 static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata) {
    141     switch (state) {
    142         case AVAHI_CLIENT_FAILURE:
    143             fprintf(stderr, _("Client failure, exiting: %s\n"), avahi_strerror(avahi_client_errno(c)));
    144             avahi_simple_poll_quit(simple_poll);
    145             break;
    146 
    147         case AVAHI_CLIENT_S_REGISTERING:
    148         case AVAHI_CLIENT_S_RUNNING:
    149         case AVAHI_CLIENT_S_COLLISION:
    150         case AVAHI_CLIENT_CONNECTING:
    151             ;
    152     }
    153 }
    154 
    155 static void help(FILE *f, const char *argv0) {
    156     fprintf(f,
    157             _("%s [options] %s <host name ...>\n"
    158               "%s [options] %s <address ... >\n\n"
    159               "    -h --help            Show this help\n"
    160               "    -V --version         Show version\n"
    161               "    -n --name            Resolve host name\n"
    162               "    -a --address         Resolve address\n"
    163               "    -v --verbose         Enable verbose mode\n"
    164               "    -6                   Lookup IPv6 address\n"
    165               "    -4                   Lookup IPv4 address\n"),
    166             argv0, strstr(argv0, "host-name") ? "[-n]" : "-n",
    167             argv0, strstr(argv0, "address") ? "[-a]" : "-a");
    168 }
    169 
    170 static int parse_command_line(Config *c, const char *argv0, int argc, char *argv[]) {
    171     int o;
    172 
    173     static const struct option long_options[] = {
    174         { "help",           no_argument,       NULL, 'h' },
    175         { "version",        no_argument,       NULL, 'V' },
    176         { "name",           no_argument,       NULL, 'n' },
    177         { "address",        no_argument,       NULL, 'a' },
    178         { "verbose",        no_argument,       NULL, 'v' },
    179         { NULL, 0, NULL, 0 }
    180     };
    181 
    182     assert(c);
    183 
    184     c->command = strstr(argv0, "address") ? COMMAND_RESOLVE_ADDRESS : (strstr(argv0, "host-name") ? COMMAND_RESOLVE_HOST_NAME : COMMAND_UNSPEC);
    185     c->proto = AVAHI_PROTO_UNSPEC;
    186     c->verbose = 0;
    187 
    188     while ((o = getopt_long(argc, argv, "hVnav46", long_options, NULL)) >= 0) {
    189 
    190         switch(o) {
    191             case 'h':
    192                 c->command = COMMAND_HELP;
    193                 break;
    194             case 'V':
    195                 c->command = COMMAND_VERSION;
    196                 break;
    197             case 'n':
    198                 c->command = COMMAND_RESOLVE_HOST_NAME;
    199                 break;
    200             case 'a':
    201                 c->command = COMMAND_RESOLVE_ADDRESS;
    202                 break;
    203             case 'v':
    204                 c->verbose = 1;
    205                 break;
    206             case '4':
    207                 c->proto = AVAHI_PROTO_INET;
    208                 break;
    209             case '6':
    210                 c->proto = AVAHI_PROTO_INET6;
    211                 break;
    212             default:
    213                 return -1;
    214         }
    215     }
    216 
    217     if (c->command == COMMAND_RESOLVE_ADDRESS || c->command == COMMAND_RESOLVE_HOST_NAME) {
    218         if (optind >= argc) {
    219             fprintf(stderr, _("Too few arguments\n"));
    220             return -1;
    221         }
    222     }
    223 
    224     return 0;
    225 }
    226 
    227 int main(int argc, char *argv[]) {
    228     int ret = 1, error;
    229     Config config;
    230     const char *argv0;
    231 
    232     avahi_init_i18n();
    233     setlocale(LC_ALL, "");
    234 
    235     if ((argv0 = strrchr(argv[0], '/')))
    236         argv0++;
    237     else
    238         argv0 = argv[0];
    239 
    240     if (parse_command_line(&config, argv0, argc, argv) < 0)
    241         goto fail;
    242 
    243     switch (config.command) {
    244         case COMMAND_UNSPEC:
    245             ret = 1;
    246             fprintf(stderr, _("No command specified.\n"));
    247             break;
    248 
    249         case COMMAND_HELP:
    250             help(stdout, argv0);
    251             ret = 0;
    252             break;
    253 
    254         case COMMAND_VERSION:
    255             printf("%s "PACKAGE_VERSION"\n", argv0);
    256             ret = 0;
    257             break;
    258 
    259         case COMMAND_RESOLVE_HOST_NAME:
    260         case COMMAND_RESOLVE_ADDRESS: {
    261             int i;
    262 
    263             if (!(simple_poll = avahi_simple_poll_new())) {
    264                 fprintf(stderr, _("Failed to create simple poll object.\n"));
    265                 goto fail;
    266             }
    267 
    268             if (sigint_install(simple_poll) < 0)
    269                 goto fail;
    270 
    271             if (!(client = avahi_client_new(avahi_simple_poll_get(simple_poll), 0, client_callback, NULL, &error))) {
    272                 fprintf(stderr, _("Failed to create client object: %s\n"), avahi_strerror(error));
    273                 goto fail;
    274             }
    275 
    276             if (config.verbose) {
    277                 const char *version, *hn;
    278 
    279                 if (!(version = avahi_client_get_version_string(client))) {
    280                     fprintf(stderr, _("Failed to query version string: %s\n"), avahi_strerror(avahi_client_errno(client)));
    281                     goto fail;
    282                 }
    283 
    284                 if (!(hn = avahi_client_get_host_name_fqdn(client))) {
    285                     fprintf(stderr, _("Failed to query host name: %s\n"), avahi_strerror(avahi_client_errno(client)));
    286                     goto fail;
    287                 }
    288 
    289                 fprintf(stderr, _("Server version: %s; Host name: %s\n"), version, hn);
    290             }
    291 
    292             n_resolving = 0;
    293 
    294             for (i = optind; i < argc; i++) {
    295 
    296                 if (config.command == COMMAND_RESOLVE_HOST_NAME) {
    297 
    298                     if (!(avahi_host_name_resolver_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, argv[i], config.proto, 0, host_name_resolver_callback, NULL))) {
    299                         fprintf(stderr, _("Failed to create host name resolver: %s\n"), avahi_strerror(avahi_client_errno(client)));
    300                         goto fail;
    301                     }
    302 
    303                 } else {
    304                     AvahiAddress a;
    305 
    306                     assert(config.command == COMMAND_RESOLVE_ADDRESS);
    307 
    308                     if (!avahi_address_parse(argv[i], AVAHI_PROTO_UNSPEC, &a)) {
    309                         fprintf(stderr, _("Failed to parse address '%s'\n"), argv[i]);
    310                         goto fail;
    311                     }
    312 
    313                     if (!(avahi_address_resolver_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, &a, 0, address_resolver_callback, NULL))) {
    314                         fprintf(stderr, _("Failed to create address resolver: %s\n"), avahi_strerror(avahi_client_errno(client)));
    315                         goto fail;
    316                     }
    317                 }
    318 
    319                 n_resolving++;
    320             }
    321 
    322             avahi_simple_poll_loop(simple_poll);
    323             ret = 0;
    324             break;
    325         }
    326     }
    327 
    328 fail:
    329 
    330     if (client)
    331         avahi_client_free(client);
    332 
    333     sigint_uninstall();
    334 
    335     if (simple_poll)
    336         avahi_simple_poll_free(simple_poll);
    337 
    338     return ret;
    339 }
    340