xref: /netbsd-src/external/gpl2/gettext/dist/gettext-tools/src/hostname.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1 /* Display hostname in various forms.
2    Copyright (C) 2001-2003, 2006 Free Software Foundation, Inc.
3    Written by Bruno Haible <haible@clisp.cons.org>, 2001.
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2, or (at your option)
8    any later version.
9 
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software Foundation,
17    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
18 
19 
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23 
24 #include <errno.h>
25 #include <getopt.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <locale.h>
30 
31 #if defined _WIN32 || defined __WIN32__
32 # define WIN32_NATIVE
33 #endif
34 
35 /* Get gethostname().  */
36 #include <unistd.h>
37 
38 #ifdef WIN32_NATIVE
39 /* Native Woe32 API lacks gethostname() but has GetComputerName() instead.  */
40 # include <windows.h>
41 #else
42 /* Some systems, like early Solaris versions, lack gethostname() but
43    have uname() instead.  */
44 # if !HAVE_GETHOSTNAME
45 #  include <sys/utsname.h>
46 # endif
47 #endif
48 
49 /* Get MAXHOSTNAMELEN.  */
50 #include <sys/param.h>
51 #ifndef MAXHOSTNAMELEN
52 # define MAXHOSTNAMELEN 64
53 #endif
54 
55 /* Support for using gethostbyname().  */
56 #if HAVE_GETHOSTBYNAME
57 # include <sys/types.h>
58 # include <sys/socket.h> /* defines AF_INET, AF_INET6 */
59 # include <netinet/in.h> /* declares ntohs(), defines struct sockaddr_in */
60 # if HAVE_ARPA_INET_H
61 #  include <arpa/inet.h> /* declares inet_ntoa(), inet_ntop() */
62 # endif
63 # if HAVE_IPV6
64 #  if !defined(__CYGWIN__) /* Cygwin has only s6_addr, no s6_addr16 */
65 #   if defined(__APPLE__) && defined(__MACH__) /* MacOS X */
66 #    define in6_u __u6_addr
67 #    define u6_addr16 __u6_addr16
68 #   endif
69     /* Use s6_addr16 for portability.  See RFC 2553.  */
70 #   ifndef s6_addr16
71 #    define s6_addr16 in6_u.u6_addr16
72 #   endif
73 #   define HAVE_IN6_S6_ADDR16 1
74 #  endif
75 # endif
76 # include <netdb.h> /* defines struct hostent, declares gethostbyname() */
77 #endif
78 
79 /* Include this after <sys/socket.h>, to avoid a syntax error on BeOS.  */
80 #include <stdbool.h>
81 
82 #include "closeout.h"
83 #include "error.h"
84 #include "error-progname.h"
85 #include "progname.h"
86 #include "relocatable.h"
87 #include "basename.h"
88 #include "xalloc.h"
89 #include "exit.h"
90 #include "propername.h"
91 #include "gettext.h"
92 
93 #define _(str) gettext (str)
94 
95 
96 /* Output format.  */
97 static enum { default_format, short_format, long_format, ip_format } format;
98 
99 /* Long options.  */
100 static const struct option long_options[] =
101 {
102   { "fqdn", no_argument, NULL, 'f' },
103   { "help", no_argument, NULL, 'h' },
104   { "ip-address", no_argument, NULL, 'i' },
105   { "long", no_argument, NULL, 'f' },
106   { "short", no_argument, NULL, 's' },
107   { "version", no_argument, NULL, 'V' },
108   { NULL, 0, NULL, 0 }
109 };
110 
111 
112 /* Forward declaration of local functions.  */
113 static void usage (int status)
114 #if defined __GNUC__ && ((__GNUC__ == 2 && __GNUC_MINOR__ >= 5) || __GNUC__ > 2)
115      __attribute__ ((noreturn))
116 #endif
117 ;
118 static void print_hostname (void);
119 
120 int
main(int argc,char * argv[])121 main (int argc, char *argv[])
122 {
123   int optchar;
124   bool do_help;
125   bool do_version;
126 
127   /* Set program name for messages.  */
128   set_program_name (argv[0]);
129   error_print_progname = maybe_print_progname;
130 
131 #ifdef HAVE_SETLOCALE
132   /* Set locale via LC_ALL.  */
133   setlocale (LC_ALL, "");
134 #endif
135 
136   /* Set the text message domain.  */
137   bindtextdomain (PACKAGE, relocate (LOCALEDIR));
138   textdomain (PACKAGE);
139 
140   /* Ensure that write errors on stdout are detected.  */
141   atexit (close_stdout);
142 
143   /* Set default values for variables.  */
144   do_help = false;
145   do_version = false;
146   format = default_format;
147 
148   /* Parse command line options.  */
149   while ((optchar = getopt_long (argc, argv, "fhisV", long_options, NULL))
150 	 != EOF)
151     switch (optchar)
152     {
153     case '\0':		/* Long option.  */
154       break;
155     case 'f':
156       format = long_format;
157       break;
158     case 's':
159       format = short_format;
160       break;
161     case 'i':
162       format = ip_format;
163       break;
164     case 'h':
165       do_help = true;
166       break;
167     case 'V':
168       do_version = true;
169       break;
170     default:
171       usage (EXIT_FAILURE);
172       /* NOTREACHED */
173     }
174 
175   /* Version information requested.  */
176   if (do_version)
177     {
178       printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION);
179       /* xgettext: no-wrap */
180       printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
181 This is free software; see the source for copying conditions.  There is NO\n\
182 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
183 "),
184 	      "2001-2003");
185       printf (_("Written by %s.\n"), proper_name ("Bruno Haible"));
186       exit (EXIT_SUCCESS);
187     }
188 
189   /* Help is requested.  */
190   if (do_help)
191     usage (EXIT_SUCCESS);
192 
193   /* Test for extraneous arguments.  */
194   if (optind != argc)
195     error (EXIT_FAILURE, 0, _("too many arguments"));
196 
197   /* Get and print the hostname.  */
198   print_hostname ();
199 
200   exit (EXIT_SUCCESS);
201 }
202 
203 /* Display usage information and exit.  */
204 static void
usage(int status)205 usage (int status)
206 {
207   if (status != EXIT_SUCCESS)
208     fprintf (stderr, _("Try `%s --help' for more information.\n"),
209 	     program_name);
210   else
211     {
212       printf (_("\
213 Usage: %s [OPTION]\n\
214 "), program_name);
215       printf ("\n");
216       printf (_("\
217 Print the machine's hostname.\n"));
218       printf ("\n");
219       printf (_("\
220 Output format:\n"));
221       printf (_("\
222   -s, --short                 short host name\n"));
223       printf (_("\
224   -f, --fqdn, --long          long host name, includes fully qualified domain\n\
225                                 name, and aliases\n"));
226       printf (_("\
227   -i, --ip-address            addresses for the hostname\n"));
228       printf ("\n");
229       printf (_("\
230 Informative output:\n"));
231       printf (_("\
232   -h, --help                  display this help and exit\n"));
233       printf (_("\
234   -V, --version               output version information and exit\n"));
235       printf ("\n");
236       fputs (_("Report bugs to <bug-gnu-gettext@gnu.org>.\n"),
237 	     stdout);
238     }
239 
240   exit (status);
241 }
242 
243 /* Returns an xmalloc()ed string containing the machine's host name.  */
244 static char *
xgethostname()245 xgethostname ()
246 {
247 #ifdef WIN32_NATIVE
248   char hostname[MAX_COMPUTERNAME_LENGTH+1];
249   DWORD size = sizeof (hostname);
250 
251   if (!GetComputerName (hostname, &size))
252     error (EXIT_FAILURE, 0, _("could not get host name"));
253   return xstrdup (hostname);
254 #elif HAVE_GETHOSTNAME
255   char hostname[MAXHOSTNAMELEN+1];
256 
257   if (gethostname (hostname, MAXHOSTNAMELEN) < 0)
258     error (EXIT_FAILURE, errno, _("could not get host name"));
259   hostname[MAXHOSTNAMELEN] = '\0';
260   return xstrdup (hostname);
261 #else
262   struct utsname utsname;
263 
264   if (uname (&utsname) < 0)
265     error (EXIT_FAILURE, errno, _("could not get host name"));
266   return xstrdup (utsname.nodename);
267 #endif
268 }
269 
270 /* Converts an AF_INET address to a printable, presentable format.
271    BUFFER is an array with at least 15+1 bytes.  ADDR is 'struct in_addr'.  */
272 #if HAVE_INET_NTOP
273 # define ipv4_ntop(buffer,addr) \
274     inet_ntop (AF_INET, &addr, buffer, 15+1)
275 #else
276 # define ipv4_ntop(buffer,addr) \
277     strcpy (buffer, inet_ntoa (addr))
278 #endif
279 
280 #if HAVE_IPV6
281 /* Converts an AF_INET6 address to a printable, presentable format.
282    BUFFER is an array with at least 45+1 bytes.  ADDR is 'struct in6_addr'.  */
283 # if HAVE_INET_NTOP
284 #  define ipv6_ntop(buffer,addr) \
285      inet_ntop (AF_INET6, &addr, buffer, 45+1)
286 # elif HAVE_IN6_S6_ADDR16
287 #  define ipv6_ntop(buffer,addr) \
288      sprintf (buffer, "%x:%x:%x:%x:%x:%x:%x:%x", \
289 	      ntohs ((addr).s6_addr16[0]), \
290 	      ntohs ((addr).s6_addr16[1]), \
291 	      ntohs ((addr).s6_addr16[2]), \
292 	      ntohs ((addr).s6_addr16[3]), \
293 	      ntohs ((addr).s6_addr16[4]), \
294 	      ntohs ((addr).s6_addr16[5]), \
295 	      ntohs ((addr).s6_addr16[6]), \
296 	      ntohs ((addr).s6_addr16[7]))
297 # else
298 #  define ipv6_ntop(buffer,addr) \
299      sprintf (buffer, "%x:%x:%x:%x:%x:%x:%x:%x", \
300 	      ((addr).s6_addr[0] << 8) | (addr).s6_addr[1], \
301 	      ((addr).s6_addr[2] << 8) | (addr).s6_addr[3], \
302 	      ((addr).s6_addr[4] << 8) | (addr).s6_addr[5], \
303 	      ((addr).s6_addr[6] << 8) | (addr).s6_addr[7], \
304 	      ((addr).s6_addr[8] << 8) | (addr).s6_addr[9], \
305 	      ((addr).s6_addr[10] << 8) | (addr).s6_addr[11], \
306 	      ((addr).s6_addr[12] << 8) | (addr).s6_addr[13], \
307 	      ((addr).s6_addr[14] << 8) | (addr).s6_addr[15])
308 # endif
309 #endif
310 
311 /* Print the hostname according to the specified format.  */
312 static void
print_hostname()313 print_hostname ()
314 {
315   char *hostname;
316   char *dot;
317 #if HAVE_GETHOSTBYNAME
318   struct hostent *h;
319   size_t i;
320 #endif
321 
322   hostname = xgethostname ();
323 
324   switch (format)
325     {
326     case default_format:
327       /* Print the hostname, as returned by the system call.  */
328       printf ("%s\n", hostname);
329       break;
330 
331     case short_format:
332       /* Print only the part before the first dot.  */
333       dot = strchr (hostname, '.');
334       if (dot != NULL)
335 	*dot = '\0';
336       printf ("%s\n", hostname);
337       break;
338 
339     case long_format:
340       /* Look for netwide usable hostname and aliases using gethostbyname().  */
341 #if HAVE_GETHOSTBYNAME
342       h = gethostbyname (hostname);
343       if (h != NULL)
344 	{
345 	  printf ("%s\n", h->h_name);
346 	  if (h->h_aliases != NULL)
347 	    for (i = 0; h->h_aliases[i] != NULL; i++)
348 	      printf ("%s\n", h->h_aliases[i]);
349 	}
350       else
351 #endif
352 	printf ("%s\n", hostname);
353       break;
354 
355     case ip_format:
356       /* Look for netwide usable IP addresses using gethostbyname().  */
357 #if HAVE_GETHOSTBYNAME
358       h = gethostbyname (hostname);
359       if (h != NULL && h->h_addr_list != NULL)
360 	for (i = 0; h->h_addr_list[i] != NULL; i++)
361 	  {
362 #if HAVE_IPV6
363 	    if (h->h_addrtype == AF_INET6)
364 	      {
365 		char buffer[45+1];
366 		ipv6_ntop (buffer, *(const struct in6_addr*) h->h_addr_list[i]);
367 		printf("[%s]\n", buffer);
368 	      }
369 	    else
370 #endif
371 	    if (h->h_addrtype == AF_INET)
372 	      {
373 		char buffer[15+1];
374 		ipv4_ntop (buffer, *(const struct in_addr*) h->h_addr_list[i]);
375 		printf("[%s]\n", buffer);
376 	      }
377 	  }
378 #endif
379       break;
380 
381     default:
382       abort ();
383     }
384 }
385