1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2015 Lennart Poettering
12 #include <sys/utsname.h>
15 //#include "alloc-util.h"
17 //#include "fd-util.h"
19 #include "hostname-util.h"
21 #include "string-util.h"
23 #if 0 /// UNNEEDED by elogind
24 bool hostname_is_set(void) {
27 assert_se(uname(&u) >= 0);
29 if (isempty(u.nodename))
32 /* This is the built-in kernel default host name */
33 if (streq(u.nodename, "(none)"))
40 char* gethostname_malloc(void) {
43 /* This call tries to return something useful, either the actual hostname
44 * or it makes something up. The only reason it might fail is OOM.
45 * It might even return "localhost" if that's set. */
47 assert_se(uname(&u) >= 0);
49 if (isempty(u.nodename) || streq(u.nodename, "(none)"))
50 #if 0 /// elogind has no hostnamed and such nonsense
51 return strdup(FALLBACK_HOSTNAME);
53 return strdup("localhost");
56 return strdup(u.nodename);
59 #if 0 /// UNNEEDED by elogind
60 int gethostname_strict(char **ret) {
64 /* This call will rather fail than make up a name. It will not return "localhost" either. */
66 assert_se(uname(&u) >= 0);
68 if (isempty(u.nodename))
71 if (streq(u.nodename, "(none)"))
74 if (is_localhost(u.nodename))
77 k = strdup(u.nodename);
86 static bool hostname_valid_char(char c) {
88 (c >= 'a' && c <= 'z') ||
89 (c >= 'A' && c <= 'Z') ||
90 (c >= '0' && c <= '9') ||
91 IN_SET(c, '-', '_', '.');
95 * Check if s looks like a valid host name or FQDN. This does not do
96 * full DNS validation, but only checks if the name is composed of
97 * allowed characters and the length is not above the maximum allowed
98 * by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if
99 * allow_trailing_dot is true and at least two components are present
100 * in the name. Note that due to the restricted charset and length
101 * this call is substantially more conservative than
102 * dns_name_is_valid().
104 bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
112 /* Doesn't accept empty hostnames, hostnames with
113 * leading dots, and hostnames with multiple dots in a
114 * sequence. Also ensures that the length stays below
117 for (p = s, dot = true; *p; p++) {
125 if (!hostname_valid_char(*p))
132 if (dot && (n_dots < 2 || !allow_trailing_dot))
135 if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on
136 * Linux, but DNS allows domain names
137 * up to 255 characters */
143 #if 0 /// UNNEEDED by elogind
144 char* hostname_cleanup(char *s) {
150 strshorten(s, HOST_NAME_MAX);
152 for (p = s, d = s, dot = true; *p; p++) {
159 } else if (hostname_valid_char(*p)) {
174 bool is_localhost(const char *hostname) {
177 /* This tries to identify local host and domain names
178 * described in RFC6761 plus the redhatism of localdomain */
180 return strcaseeq(hostname, "localhost") ||
181 strcaseeq(hostname, "localhost.") ||
182 strcaseeq(hostname, "localhost.localdomain") ||
183 strcaseeq(hostname, "localhost.localdomain.") ||
184 endswith_no_case(hostname, ".localhost") ||
185 endswith_no_case(hostname, ".localhost.") ||
186 endswith_no_case(hostname, ".localhost.localdomain") ||
187 endswith_no_case(hostname, ".localhost.localdomain.");
190 #if 0 /// UNNEEDED by elogind
191 bool is_gateway_hostname(const char *hostname) {
194 /* This tries to identify the valid syntaxes for the our
195 * synthetic "gateway" host. */
198 strcaseeq(hostname, "_gateway") || strcaseeq(hostname, "_gateway.")
199 #if ENABLE_COMPAT_GATEWAY_HOSTNAME
200 || strcaseeq(hostname, "gateway") || strcaseeq(hostname, "gateway.")
205 int sethostname_idempotent(const char *s) {
206 char buf[HOST_NAME_MAX + 1] = {};
210 if (gethostname(buf, sizeof(buf)) < 0)
216 if (sethostname(s, strlen(s)) < 0)
222 int shorten_overlong(const char *s, char **ret) {
225 /* Shorten an overlong name to HOST_NAME_MAX or to the first dot,
226 * whatever comes earlier. */
234 if (hostname_is_valid(h, false)) {
243 strshorten(h, HOST_NAME_MAX);
245 if (!hostname_is_valid(h, false)) {
254 int read_etc_hostname_stream(FILE *f, char **ret) {
261 _cleanup_free_ char *line = NULL;
264 r = read_line(f, LONG_LINE_MAX, &line);
267 if (r == 0) /* EOF without any hostname? the file is empty, let's treat that exactly like no file at all: ENOENT */
272 /* File may have empty lines or comments, ignore them */
273 if (!IN_SET(*p, '\0', '#')) {
276 hostname_cleanup(p); /* normalize the hostname */
278 if (!hostname_is_valid(p, true)) /* check that the hostname we return is valid */
291 int read_etc_hostname(const char *path, char **ret) {
292 _cleanup_fclose_ FILE *f = NULL;
297 path = "/etc/hostname";
299 f = fopen(path, "re");
303 return read_etc_hostname_stream(f, ret);