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