1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
6 #include <sys/utsname.h>
9 #include "alloc-util.h"
13 #include "hostname-setup.h"
14 #include "hostname-util.h"
17 #include "proc-cmdline.h"
18 #include "string-table.h"
19 #include "string-util.h"
22 static int sethostname_idempotent_full(const char *s
, bool really
) {
23 char buf
[HOST_NAME_MAX
+ 1] = {};
27 if (gethostname(buf
, sizeof(buf
) - 1) < 0)
34 sethostname(s
, strlen(s
)) < 0)
40 int sethostname_idempotent(const char *s
) {
41 return sethostname_idempotent_full(s
, true);
44 bool get_hostname_filtered(char ret
[static HOST_NAME_MAX
+ 1]) {
45 char buf
[HOST_NAME_MAX
+ 1] = {};
47 /* Returns true if we got a good hostname, false otherwise. */
49 if (gethostname(buf
, sizeof(buf
) - 1) < 0)
50 return false; /* This can realistically only fail with ENAMETOOLONG.
51 * Let's treat that case the same as an invalid hostname. */
56 /* This is the built-in kernel default hostname */
57 if (streq(buf
, "(none)"))
60 memcpy(ret
, buf
, sizeof buf
);
64 int shorten_overlong(const char *s
, char **ret
) {
67 /* Shorten an overlong name to HOST_NAME_MAX or to the first dot,
68 * whatever comes earlier. */
76 if (hostname_is_valid(h
, 0)) {
85 strshorten(h
, HOST_NAME_MAX
);
87 if (!hostname_is_valid(h
, 0)) {
96 int read_etc_hostname_stream(FILE *f
, char **ret
) {
103 _cleanup_free_
char *line
= NULL
;
106 r
= read_line(f
, LONG_LINE_MAX
, &line
);
109 if (r
== 0) /* EOF without any hostname? the file is empty, let's treat that exactly like no file at all: ENOENT */
114 /* File may have empty lines or comments, ignore them */
115 if (!IN_SET(*p
, '\0', '#')) {
118 hostname_cleanup(p
); /* normalize the hostname */
120 if (!hostname_is_valid(p
, VALID_HOSTNAME_TRAILING_DOT
)) /* check that the hostname we return is valid */
133 int read_etc_hostname(const char *path
, char **ret
) {
134 _cleanup_fclose_
FILE *f
= NULL
;
139 path
= "/etc/hostname";
141 f
= fopen(path
, "re");
145 return read_etc_hostname_stream(f
, ret
);
148 void hostname_update_source_hint(const char *hostname
, HostnameSource source
) {
151 /* Why save the value and not just create a flag file? This way we will
152 * notice if somebody sets the hostname directly (not going through hostnamed).
155 if (source
== HOSTNAME_DEFAULT
) {
156 r
= write_string_file("/run/systemd/default-hostname", hostname
,
157 WRITE_STRING_FILE_CREATE
| WRITE_STRING_FILE_ATOMIC
);
159 log_warning_errno(r
, "Failed to create \"/run/systemd/default-hostname\": %m");
161 unlink_or_warn("/run/systemd/default-hostname");
164 int hostname_setup(bool really
) {
165 _cleanup_free_
char *b
= NULL
;
166 const char *hn
= NULL
;
167 HostnameSource source
;
171 r
= proc_cmdline_get_key("systemd.hostname", 0, &b
);
173 log_warning_errno(r
, "Failed to retrieve system hostname from kernel command line, ignoring: %m");
175 if (hostname_is_valid(b
, true)) {
177 source
= HOSTNAME_TRANSIENT
;
179 log_warning("Hostname specified on kernel command line is invalid, ignoring: %s", b
);
185 r
= read_etc_hostname(NULL
, &b
);
190 log_warning_errno(r
, "Failed to read configured hostname: %m");
193 source
= HOSTNAME_STATIC
;
198 /* Don't override the hostname if it is already set and not explicitly configured */
200 char buf
[HOST_NAME_MAX
+ 1] = {};
201 if (get_hostname_filtered(buf
)) {
202 log_debug("No hostname configured, leaving existing hostname <%s> in place.", buf
);
207 log_info("No hostname configured, using default hostname.");
209 hn
= b
= get_default_hostname();
213 source
= HOSTNAME_DEFAULT
;
217 r
= sethostname_idempotent_full(hn
, really
);
219 return log_warning_errno(r
, "Failed to set hostname to <%s>: %m", hn
);
221 log_debug("Hostname was already set to <%s>.", hn
);
223 log_info("Hostname %s to <%s>.",
224 really
? "set" : "would have been set",
228 hostname_update_source_hint(hn
, source
);
233 static const char* const hostname_source_table
[] = {
234 [HOSTNAME_STATIC
] = "static",
235 [HOSTNAME_TRANSIENT
] = "transient",
236 [HOSTNAME_DEFAULT
] = "default",
239 DEFINE_STRING_TABLE_LOOKUP(hostname_source
, HostnameSource
);