]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/hostname-util.c
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"
19 #include "hostname-util.h"
21 #include "string-util.h"
23 bool hostname_is_set(void) {
26 assert_se(uname(&u
) >= 0);
28 if (isempty(u
.nodename
))
31 /* This is the built-in kernel default host name */
32 if (streq(u
.nodename
, "(none)"))
38 char* gethostname_malloc(void) {
41 /* This call tries to return something useful, either the actual hostname
42 * or it makes something up. The only reason it might fail is OOM.
43 * It might even return "localhost" if that's set. */
45 assert_se(uname(&u
) >= 0);
47 if (isempty(u
.nodename
) || streq(u
.nodename
, "(none)"))
48 return strdup(FALLBACK_HOSTNAME
);
50 return strdup(u
.nodename
);
53 int gethostname_strict(char **ret
) {
57 /* This call will rather fail than make up a name. It will not return "localhost" either. */
59 assert_se(uname(&u
) >= 0);
61 if (isempty(u
.nodename
))
64 if (streq(u
.nodename
, "(none)"))
67 if (is_localhost(u
.nodename
))
70 k
= strdup(u
.nodename
);
78 static bool hostname_valid_char(char c
) {
80 (c
>= 'a' && c
<= 'z') ||
81 (c
>= 'A' && c
<= 'Z') ||
82 (c
>= '0' && c
<= '9') ||
83 IN_SET(c
, '-', '_', '.');
87 * Check if s looks like a valid host name or FQDN. This does not do
88 * full DNS validation, but only checks if the name is composed of
89 * allowed characters and the length is not above the maximum allowed
90 * by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if
91 * allow_trailing_dot is true and at least two components are present
92 * in the name. Note that due to the restricted charset and length
93 * this call is substantially more conservative than
94 * dns_name_is_valid().
96 bool hostname_is_valid(const char *s
, bool allow_trailing_dot
) {
104 /* Doesn't accept empty hostnames, hostnames with
105 * leading dots, and hostnames with multiple dots in a
106 * sequence. Also ensures that the length stays below
109 for (p
= s
, dot
= true; *p
; p
++) {
117 if (!hostname_valid_char(*p
))
124 if (dot
&& (n_dots
< 2 || !allow_trailing_dot
))
127 if (p
-s
> HOST_NAME_MAX
) /* Note that HOST_NAME_MAX is 64 on
128 * Linux, but DNS allows domain names
129 * up to 255 characters */
135 char* hostname_cleanup(char *s
) {
141 strshorten(s
, HOST_NAME_MAX
);
143 for (p
= s
, d
= s
, dot
= true; *p
; p
++) {
150 } else if (hostname_valid_char(*p
)) {
164 bool is_localhost(const char *hostname
) {
167 /* This tries to identify local host and domain names
168 * described in RFC6761 plus the redhatism of localdomain */
170 return strcaseeq(hostname
, "localhost") ||
171 strcaseeq(hostname
, "localhost.") ||
172 strcaseeq(hostname
, "localhost.localdomain") ||
173 strcaseeq(hostname
, "localhost.localdomain.") ||
174 endswith_no_case(hostname
, ".localhost") ||
175 endswith_no_case(hostname
, ".localhost.") ||
176 endswith_no_case(hostname
, ".localhost.localdomain") ||
177 endswith_no_case(hostname
, ".localhost.localdomain.");
180 bool is_gateway_hostname(const char *hostname
) {
183 /* This tries to identify the valid syntaxes for the our
184 * synthetic "gateway" host. */
187 strcaseeq(hostname
, "_gateway") || strcaseeq(hostname
, "_gateway.")
188 #if ENABLE_COMPAT_GATEWAY_HOSTNAME
189 || strcaseeq(hostname
, "gateway") || strcaseeq(hostname
, "gateway.")
194 int sethostname_idempotent(const char *s
) {
195 char buf
[HOST_NAME_MAX
+ 1] = {};
199 if (gethostname(buf
, sizeof(buf
)) < 0)
205 if (sethostname(s
, strlen(s
)) < 0)
211 int shorten_overlong(const char *s
, char **ret
) {
214 /* Shorten an overlong name to HOST_NAME_MAX or to the first dot,
215 * whatever comes earlier. */
223 if (hostname_is_valid(h
, false)) {
232 strshorten(h
, HOST_NAME_MAX
);
234 if (!hostname_is_valid(h
, false)) {
243 int read_etc_hostname_stream(FILE *f
, char **ret
) {
250 _cleanup_free_
char *line
= NULL
;
253 r
= read_line(f
, LONG_LINE_MAX
, &line
);
256 if (r
== 0) /* EOF without any hostname? the file is empty, let's treat that exactly like no file at all: ENOENT */
261 /* File may have empty lines or comments, ignore them */
262 if (!IN_SET(*p
, '\0', '#')) {
265 hostname_cleanup(p
); /* normalize the hostname */
267 if (!hostname_is_valid(p
, true)) /* check that the hostname we return is valid */
280 int read_etc_hostname(const char *path
, char **ret
) {
281 _cleanup_fclose_
FILE *f
= NULL
;
286 path
= "/etc/hostname";
288 f
= fopen(path
, "re");
292 return read_etc_hostname_stream(f
, ret
);