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 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 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 * 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 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