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. */ 97static enum { default_format, short_format, long_format, ip_format } format; 98 99/* Long options. */ 100static 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. */ 113static void usage (int status) 114#if defined __GNUC__ && ((__GNUC__ == 2 && __GNUC_MINOR__ >= 5) || __GNUC__ > 2) 115 __attribute__ ((noreturn)) 116#endif 117; 118static void print_hostname (void); 119 120int 121main (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\ 181This is free software; see the source for copying conditions. There is NO\n\ 182warranty; 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. */ 204static void 205usage (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 (_("\ 213Usage: %s [OPTION]\n\ 214"), program_name); 215 printf ("\n"); 216 printf (_("\ 217Print the machine's hostname.\n")); 218 printf ("\n"); 219 printf (_("\ 220Output 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 (_("\ 230Informative 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. */ 244static char * 245xgethostname () 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. */ 312static void 313print_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