]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/hostname-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
7 #include <sys/utsname.h>
10 #include "alloc-util.h"
13 #include "hostname-util.h"
15 #include "string-util.h"
17 bool hostname_is_set(void) {
20 assert_se(uname(&u
) >= 0);
22 if (isempty(u
.nodename
))
25 /* This is the built-in kernel default host name */
26 if (streq(u
.nodename
, "(none)"))
32 char* gethostname_malloc(void) {
35 /* This call tries to return something useful, either the actual hostname
36 * or it makes something up. The only reason it might fail is OOM.
37 * It might even return "localhost" if that's set. */
39 assert_se(uname(&u
) >= 0);
41 if (isempty(u
.nodename
) || streq(u
.nodename
, "(none)"))
42 return strdup(FALLBACK_HOSTNAME
);
44 return strdup(u
.nodename
);
47 int gethostname_strict(char **ret
) {
51 /* This call will rather fail than make up a name. It will not return "localhost" either. */
53 assert_se(uname(&u
) >= 0);
55 if (isempty(u
.nodename
))
58 if (streq(u
.nodename
, "(none)"))
61 if (is_localhost(u
.nodename
))
64 k
= strdup(u
.nodename
);
72 static bool hostname_valid_char(char c
) {
74 (c
>= 'a' && c
<= 'z') ||
75 (c
>= 'A' && c
<= 'Z') ||
76 (c
>= '0' && c
<= '9') ||
77 IN_SET(c
, '-', '_', '.');
81 * Check if s looks like a valid host name or FQDN. This does not do
82 * full DNS validation, but only checks if the name is composed of
83 * allowed characters and the length is not above the maximum allowed
84 * by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if
85 * allow_trailing_dot is true and at least two components are present
86 * in the name. Note that due to the restricted charset and length
87 * this call is substantially more conservative than
88 * dns_name_is_valid().
90 bool hostname_is_valid(const char *s
, bool allow_trailing_dot
) {
98 /* Doesn't accept empty hostnames, hostnames with
99 * leading dots, and hostnames with multiple dots in a
100 * sequence. Also ensures that the length stays below
103 for (p
= s
, dot
= true; *p
; p
++) {
111 if (!hostname_valid_char(*p
))
118 if (dot
&& (n_dots
< 2 || !allow_trailing_dot
))
121 if (p
-s
> HOST_NAME_MAX
) /* Note that HOST_NAME_MAX is 64 on
122 * Linux, but DNS allows domain names
123 * up to 255 characters */
129 char* hostname_cleanup(char *s
) {
135 strshorten(s
, HOST_NAME_MAX
);
137 for (p
= s
, d
= s
, dot
= true; *p
; p
++) {
144 } else if (hostname_valid_char(*p
)) {
158 bool is_localhost(const char *hostname
) {
161 /* This tries to identify local host and domain names
162 * described in RFC6761 plus the redhatism of localdomain */
164 return strcaseeq(hostname
, "localhost") ||
165 strcaseeq(hostname
, "localhost.") ||
166 strcaseeq(hostname
, "localhost.localdomain") ||
167 strcaseeq(hostname
, "localhost.localdomain.") ||
168 endswith_no_case(hostname
, ".localhost") ||
169 endswith_no_case(hostname
, ".localhost.") ||
170 endswith_no_case(hostname
, ".localhost.localdomain") ||
171 endswith_no_case(hostname
, ".localhost.localdomain.");
174 bool is_gateway_hostname(const char *hostname
) {
177 /* This tries to identify the valid syntaxes for the our
178 * synthetic "gateway" host. */
181 strcaseeq(hostname
, "_gateway") || strcaseeq(hostname
, "_gateway.")
182 #if ENABLE_COMPAT_GATEWAY_HOSTNAME
183 || strcaseeq(hostname
, "gateway") || strcaseeq(hostname
, "gateway.")
188 int sethostname_idempotent(const char *s
) {
189 char buf
[HOST_NAME_MAX
+ 1] = {};
193 if (gethostname(buf
, sizeof(buf
)) < 0)
199 if (sethostname(s
, strlen(s
)) < 0)
205 int shorten_overlong(const char *s
, char **ret
) {
208 /* Shorten an overlong name to HOST_NAME_MAX or to the first dot,
209 * whatever comes earlier. */
217 if (hostname_is_valid(h
, false)) {
226 strshorten(h
, HOST_NAME_MAX
);
228 if (!hostname_is_valid(h
, false)) {
237 int read_etc_hostname_stream(FILE *f
, char **ret
) {
244 _cleanup_free_
char *line
= NULL
;
247 r
= read_line(f
, LONG_LINE_MAX
, &line
);
250 if (r
== 0) /* EOF without any hostname? the file is empty, let's treat that exactly like no file at all: ENOENT */
255 /* File may have empty lines or comments, ignore them */
256 if (!IN_SET(*p
, '\0', '#')) {
259 hostname_cleanup(p
); /* normalize the hostname */
261 if (!hostname_is_valid(p
, true)) /* check that the hostname we return is valid */
274 int read_etc_hostname(const char *path
, char **ret
) {
275 _cleanup_fclose_
FILE *f
= NULL
;
280 path
= "/etc/hostname";
282 f
= fopen(path
, "re");
286 return read_etc_hostname_stream(f
, ret
);