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