]>
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"
14 #include "hostname-util.h"
16 #include "string-util.h"
18 bool hostname_is_set(void) {
21 assert_se(uname(&u
) >= 0);
23 if (isempty(u
.nodename
))
26 /* This is the built-in kernel default host name */
27 if (streq(u
.nodename
, "(none)"))
33 char* gethostname_malloc(void) {
36 /* This call tries to return something useful, either the actual hostname
37 * or it makes something up. The only reason it might fail is OOM.
38 * It might even return "localhost" if that's set. */
40 assert_se(uname(&u
) >= 0);
42 if (isempty(u
.nodename
) || streq(u
.nodename
, "(none)"))
43 return strdup(FALLBACK_HOSTNAME
);
45 return strdup(u
.nodename
);
48 int gethostname_strict(char **ret
) {
52 /* This call will rather fail than make up a name. It will not return "localhost" either. */
54 assert_se(uname(&u
) >= 0);
56 if (isempty(u
.nodename
))
59 if (streq(u
.nodename
, "(none)"))
62 if (is_localhost(u
.nodename
))
65 k
= strdup(u
.nodename
);
73 static bool hostname_valid_char(char c
) {
75 (c
>= 'a' && c
<= 'z') ||
76 (c
>= 'A' && c
<= 'Z') ||
77 (c
>= '0' && c
<= '9') ||
78 IN_SET(c
, '-', '_', '.');
82 * Check if s looks like a valid host name or FQDN. This does not do
83 * full DNS validation, but only checks if the name is composed of
84 * allowed characters and the length is not above the maximum allowed
85 * by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if
86 * allow_trailing_dot is true and at least two components are present
87 * in the name. Note that due to the restricted charset and length
88 * this call is substantially more conservative than
89 * dns_name_is_valid().
91 bool hostname_is_valid(const char *s
, bool allow_trailing_dot
) {
99 /* Doesn't accept empty hostnames, hostnames with
100 * leading dots, and hostnames with multiple dots in a
101 * sequence. Also ensures that the length stays below
104 for (p
= s
, dot
= true; *p
; p
++) {
112 if (!hostname_valid_char(*p
))
119 if (dot
&& (n_dots
< 2 || !allow_trailing_dot
))
122 if (p
-s
> HOST_NAME_MAX
) /* Note that HOST_NAME_MAX is 64 on
123 * Linux, but DNS allows domain names
124 * up to 255 characters */
130 char* hostname_cleanup(char *s
) {
136 strshorten(s
, HOST_NAME_MAX
);
138 for (p
= s
, d
= s
, dot
= true; *p
; p
++) {
145 } else if (hostname_valid_char(*p
)) {
159 bool is_localhost(const char *hostname
) {
162 /* This tries to identify local host and domain names
163 * described in RFC6761 plus the redhatism of localdomain */
165 return strcaseeq(hostname
, "localhost") ||
166 strcaseeq(hostname
, "localhost.") ||
167 strcaseeq(hostname
, "localhost.localdomain") ||
168 strcaseeq(hostname
, "localhost.localdomain.") ||
169 endswith_no_case(hostname
, ".localhost") ||
170 endswith_no_case(hostname
, ".localhost.") ||
171 endswith_no_case(hostname
, ".localhost.localdomain") ||
172 endswith_no_case(hostname
, ".localhost.localdomain.");
175 bool is_gateway_hostname(const char *hostname
) {
178 /* This tries to identify the valid syntaxes for the our
179 * synthetic "gateway" host. */
182 strcaseeq(hostname
, "_gateway") || strcaseeq(hostname
, "_gateway.")
183 #if ENABLE_COMPAT_GATEWAY_HOSTNAME
184 || strcaseeq(hostname
, "gateway") || strcaseeq(hostname
, "gateway.")
189 int sethostname_idempotent(const char *s
) {
190 char buf
[HOST_NAME_MAX
+ 1] = {};
194 if (gethostname(buf
, sizeof(buf
)) < 0)
200 if (sethostname(s
, strlen(s
)) < 0)
206 int shorten_overlong(const char *s
, char **ret
) {
209 /* Shorten an overlong name to HOST_NAME_MAX or to the first dot,
210 * whatever comes earlier. */
218 if (hostname_is_valid(h
, false)) {
227 strshorten(h
, HOST_NAME_MAX
);
229 if (!hostname_is_valid(h
, false)) {
238 int read_etc_hostname_stream(FILE *f
, char **ret
) {
245 _cleanup_free_
char *line
= NULL
;
248 r
= read_line(f
, LONG_LINE_MAX
, &line
);
251 if (r
== 0) /* EOF without any hostname? the file is empty, let's treat that exactly like no file at all: ENOENT */
256 /* File may have empty lines or comments, ignore them */
257 if (!IN_SET(*p
, '\0', '#')) {
260 hostname_cleanup(p
); /* normalize the hostname */
262 if (!hostname_is_valid(p
, true)) /* check that the hostname we return is valid */
275 int read_etc_hostname(const char *path
, char **ret
) {
276 _cleanup_fclose_
FILE *f
= NULL
;
281 path
= "/etc/hostname";
283 f
= fopen(path
, "re");
287 return read_etc_hostname_stream(f
, ret
);