1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2015 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include <sys/utsname.h>
28 //#include "alloc-util.h"
30 //#include "fd-util.h"
32 #include "hostname-util.h"
34 #include "string-util.h"
36 #if 0 /// UNNEEDED by elogind
37 bool hostname_is_set(void) {
40 assert_se(uname(&u) >= 0);
42 if (isempty(u.nodename))
45 /* This is the built-in kernel default host name */
46 if (streq(u.nodename, "(none)"))
53 char* gethostname_malloc(void) {
56 /* This call tries to return something useful, either the actual hostname
57 * or it makes something up. The only reason it might fail is OOM.
58 * It might even return "localhost" if that's set. */
60 assert_se(uname(&u) >= 0);
62 if (isempty(u.nodename) || streq(u.nodename, "(none)"))
63 #if 0 /// elogind has no hostnamed and such nonsense
64 return strdup(FALLBACK_HOSTNAME);
66 return strdup("localhost");
69 return strdup(u.nodename);
72 #if 0 /// UNNEEDED by elogind
73 int gethostname_strict(char **ret) {
77 /* This call will rather fail than make up a name. It will not return "localhost" either. */
79 assert_se(uname(&u) >= 0);
81 if (isempty(u.nodename))
84 if (streq(u.nodename, "(none)"))
87 if (is_localhost(u.nodename))
90 k = strdup(u.nodename);
99 static bool hostname_valid_char(char c) {
101 (c >= 'a' && c <= 'z') ||
102 (c >= 'A' && c <= 'Z') ||
103 (c >= '0' && c <= '9') ||
104 IN_SET(c, '-', '_', '.');
108 * Check if s looks like a valid host name or FQDN. This does not do
109 * full DNS validation, but only checks if the name is composed of
110 * allowed characters and the length is not above the maximum allowed
111 * by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if
112 * allow_trailing_dot is true and at least two components are present
113 * in the name. Note that due to the restricted charset and length
114 * this call is substantially more conservative than
115 * dns_name_is_valid().
117 bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
125 /* Doesn't accept empty hostnames, hostnames with
126 * leading dots, and hostnames with multiple dots in a
127 * sequence. Also ensures that the length stays below
130 for (p = s, dot = true; *p; p++) {
138 if (!hostname_valid_char(*p))
145 if (dot && (n_dots < 2 || !allow_trailing_dot))
148 if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on
149 * Linux, but DNS allows domain names
150 * up to 255 characters */
156 #if 0 /// UNNEEDED by elogind
157 char* hostname_cleanup(char *s) {
163 strshorten(s, HOST_NAME_MAX);
165 for (p = s, d = s, dot = true; *p; p++) {
172 } else if (hostname_valid_char(*p)) {
187 bool is_localhost(const char *hostname) {
190 /* This tries to identify local host and domain names
191 * described in RFC6761 plus the redhatism of localdomain */
193 return strcaseeq(hostname, "localhost") ||
194 strcaseeq(hostname, "localhost.") ||
195 strcaseeq(hostname, "localhost.localdomain") ||
196 strcaseeq(hostname, "localhost.localdomain.") ||
197 endswith_no_case(hostname, ".localhost") ||
198 endswith_no_case(hostname, ".localhost.") ||
199 endswith_no_case(hostname, ".localhost.localdomain") ||
200 endswith_no_case(hostname, ".localhost.localdomain.");
203 #if 0 /// UNNEEDED by elogind
204 bool is_gateway_hostname(const char *hostname) {
207 /* This tries to identify the valid syntaxes for the our
208 * synthetic "gateway" host. */
211 strcaseeq(hostname, "_gateway") || strcaseeq(hostname, "_gateway.")
212 #if ENABLE_COMPAT_GATEWAY_HOSTNAME
213 || strcaseeq(hostname, "gateway") || strcaseeq(hostname, "gateway.")
218 int sethostname_idempotent(const char *s) {
219 char buf[HOST_NAME_MAX + 1] = {};
223 if (gethostname(buf, sizeof(buf)) < 0)
229 if (sethostname(s, strlen(s)) < 0)
235 int shorten_overlong(const char *s, char **ret) {
238 /* Shorten an overlong name to HOST_NAME_MAX or to the first dot,
239 * whatever comes earlier. */
247 if (hostname_is_valid(h, false)) {
256 strshorten(h, HOST_NAME_MAX);
258 if (!hostname_is_valid(h, false)) {
267 int read_etc_hostname_stream(FILE *f, char **ret) {
274 _cleanup_free_ char *line = NULL;
277 r = read_line(f, LONG_LINE_MAX, &line);
280 if (r == 0) /* EOF without any hostname? the file is empty, let's treat that exactly like no file at all: ENOENT */
285 /* File may have empty lines or comments, ignore them */
286 if (!IN_SET(*p, '\0', '#')) {
289 hostname_cleanup(p); /* normalize the hostname */
291 if (!hostname_is_valid(p, true)) /* check that the hostname we return is valid */
304 int read_etc_hostname(const char *path, char **ret) {
305 _cleanup_fclose_ FILE *f = NULL;
310 path = "/etc/hostname";
312 f = fopen(path, "re");
316 return read_etc_hostname_stream(f, ret);