diff options
author | A. Wilcox <AWilcox@Wilcox-Tech.com> | 2022-04-22 03:11:53 -0500 |
---|---|---|
committer | A. Wilcox <AWilcox@Wilcox-Tech.com> | 2022-04-22 03:11:53 -0500 |
commit | 7b782cd4082e4d8aae483b5e4b68b62063ec2615 (patch) | |
tree | 19fb46da5676d7d22fdb38de428609d5757da750 | |
parent | dbd74ddb26b5a0494ed2f075e886e3450a7ede7b (diff) | |
download | shimmy-7b782cd4082e4d8aae483b5e4b68b62063ec2615.tar.gz shimmy-7b782cd4082e4d8aae483b5e4b68b62063ec2615.tar.bz2 shimmy-7b782cd4082e4d8aae483b5e4b68b62063ec2615.tar.xz shimmy-7b782cd4082e4d8aae483b5e4b68b62063ec2615.zip |
Add initial hostname(1) implementation
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | hostname/Makefile | 16 | ||||
-rw-r--r-- | hostname/hostname.1 | 36 | ||||
-rw-r--r-- | hostname/hostname.c | 207 |
4 files changed, 266 insertions, 1 deletions
@@ -1,18 +1,24 @@ .POSIX: -all: getconf/getconf localedef/localedef +all: getconf/getconf hostname/hostname localedef/localedef getconf/getconf: cd getconf && $(MAKE) +hostname/hostname: + cd hostname && $(MAKE) + localedef/localedef: cd localedef && ${MAKE} clean: cd getconf && $(MAKE) clean + cd hostname && $(MAKE) clean + cd localedef && $(MAKE) clean install: mkdir -p $(DESTDIR)/usr/bin mkdir -p $(DESTDIR)/usr/share/man/man1 cd getconf && $(MAKE) install + cd hostname && $(MAKE) install cd localedef && $(MAKE) install diff --git a/hostname/Makefile b/hostname/Makefile new file mode 100644 index 0000000..bb4dc1b --- /dev/null +++ b/hostname/Makefile @@ -0,0 +1,16 @@ +.POSIX: + +VERSTR=0.7 + +CFLAGS=-D _POSIX_C_SOURCE=200809L -D _XOPEN_SOURCE=700 -D SHIMMY_VERSION=\"$(VERSTR)\" + +hostname: hostname.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + +clean: + -rm hostname + +install: hostname + cp hostname $(DESTDIR)/usr/bin/hostname + cp hostname.1 $(DESTDIR)/usr/share/man/man1/hostname.1 + diff --git a/hostname/hostname.1 b/hostname/hostname.1 new file mode 100644 index 0000000..94e12eb --- /dev/null +++ b/hostname/hostname.1 @@ -0,0 +1,36 @@ +.Dd April 22, 2022 +.Dt GETCONF 1 "Base Commands Manual" +.Os "Adélie Linux" +.Sh NAME +.Nm hostname +.Nd get or set node name +.Sh SYNOPSIS +.Nm +.Nm +.Op Fl F Ar filename +.Ar name +.Sh DESCRIPTION +In the first form, the +.Nm +utility prints the current node name on the running system. +.Pp +In the second form, the +.Nm +utility sets the currenet node name to the value specified. +.Sh OPTIONS +.Sh DIAGNOSTICS +.Ex -std +.Sh SEE ALSO +.Xr gethostname 3 , +.Xr getaddrinfo 3 , +.Xr getnameinfo 3 . +.Sh STANDARDS +The eventual goal for the +.Nm +utility is full conformance to LSB 5.0. +.Sh AUTHORS +.An A. Wilcox +.Aq awilfox@adelielinux.org +.Sh BUGS +Documentation is incomplete. NIS/YP domain name support is not available +in this release. Long options accepted by net-tools are not accepted. 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; +} |