From 7b782cd4082e4d8aae483b5e4b68b62063ec2615 Mon Sep 17 00:00:00 2001 From: "A. Wilcox" Date: Fri, 22 Apr 2022 03:11:53 -0500 Subject: Add initial hostname(1) implementation --- Makefile | 8 +- hostname/Makefile | 16 ++++ hostname/hostname.1 | 36 +++++++++ hostname/hostname.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 266 insertions(+), 1 deletion(-) create mode 100644 hostname/Makefile create mode 100644 hostname/hostname.1 create mode 100644 hostname/hostname.c diff --git a/Makefile b/Makefile index 26b890c..4e355cb 100644 --- a/Makefile +++ b/Makefile @@ -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 /* inet_ntop */ +#include /* errno */ +#include /* bool type and true/false */ +#include /* stderr, stdout, fprintf, fflush */ +#include /* EXIT_FAILURE, EXIT_SUCCESS */ +#include /* strchr */ +#include /* getopt, sysconf */ + +/* gai and friends */ +#include +#include + +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; +} -- cgit v1.2.3-70-g09d2 From 2a708d9795c2474be8af2b4920c3806fc7b8f5cf Mon Sep 17 00:00:00 2001 From: "A. Wilcox" Date: Sat, 23 Apr 2022 02:41:04 -0500 Subject: hostname: Add ability to set node name --- hostname/hostname.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/hostname/hostname.c b/hostname/hostname.c index 3dc1224..d19e4b8 100644 --- a/hostname/hostname.c +++ b/hostname/hostname.c @@ -18,6 +18,18 @@ #include #include +/* open, read, close */ +#include +#include + +int sethostname(const char *value, +#ifdef __linux__ + size_t +#else + int +#endif + namelen); + int do_print_nodename(bool verbose, bool domain, bool fqdn, bool address, bool shorten) { long hostname = sysconf(_SC_HOST_NAME_MAX); @@ -113,9 +125,53 @@ int do_print_nodename(bool verbose, bool domain, bool fqdn, bool address, bool s 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; + size_t len; + + if(file) + { + /* This is insane. There is no validation whatsoever. + * However, strace on net-tools hostname(1) shows this to be + * the exact algorithm used, so... */ + char buf[1024]; + int fildes = open(value, O_RDONLY); + ssize_t result = 0; + + if(fildes == -1) + { + perror("open"); + return EXIT_FAILURE; + } + + while(true) + { + char *curr = buf; + result = read(fildes, buf, sizeof buf); + switch(result) + { + case -1: + perror("read"); + close(fildes); + return EXIT_FAILURE; + case 0: + close(fildes); + return EXIT_SUCCESS; + } + do + { + len = result; + char *pos = strchr(curr, '\n'); + if(pos) + { + len = pos - curr; + } + sethostname(curr, (len > 63) ? 63 : len); + } while((curr = strchr(curr, '\n'))); + } + } + + len = strlen(value); + sethostname(value, len); + return EXIT_SUCCESS; } void usage() -- cgit v1.2.3-70-g09d2 From 452f87ace48b6cc710e2b50a749c818825455493 Mon Sep 17 00:00:00 2001 From: "A. Wilcox" Date: Sat, 23 Apr 2022 03:17:26 -0500 Subject: hostname: Fix file reading for setting node name This isn't exactly compatible with net-tools, but it is close. net-tools will buffer a line longer than 1024 characters (up to the next 63 characters). This implementation will break at the 1024th character and start a new block of 63 char names there. I sincerely hope nobody is actually using this weird, undefined behaviour for anything serious. --- hostname/hostname.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/hostname/hostname.c b/hostname/hostname.c index d19e4b8..b994a07 100644 --- a/hostname/hostname.c +++ b/hostname/hostname.c @@ -132,7 +132,7 @@ int do_set_nodename(bool file, const char *value) /* This is insane. There is no validation whatsoever. * However, strace on net-tools hostname(1) shows this to be * the exact algorithm used, so... */ - char buf[1024]; + char buf[1025]; int fildes = open(value, O_RDONLY); ssize_t result = 0; @@ -145,7 +145,8 @@ int do_set_nodename(bool file, const char *value) while(true) { char *curr = buf; - result = read(fildes, buf, sizeof buf); + memset(buf, 0, sizeof buf); + result = read(fildes, buf, sizeof buf - 1); switch(result) { case -1: @@ -158,14 +159,21 @@ int do_set_nodename(bool file, const char *value) } do { - len = result; + len = strnlen(curr, result); char *pos = strchr(curr, '\n'); if(pos) { len = pos - curr; } - sethostname(curr, (len > 63) ? 63 : len); - } while((curr = strchr(curr, '\n'))); + if(len == 0 || *curr == '#') continue; + while(len > 63) + { + sethostname(curr, 63); + len -= 63; + curr += 63; + } + sethostname(curr, len); + } while(curr = strchr(curr, '\n') + 1, curr != 0x1); } } -- cgit v1.2.3-70-g09d2 From e65c2374fe0b8fa952bab270213723454ec067b4 Mon Sep 17 00:00:00 2001 From: "A. Wilcox" Date: Sat, 23 Apr 2022 23:11:40 -0500 Subject: hostname: Fix logic Thanks to floatcomplex. --- hostname/hostname.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hostname/hostname.c b/hostname/hostname.c index b994a07..7dcef71 100644 --- a/hostname/hostname.c +++ b/hostname/hostname.c @@ -173,7 +173,7 @@ int do_set_nodename(bool file, const char *value) curr += 63; } sethostname(curr, len); - } while(curr = strchr(curr, '\n') + 1, curr != 0x1); + } while((curr = strchr(curr, '\n')) && curr++); } } -- cgit v1.2.3-70-g09d2