| /* Display hostname in various forms. |
| Copyright (C) 2001-2003, 2006-2007, 2012, 2014, 2018-2020 Free Software |
| Foundation, Inc. |
| Written by Bruno Haible <haible@clisp.cons.org>, 2001. |
| |
| This program is free software: you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
| |
| |
| #ifdef HAVE_CONFIG_H |
| # include "config.h" |
| #endif |
| |
| #include <errno.h> |
| #include <getopt.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <locale.h> |
| |
| #if defined _WIN32 |
| # define WIN32_NATIVE |
| #endif |
| |
| /* Get gethostname(). */ |
| #include <unistd.h> |
| |
| #ifdef WIN32_NATIVE |
| /* Native Woe32 API lacks gethostname() but has GetComputerName() instead. */ |
| # include <windows.h> |
| #else |
| /* Some systems, like early Solaris versions, lack gethostname() but |
| have uname() instead. */ |
| # if !HAVE_GETHOSTNAME |
| # include <sys/utsname.h> |
| # endif |
| #endif |
| |
| /* Get MAXHOSTNAMELEN. */ |
| #if HAVE_SYS_PARAM_H |
| # include <sys/param.h> |
| #endif |
| #ifndef MAXHOSTNAMELEN |
| # define MAXHOSTNAMELEN 64 |
| #endif |
| |
| /* Support for using gethostbyname(). */ |
| #if HAVE_GETHOSTBYNAME |
| # include <sys/types.h> |
| # include <sys/socket.h> /* defines AF_INET, AF_INET6 */ |
| # include <netinet/in.h> /* declares ntohs(), defines struct sockaddr_in */ |
| # if HAVE_ARPA_INET_H |
| # include <arpa/inet.h> /* declares inet_ntoa(), inet_ntop() */ |
| # endif |
| # if HAVE_IPV6 |
| # if !defined(__CYGWIN__) /* Cygwin has only s6_addr, no s6_addr16 */ |
| # if defined(__APPLE__) && defined(__MACH__) /* MacOS X */ |
| # define in6_u __u6_addr |
| # define u6_addr16 __u6_addr16 |
| # endif |
| /* Use s6_addr16 for portability. See RFC 2553. */ |
| # ifndef s6_addr16 |
| # define s6_addr16 in6_u.u6_addr16 |
| # endif |
| # define HAVE_IN6_S6_ADDR16 1 |
| # endif |
| # endif |
| # include <netdb.h> /* defines struct hostent, declares gethostbyname() */ |
| #endif |
| |
| /* Include this after <sys/socket.h>, to avoid a syntax error on BeOS. */ |
| #include <stdbool.h> |
| |
| #include "noreturn.h" |
| #include "closeout.h" |
| #include "error.h" |
| #include "error-progname.h" |
| #include "progname.h" |
| #include "relocatable.h" |
| #include "basename-lgpl.h" |
| #include "xalloc.h" |
| #include "propername.h" |
| #include "gettext.h" |
| |
| #define _(str) gettext (str) |
| |
| |
| /* Output format. */ |
| static enum { default_format, short_format, long_format, ip_format } format; |
| |
| /* Long options. */ |
| static const struct option long_options[] = |
| { |
| { "fqdn", no_argument, NULL, 'f' }, |
| { "help", no_argument, NULL, 'h' }, |
| { "ip-address", no_argument, NULL, 'i' }, |
| { "long", no_argument, NULL, 'f' }, |
| { "short", no_argument, NULL, 's' }, |
| { "version", no_argument, NULL, 'V' }, |
| { NULL, 0, NULL, 0 } |
| }; |
| |
| |
| /* Forward declaration of local functions. */ |
| _GL_NORETURN_FUNC static void usage (int status); |
| static void print_hostname (void); |
| |
| int |
| main (int argc, char *argv[]) |
| { |
| int optchar; |
| bool do_help; |
| bool do_version; |
| |
| /* Set program name for messages. */ |
| set_program_name (argv[0]); |
| error_print_progname = maybe_print_progname; |
| |
| /* Set locale via LC_ALL. */ |
| setlocale (LC_ALL, ""); |
| |
| /* Set the text message domain. */ |
| bindtextdomain (PACKAGE, relocate (LOCALEDIR)); |
| textdomain (PACKAGE); |
| |
| /* Ensure that write errors on stdout are detected. */ |
| atexit (close_stdout); |
| |
| /* Set default values for variables. */ |
| do_help = false; |
| do_version = false; |
| format = default_format; |
| |
| /* Parse command line options. */ |
| while ((optchar = getopt_long (argc, argv, "fhisV", long_options, NULL)) |
| != EOF) |
| switch (optchar) |
| { |
| case '\0': /* Long option. */ |
| break; |
| case 'f': |
| format = long_format; |
| break; |
| case 's': |
| format = short_format; |
| break; |
| case 'i': |
| format = ip_format; |
| break; |
| case 'h': |
| do_help = true; |
| break; |
| case 'V': |
| do_version = true; |
| break; |
| default: |
| usage (EXIT_FAILURE); |
| /* NOTREACHED */ |
| } |
| |
| /* Version information requested. */ |
| if (do_version) |
| { |
| printf ("%s (GNU %s) %s\n", last_component (program_name), |
| PACKAGE, VERSION); |
| /* xgettext: no-wrap */ |
| printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\ |
| License GPLv3+: GNU GPL version 3 or later <%s>\n\ |
| This is free software: you are free to change and redistribute it.\n\ |
| There is NO WARRANTY, to the extent permitted by law.\n\ |
| "), |
| "2001-2020", "https://gnu.org/licenses/gpl.html"); |
| printf (_("Written by %s.\n"), proper_name ("Bruno Haible")); |
| exit (EXIT_SUCCESS); |
| } |
| |
| /* Help is requested. */ |
| if (do_help) |
| usage (EXIT_SUCCESS); |
| |
| /* Test for extraneous arguments. */ |
| if (optind != argc) |
| error (EXIT_FAILURE, 0, _("too many arguments")); |
| |
| /* Get and print the hostname. */ |
| print_hostname (); |
| |
| exit (EXIT_SUCCESS); |
| } |
| |
| /* Display usage information and exit. */ |
| static void |
| usage (int status) |
| { |
| if (status != EXIT_SUCCESS) |
| fprintf (stderr, _("Try '%s --help' for more information.\n"), |
| program_name); |
| else |
| { |
| printf (_("\ |
| Usage: %s [OPTION]\n\ |
| "), program_name); |
| printf ("\n"); |
| printf (_("\ |
| Print the machine's hostname.\n")); |
| printf ("\n"); |
| printf (_("\ |
| Output format:\n")); |
| printf (_("\ |
| -s, --short short host name\n")); |
| printf (_("\ |
| -f, --fqdn, --long long host name, includes fully qualified domain\n\ |
| name, and aliases\n")); |
| printf (_("\ |
| -i, --ip-address addresses for the hostname\n")); |
| printf ("\n"); |
| printf (_("\ |
| Informative output:\n")); |
| printf (_("\ |
| -h, --help display this help and exit\n")); |
| printf (_("\ |
| -V, --version output version information and exit\n")); |
| printf ("\n"); |
| /* TRANSLATORS: The first placeholder is the web address of the Savannah |
| project of this package. The second placeholder is the bug-reporting |
| email address for this package. Please add _another line_ saying |
| "Report translation bugs to <...>\n" with the address for translation |
| bugs (typically your translation team's web or email address). */ |
| printf(_("\ |
| Report bugs in the bug tracker at <%s>\n\ |
| or by email to <%s>.\n"), |
| "https://savannah.gnu.org/projects/gettext", |
| "bug-gettext@gnu.org"); |
| } |
| |
| exit (status); |
| } |
| |
| /* Returns an xmalloc()ed string containing the machine's host name. */ |
| static char * |
| xgethostname () |
| { |
| #ifdef WIN32_NATIVE |
| char hostname[MAX_COMPUTERNAME_LENGTH+1]; |
| DWORD size = sizeof (hostname); |
| |
| if (!GetComputerName (hostname, &size)) |
| error (EXIT_FAILURE, 0, _("could not get host name")); |
| return xstrdup (hostname); |
| #elif HAVE_GETHOSTNAME |
| char hostname[MAXHOSTNAMELEN+1]; |
| |
| if (gethostname (hostname, MAXHOSTNAMELEN) < 0) |
| error (EXIT_FAILURE, errno, _("could not get host name")); |
| hostname[MAXHOSTNAMELEN] = '\0'; |
| return xstrdup (hostname); |
| #else |
| struct utsname utsname; |
| |
| if (uname (&utsname) < 0) |
| error (EXIT_FAILURE, errno, _("could not get host name")); |
| return xstrdup (utsname.nodename); |
| #endif |
| } |
| |
| /* Converts an AF_INET address to a printable, presentable format. |
| BUFFER is an array with at least 15+1 bytes. ADDR is 'struct in_addr'. */ |
| #if HAVE_INET_NTOP |
| # define ipv4_ntop(buffer,addr) \ |
| inet_ntop (AF_INET, &addr, buffer, 15+1) |
| #else |
| # define ipv4_ntop(buffer,addr) \ |
| strcpy (buffer, inet_ntoa (addr)) |
| #endif |
| |
| #if HAVE_IPV6 |
| /* Converts an AF_INET6 address to a printable, presentable format. |
| BUFFER is an array with at least 45+1 bytes. ADDR is 'struct in6_addr'. */ |
| # if HAVE_INET_NTOP |
| # define ipv6_ntop(buffer,addr) \ |
| inet_ntop (AF_INET6, &addr, buffer, 45+1) |
| # elif HAVE_IN6_S6_ADDR16 |
| # define ipv6_ntop(buffer,addr) \ |
| sprintf (buffer, "%x:%x:%x:%x:%x:%x:%x:%x", \ |
| ntohs ((addr).s6_addr16[0]), \ |
| ntohs ((addr).s6_addr16[1]), \ |
| ntohs ((addr).s6_addr16[2]), \ |
| ntohs ((addr).s6_addr16[3]), \ |
| ntohs ((addr).s6_addr16[4]), \ |
| ntohs ((addr).s6_addr16[5]), \ |
| ntohs ((addr).s6_addr16[6]), \ |
| ntohs ((addr).s6_addr16[7])) |
| # else |
| # define ipv6_ntop(buffer,addr) \ |
| sprintf (buffer, "%x:%x:%x:%x:%x:%x:%x:%x", \ |
| ((addr).s6_addr[0] << 8) | (addr).s6_addr[1], \ |
| ((addr).s6_addr[2] << 8) | (addr).s6_addr[3], \ |
| ((addr).s6_addr[4] << 8) | (addr).s6_addr[5], \ |
| ((addr).s6_addr[6] << 8) | (addr).s6_addr[7], \ |
| ((addr).s6_addr[8] << 8) | (addr).s6_addr[9], \ |
| ((addr).s6_addr[10] << 8) | (addr).s6_addr[11], \ |
| ((addr).s6_addr[12] << 8) | (addr).s6_addr[13], \ |
| ((addr).s6_addr[14] << 8) | (addr).s6_addr[15]) |
| # endif |
| #endif |
| |
| /* Print the hostname according to the specified format. */ |
| static void |
| print_hostname () |
| { |
| char *hostname; |
| char *dot; |
| #if HAVE_GETHOSTBYNAME |
| struct hostent *h; |
| size_t i; |
| #endif |
| |
| hostname = xgethostname (); |
| |
| switch (format) |
| { |
| case default_format: |
| /* Print the hostname, as returned by the system call. */ |
| printf ("%s\n", hostname); |
| break; |
| |
| case short_format: |
| /* Print only the part before the first dot. */ |
| dot = strchr (hostname, '.'); |
| if (dot != NULL) |
| *dot = '\0'; |
| printf ("%s\n", hostname); |
| break; |
| |
| case long_format: |
| /* Look for netwide usable hostname and aliases using gethostbyname(). */ |
| #if HAVE_GETHOSTBYNAME |
| h = gethostbyname (hostname); |
| if (h != NULL) |
| { |
| printf ("%s\n", h->h_name); |
| if (h->h_aliases != NULL) |
| for (i = 0; h->h_aliases[i] != NULL; i++) |
| printf ("%s\n", h->h_aliases[i]); |
| } |
| else |
| #endif |
| printf ("%s\n", hostname); |
| break; |
| |
| case ip_format: |
| /* Look for netwide usable IP addresses using gethostbyname(). */ |
| #if HAVE_GETHOSTBYNAME |
| h = gethostbyname (hostname); |
| if (h != NULL && h->h_addr_list != NULL) |
| for (i = 0; h->h_addr_list[i] != NULL; i++) |
| { |
| #if HAVE_IPV6 |
| if (h->h_addrtype == AF_INET6) |
| { |
| char buffer[45+1]; |
| ipv6_ntop (buffer, *(const struct in6_addr*) h->h_addr_list[i]); |
| printf("[%s]\n", buffer); |
| } |
| else |
| #endif |
| if (h->h_addrtype == AF_INET) |
| { |
| char buffer[15+1]; |
| ipv4_ntop (buffer, *(const struct in_addr*) h->h_addr_list[i]); |
| printf("[%s]\n", buffer); |
| } |
| } |
| #endif |
| break; |
| |
| default: |
| abort (); |
| } |
| } |