]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/hostname-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
6 #include <sys/utsname.h>
9 #include "alloc-util.h"
12 #include "hostname-util.h"
14 #include "string-util.h"
16 bool hostname_is_set(void) {
19 assert_se(uname(&u
) >= 0);
21 if (isempty(u
.nodename
))
24 /* This is the built-in kernel default hostname */
25 if (streq(u
.nodename
, "(none)"))
31 char* gethostname_malloc(void) {
34 /* This call tries to return something useful, either the actual hostname
35 * or it makes something up. The only reason it might fail is OOM.
36 * It might even return "localhost" if that's set. */
38 assert_se(uname(&u
) >= 0);
40 if (isempty(u
.nodename
) || streq(u
.nodename
, "(none)"))
41 return strdup(FALLBACK_HOSTNAME
);
43 return strdup(u
.nodename
);
46 int gethostname_strict(char **ret
) {
50 /* This call will rather fail than make up a name. It will not return "localhost" either. */
52 assert_se(uname(&u
) >= 0);
54 if (isempty(u
.nodename
))
57 if (streq(u
.nodename
, "(none)"))
60 if (is_localhost(u
.nodename
))
63 k
= strdup(u
.nodename
);
71 bool valid_ldh_char(char c
) {
73 (c
>= 'a' && c
<= 'z') ||
74 (c
>= 'A' && c
<= 'Z') ||
75 (c
>= '0' && c
<= '9') ||
80 * Check if s looks like a valid hostname or FQDN. This does not do
81 * full DNS validation, but only checks if the name is composed of
82 * allowed characters and the length is not above the maximum allowed
83 * by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if
84 * allow_trailing_dot is true and at least two components are present
85 * in the name. Note that due to the restricted charset and length
86 * this call is substantially more conservative than
87 * dns_name_is_valid().
89 bool hostname_is_valid(const char *s
, bool allow_trailing_dot
) {
97 /* Doesn't accept empty hostnames, hostnames with
98 * leading dots, and hostnames with multiple dots in a
99 * sequence. Also ensures that the length stays below
102 for (p
= s
, dot
= hyphen
= true; *p
; p
++)
111 } else if (*p
== '-') {
119 if (!valid_ldh_char(*p
))
126 if (dot
&& (n_dots
< 2 || !allow_trailing_dot
))
131 if (p
-s
> HOST_NAME_MAX
) /* Note that HOST_NAME_MAX is 64 on
132 * Linux, but DNS allows domain names
133 * up to 255 characters */
139 char* hostname_cleanup(char *s
) {
145 for (p
= s
, d
= s
, dot
= hyphen
= true; *p
&& d
- s
< HOST_NAME_MAX
; p
++)
154 } else if (*p
== '-') {
162 } else if (valid_ldh_char(*p
)) {
168 if (d
> s
&& IN_SET(d
[-1], '-', '.'))
169 /* The dot can occur at most once, but we might have multiple
170 * hyphens, hence the loop */
177 bool is_localhost(const char *hostname
) {
180 /* This tries to identify local host and domain names
181 * described in RFC6761 plus the redhatism of localdomain */
183 return strcaseeq(hostname
, "localhost") ||
184 strcaseeq(hostname
, "localhost.") ||
185 strcaseeq(hostname
, "localhost.localdomain") ||
186 strcaseeq(hostname
, "localhost.localdomain.") ||
187 endswith_no_case(hostname
, ".localhost") ||
188 endswith_no_case(hostname
, ".localhost.") ||
189 endswith_no_case(hostname
, ".localhost.localdomain") ||
190 endswith_no_case(hostname
, ".localhost.localdomain.");
193 bool is_gateway_hostname(const char *hostname
) {
196 /* This tries to identify the valid syntaxes for the our
197 * synthetic "gateway" host. */
200 strcaseeq(hostname
, "_gateway") || strcaseeq(hostname
, "_gateway.")
201 #if ENABLE_COMPAT_GATEWAY_HOSTNAME
202 || strcaseeq(hostname
, "gateway") || strcaseeq(hostname
, "gateway.")
207 int sethostname_idempotent(const char *s
) {
208 char buf
[HOST_NAME_MAX
+ 1] = {};
212 if (gethostname(buf
, sizeof(buf
)) < 0)
218 if (sethostname(s
, strlen(s
)) < 0)
224 int shorten_overlong(const char *s
, char **ret
) {
227 /* Shorten an overlong name to HOST_NAME_MAX or to the first dot,
228 * whatever comes earlier. */
236 if (hostname_is_valid(h
, false)) {
245 strshorten(h
, HOST_NAME_MAX
);
247 if (!hostname_is_valid(h
, false)) {
256 int read_etc_hostname_stream(FILE *f
, char **ret
) {
263 _cleanup_free_
char *line
= NULL
;
266 r
= read_line(f
, LONG_LINE_MAX
, &line
);
269 if (r
== 0) /* EOF without any hostname? the file is empty, let's treat that exactly like no file at all: ENOENT */
274 /* File may have empty lines or comments, ignore them */
275 if (!IN_SET(*p
, '\0', '#')) {
278 hostname_cleanup(p
); /* normalize the hostname */
280 if (!hostname_is_valid(p
, true)) /* check that the hostname we return is valid */
293 int read_etc_hostname(const char *path
, char **ret
) {
294 _cleanup_fclose_
FILE *f
= NULL
;
299 path
= "/etc/hostname";
301 f
= fopen(path
, "re");
305 return read_etc_hostname_stream(f
, ret
);