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