]> git.meshlink.io Git - catta/blob - avahi-utils/avahi-resolve.c
small --help wording improvement
[catta] / avahi-utils / avahi-resolve.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 #ifdef HAVE_GDBM
47 #include "stdb.h"
48 #endif
49
50 typedef enum {
51     COMMAND_UNSPEC, 
52     COMMAND_HELP,
53     COMMAND_VERSION,
54     COMMAND_RESOLVE_HOST_NAME,
55     COMMAND_RESOLVE_ADDRESS
56 } Command;
57
58 typedef struct Config {
59     int verbose;
60     Command command;
61     AvahiProtocol proto;
62 } Config;
63
64 static AvahiSimplePoll *simple_poll = NULL;
65 static AvahiClient *client = NULL;
66
67 static int n_resolving = 0;
68
69 static void host_name_resolver_callback(
70     AvahiHostNameResolver *r,
71     AVAHI_GCC_UNUSED AvahiIfIndex interface,
72     AVAHI_GCC_UNUSED AvahiProtocol protocol,
73     AvahiResolverEvent event,
74     const char *name,
75     const AvahiAddress *a,
76     AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
77     AVAHI_GCC_UNUSED void *userdata) {
78     
79     assert(r);
80
81     switch (event) {
82         case AVAHI_RESOLVER_FOUND: {
83             char address[AVAHI_ADDRESS_STR_MAX];
84
85             avahi_address_snprint(address, sizeof(address), a);
86
87             printf("%s\t%s\n", name, address);
88             
89             break;
90         }
91
92         case AVAHI_RESOLVER_FAILURE:
93             
94             fprintf(stderr, "Failed to resolve host name '%s': %s\n", name, avahi_strerror(avahi_client_errno(client)));
95             break;
96     }
97
98     
99     avahi_host_name_resolver_free(r);
100
101     assert(n_resolving > 0);
102     n_resolving--;
103
104     if (n_resolving <= 0)
105         avahi_simple_poll_quit(simple_poll);
106 }
107
108 static void address_resolver_callback(
109     AvahiAddressResolver *r,
110     AVAHI_GCC_UNUSED AvahiIfIndex interface,
111     AVAHI_GCC_UNUSED AvahiProtocol protocol,
112     AvahiResolverEvent event,
113     const AvahiAddress *a,
114     const char *name,
115     AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
116     AVAHI_GCC_UNUSED void *userdata) {
117     
118     char address[AVAHI_ADDRESS_STR_MAX];
119     assert(r);
120
121     avahi_address_snprint(address, sizeof(address), a);
122
123     switch (event) {
124         case AVAHI_RESOLVER_FOUND:
125
126             printf("%s\t%s\n", address, name);
127             break;
128
129         case AVAHI_RESOLVER_FAILURE:
130             
131             fprintf(stderr, "Failed to resolve address '%s': %s\n", address, avahi_strerror(avahi_client_errno(client)));
132             break;
133     }
134
135     
136     avahi_address_resolver_free(r);
137
138     assert(n_resolving > 0);
139     n_resolving--;
140
141     if (n_resolving <= 0)
142         avahi_simple_poll_quit(simple_poll);
143 }
144
145 static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata) {
146     switch (state) {
147         case AVAHI_CLIENT_FAILURE:
148             fprintf(stderr, "Client failure, exiting: %s\n", avahi_strerror(avahi_client_errno(c)));
149             avahi_simple_poll_quit(simple_poll);
150             break;
151             
152         case AVAHI_CLIENT_S_REGISTERING:
153         case AVAHI_CLIENT_S_RUNNING:
154         case AVAHI_CLIENT_S_COLLISION:
155         case AVAHI_CLIENT_CONNECTING:
156             ;
157     }
158 }
159
160 static void help(FILE *f, const char *argv0) {
161     fprintf(f,
162             "%s [options] %s <host name ...>\n"
163             "%s [options] %s <address ... >\n\n"
164             "    -h --help            Show this help\n"
165             "    -V --version         Show version\n"
166             "    -n --name            Resolve host name\n"
167             "    -a --address         Resolve address\n"
168             "    -v --verbose         Enable verbose mode\n"
169             "    -6                   Lookup IPv6 address\n"
170             "    -4                   Lookup IPv4 address\n"
171             ,
172             argv0, strstr(argv0, "address") ? "[-a]" : "-a",
173             argv0, strstr(argv0, "host-name") ? "[-n]" : "-n");
174 }
175
176 static int parse_command_line(Config *c, int argc, char *argv[]) {
177     int o;
178
179     static const struct option long_options[] = {
180         { "help",           no_argument,       NULL, 'h' },
181         { "version",        no_argument,       NULL, 'V' },
182         { "name",           no_argument,       NULL, 'n' },
183         { "address",        no_argument,       NULL, 'a' },
184         { "verbose",        no_argument,       NULL, 'v' },
185         { NULL, 0, NULL, 0 }
186     };
187
188     assert(c);
189
190     c->command = strstr(argv[0], "address") ? COMMAND_RESOLVE_ADDRESS : (strstr(argv[0], "host-name") ? COMMAND_RESOLVE_HOST_NAME : COMMAND_UNSPEC);
191     c->proto = AVAHI_PROTO_UNSPEC;
192     c->verbose = 0;
193
194     opterr = 0;
195     while ((o = getopt_long(argc, argv, "hVnav46", long_options, NULL)) >= 0) {
196
197         switch(o) {
198             case 'h':
199                 c->command = COMMAND_HELP;
200                 break;
201             case 'V':
202                 c->command = COMMAND_VERSION;
203                 break;
204             case 'n':
205                 c->command = COMMAND_RESOLVE_HOST_NAME;
206                 break;
207             case 'a':
208                 c->command = COMMAND_RESOLVE_ADDRESS;
209                 break;
210             case 'v':
211                 c->verbose = 1;
212                 break;
213             case '4':
214                 c->proto = AVAHI_PROTO_INET;
215                 break;
216             case '6':
217                 c->proto = AVAHI_PROTO_INET6;
218                 break;
219             default:
220                 fprintf(stderr, "Invalid command line argument: %c\n", o);
221                 return -1;
222         }
223     }
224
225     if (c->command == COMMAND_RESOLVE_ADDRESS || c->command == COMMAND_RESOLVE_HOST_NAME) {
226         if (optind >= argc) {
227             fprintf(stderr, "Too few arguments\n");
228             return -1;
229         }
230     }
231         
232     return 0;
233 }
234
235 int main(int argc, char *argv[]) {
236     int ret = 1, error;
237     Config config;
238     const char *argv0;
239
240     if ((argv0 = strrchr(argv[0], '/')))
241         argv0++;
242     else
243         argv0 = argv[0];
244
245     if (parse_command_line(&config, argc, argv) < 0)
246         goto fail;
247
248     switch (config.command) {
249         case COMMAND_UNSPEC:
250             ret = 1;
251             fprintf(stderr, "No command specified.\n");
252             break;
253             
254         case COMMAND_HELP:
255             help(stdout, argv0);
256             ret = 0;
257             break;
258             
259         case COMMAND_VERSION:
260             printf("%s "PACKAGE_VERSION"\n", argv0);
261             ret = 0;
262             break;
263
264         case COMMAND_RESOLVE_HOST_NAME:
265         case COMMAND_RESOLVE_ADDRESS: {
266             int i;
267             
268             if (!(simple_poll = avahi_simple_poll_new())) {
269                 fprintf(stderr, "Failed to create simple poll object.\n");
270                 goto fail;
271             }
272             
273             if (sigint_install(simple_poll) < 0)
274                 goto fail;
275             
276             if (!(client = avahi_client_new(avahi_simple_poll_get(simple_poll), 0, client_callback, NULL, &error))) {
277                 fprintf(stderr, "Failed to create client object: %s\n", avahi_strerror(error));
278                 goto fail;
279             }
280
281             if (config.verbose) {
282                 const char *version, *hn;
283
284                 if (!(version = avahi_client_get_version_string(client))) {
285                     fprintf(stderr, "Failed to query version string: %s\n", avahi_strerror(avahi_client_errno(client)));
286                     goto fail;
287                 }
288
289                 if (!(hn = avahi_client_get_host_name_fqdn(client))) {
290                     fprintf(stderr, "Failed to query host name: %s\n", avahi_strerror(avahi_client_errno(client)));
291                     goto fail;
292                 }
293                 
294                 fprintf(stderr, "Server version: %s; Host name: %s\n", version, hn);
295             }
296
297             n_resolving = 0;
298             
299             for (i = optind; i < argc; i++) {
300
301                 if (config.command == COMMAND_RESOLVE_HOST_NAME) {
302
303                     if (!(avahi_host_name_resolver_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, argv[i], config.proto, 0, host_name_resolver_callback, NULL))) {
304                         fprintf(stderr, "Failed to create host name resolver: %s\n", avahi_strerror(avahi_client_errno(client)));
305                         goto fail;
306                     }
307                         
308                 } else {
309                     AvahiAddress a;
310                     
311                     assert(config.command == COMMAND_RESOLVE_ADDRESS);
312
313                     if (!avahi_address_parse(argv[i], AVAHI_PROTO_UNSPEC, &a)) {
314                         fprintf(stderr, "Failed to parse address '%s'\n", argv[i]);
315                         goto fail;
316                     }
317
318                     if (!(avahi_address_resolver_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, &a, 0, address_resolver_callback, NULL))) {
319                         fprintf(stderr, "Failed to create address resolver: %s\n", avahi_strerror(avahi_client_errno(client)));
320                         goto fail;
321                     }
322                 }
323
324                 n_resolving++;
325             }
326             
327             avahi_simple_poll_loop(simple_poll);
328             ret = 0;
329             break;
330         }
331     }
332     
333 fail:
334
335     if (client)
336         avahi_client_free(client);
337
338     sigint_uninstall();
339     
340     if (simple_poll)
341         avahi_simple_poll_free(simple_poll);
342
343     return ret;
344 }