summaryrefslogtreecommitdiff
path: root/hostname/hostname.c
diff options
context:
space:
mode:
Diffstat (limited to 'hostname/hostname.c')
-rw-r--r--hostname/hostname.c207
1 files changed, 207 insertions, 0 deletions
diff --git a/hostname/hostname.c b/hostname/hostname.c
new file mode 100644
index 0000000..3dc1224
--- /dev/null
+++ b/hostname/hostname.c
@@ -0,0 +1,207 @@
+/*
+ * hostname - get or set the node name of the current workstation.
+ * Copyright (c) 2022 A. Wilcox. All rights reserved.
+ * Licensed under the NCSA open source license.
+ * See LICENSE file included with this source for more information.
+ */
+
+
+#include <arpa/inet.h> /* inet_ntop */
+#include <errno.h> /* errno */
+#include <stdbool.h> /* bool type and true/false */
+#include <stdio.h> /* stderr, stdout, fprintf, fflush */
+#include <stdlib.h> /* EXIT_FAILURE, EXIT_SUCCESS */
+#include <string.h> /* strchr */
+#include <unistd.h> /* getopt, sysconf */
+
+/* gai and friends */
+#include <sys/socket.h>
+#include <netdb.h>
+
+int do_print_nodename(bool verbose, bool domain, bool fqdn, bool address, bool shorten)
+{
+ long hostname = sysconf(_SC_HOST_NAME_MAX);
+ char buf[hostname];
+ struct addrinfo *info;
+
+ if(verbose)
+ {
+ fprintf(stderr, "gethostname()=...");
+ fflush(stderr);
+ }
+ if(gethostname(buf, sizeof buf) != 0)
+ {
+ if(verbose) fprintf(stderr, "{error}\n");
+ perror("gethostname");
+ return EXIT_FAILURE;
+ }
+
+ if(verbose) fprintf(stderr, "\"%s\"\n", buf);
+
+ if(domain || fqdn || address)
+ {
+ struct addrinfo hints = {0};
+ char addr_buf[INET6_ADDRSTRLEN];
+
+ if(verbose)
+ {
+ fprintf(stderr, "getaddrinfo(\"%s\")=...", buf);
+ fflush(stderr);
+ }
+
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
+
+ if(getaddrinfo(buf, NULL, &hints, &info) != 0)
+ {
+ if(verbose) fprintf(stderr, "{error}\n");
+ perror("getaddrinfo");
+ return EXIT_FAILURE;
+ }
+
+ if(info == NULL || info->ai_canonname == NULL)
+ {
+ if(verbose) fprintf(stderr, "{no information}\n");
+ fprintf(stderr, "No information available\n");
+ return EXIT_FAILURE;
+ }
+
+ if(getnameinfo(info->ai_addr, info->ai_addrlen, addr_buf, sizeof addr_buf,
+ NULL, 0, NI_NUMERICHOST) != 0 && address)
+ {
+ if(verbose) fprintf(stderr, "{getnameinfo returned error}\n");
+ perror("getnameinfo");
+ return EXIT_FAILURE;
+ }
+
+ if(verbose) fprintf(stderr, "resolved: %s at %s\n", info->ai_canonname, addr_buf);
+
+ if(domain)
+ {
+ char *domain = strchr(info->ai_canonname, '.');
+ if(domain == NULL)
+ {
+ fprintf(stdout, "(none)\n");
+ return EXIT_SUCCESS;
+ }
+ fprintf(stdout, "%s\n", domain + 1);
+ return EXIT_SUCCESS;
+ }
+
+ if(fqdn)
+ {
+ fprintf(stdout, "%s\n", info->ai_canonname);
+ return EXIT_SUCCESS;
+ }
+
+ if(address)
+ {
+ fprintf(stdout, "%s\n", addr_buf);
+ return EXIT_SUCCESS;
+ }
+ }
+
+ if(shorten)
+ {
+ char *domain = strchr(buf, '.');
+ if(domain != NULL) *domain = '\0';
+ }
+
+ fprintf(stdout, "%s\n", buf);
+ return EXIT_SUCCESS;
+}
+
+int do_set_nodename(bool file, const char *value)
+{
+ fprintf(stderr, "setting nodenamet to %s %s not yet supported\n",
+ (file ? "contents of file" : "literal string"), value);
+ return 1;
+}
+
+void usage()
+{
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, "hostname {hostname|-F filename}\n");
+ fprintf(stderr, "hostname [-v] [-d|-f|-s]\n");
+ fprintf(stderr, "\n\tRetrieve or set node name.\n");
+}
+
+int main(int argc, char *argv[])
+{
+ /* Whether to use a file or argument */
+ bool is_file = false;
+ /* Enable verbose output */
+ bool verbose = false;
+ /* Intentionally shorten name to first part */
+ bool shorten = false;
+ /* Show DNS domain name only (if available) */
+ bool domain = false;
+ /* Go out of our way to show FQDN */
+ bool fqdn = false;
+ /* Print the IP address associated with this node */
+ bool address = false;
+ /* An error occurred during argument parsing */
+ bool arg_error = false;
+ /* The current argument being parsed */
+ int arg;
+
+ while((arg = getopt(argc, argv, ":FVvdfish")) != -1)
+ {
+ switch(arg)
+ {
+ case 'v':
+ verbose = true;
+ break;
+ case 'd':
+ domain = true;
+ break;
+ case 'F':
+ is_file = true;
+ break;
+ case 'f':
+ fqdn = true;
+ break;
+ case 'i':
+ address = true;
+ break;
+ case 's':
+ shorten = true;
+ break;
+ case 'h':
+ usage();
+ return EXIT_SUCCESS;
+ case 'V':
+ fprintf(stdout, "Shimmy " SHIMMY_VERSION "\n");
+ return EXIT_SUCCESS;
+ case ':':
+ fprintf(stderr, "required argument to '-%c' missing\n",
+ optopt);
+ arg_error = true;
+ break;
+ case '?':
+ default:
+ fprintf(stderr, "unrecognised option: '-%c'\n", optopt);
+ arg_error = true;
+ break;
+ }
+ }
+
+ switch(argc - optind)
+ {
+ case 0:
+ if(is_file || arg_error)
+ {
+ arg_error = true;
+ break;
+ }
+ return do_print_nodename(verbose, domain, fqdn, address, shorten);
+ case 1:
+ return do_set_nodename(is_file, argv[optind++]);
+ default:
+ /* just show usage. */
+ break;
+ }
+
+ usage();
+ return EXIT_FAILURE;
+}