]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/hostname-setup.c
hostnamed,shared/hostname-setup: expose the origin of the current hostname
[thirdparty/systemd.git] / src / shared / hostname-setup.c
CommitLineData
e2054217
ZJS
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include <errno.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <sys/utsname.h>
7#include <unistd.h>
8
9#include "alloc-util.h"
10#include "fd-util.h"
11#include "fileio.h"
60e4fb42 12#include "fs-util.h"
e2054217
ZJS
13#include "hostname-setup.h"
14#include "hostname-util.h"
15#include "log.h"
16#include "macro.h"
17#include "proc-cmdline.h"
60e4fb42 18#include "string-table.h"
e2054217
ZJS
19#include "string-util.h"
20#include "util.h"
21
b6fad306 22static int sethostname_idempotent_full(const char *s, bool really) {
e2054217
ZJS
23 char buf[HOST_NAME_MAX + 1] = {};
24
25 assert(s);
26
39ede7cc 27 if (gethostname(buf, sizeof(buf) - 1) < 0)
e2054217
ZJS
28 return -errno;
29
30 if (streq(buf, s))
31 return 0;
32
b6fad306
ZJS
33 if (really &&
34 sethostname(s, strlen(s)) < 0)
e2054217
ZJS
35 return -errno;
36
37 return 1;
38}
39
b6fad306
ZJS
40int sethostname_idempotent(const char *s) {
41 return sethostname_idempotent_full(s, true);
42}
43
60e4fb42
ZJS
44bool get_hostname_filtered(char ret[static HOST_NAME_MAX + 1]) {
45 char buf[HOST_NAME_MAX + 1] = {};
46
47 /* Returns true if we got a good hostname, false otherwise. */
48
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. */
52
53 if (isempty(buf))
54 return false;
55
56 /* This is the built-in kernel default hostname */
57 if (streq(buf, "(none)"))
58 return false;
59
60 memcpy(ret, buf, sizeof buf);
61 return true;
62}
63
e2054217
ZJS
64int shorten_overlong(const char *s, char **ret) {
65 char *h, *p;
66
67 /* Shorten an overlong name to HOST_NAME_MAX or to the first dot,
68 * whatever comes earlier. */
69
70 assert(s);
71
72 h = strdup(s);
73 if (!h)
74 return -ENOMEM;
75
76 if (hostname_is_valid(h, 0)) {
77 *ret = h;
78 return 0;
79 }
80
81 p = strchr(h, '.');
82 if (p)
83 *p = 0;
84
85 strshorten(h, HOST_NAME_MAX);
86
87 if (!hostname_is_valid(h, 0)) {
88 free(h);
89 return -EDOM;
90 }
91
92 *ret = h;
93 return 1;
94}
95
96int read_etc_hostname_stream(FILE *f, char **ret) {
97 int r;
98
99 assert(f);
100 assert(ret);
101
102 for (;;) {
103 _cleanup_free_ char *line = NULL;
104 char *p;
105
106 r = read_line(f, LONG_LINE_MAX, &line);
107 if (r < 0)
108 return r;
109 if (r == 0) /* EOF without any hostname? the file is empty, let's treat that exactly like no file at all: ENOENT */
110 return -ENOENT;
111
112 p = strstrip(line);
113
114 /* File may have empty lines or comments, ignore them */
115 if (!IN_SET(*p, '\0', '#')) {
116 char *copy;
117
118 hostname_cleanup(p); /* normalize the hostname */
119
120 if (!hostname_is_valid(p, VALID_HOSTNAME_TRAILING_DOT)) /* check that the hostname we return is valid */
121 return -EBADMSG;
122
123 copy = strdup(p);
124 if (!copy)
125 return -ENOMEM;
126
127 *ret = copy;
128 return 0;
129 }
130 }
131}
132
133int read_etc_hostname(const char *path, char **ret) {
134 _cleanup_fclose_ FILE *f = NULL;
135
136 assert(ret);
137
138 if (!path)
139 path = "/etc/hostname";
140
141 f = fopen(path, "re");
142 if (!f)
143 return -errno;
144
145 return read_etc_hostname_stream(f, ret);
e2054217
ZJS
146}
147
60e4fb42
ZJS
148void hostname_update_source_hint(const char *hostname, HostnameSource source) {
149 int r;
e2054217 150
60e4fb42
ZJS
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).
153 */
e2054217 154
60e4fb42
ZJS
155 if (source == HOSTNAME_FALLBACK) {
156 r = write_string_file("/run/systemd/fallback-hostname", hostname,
157 WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_ATOMIC);
158 if (r < 0)
159 log_warning_errno(r, "Failed to create \"/run/systemd/fallback-hostname\": %m");
160 } else
161 unlink_or_warn("/run/systemd/fallback-hostname");
e2054217
ZJS
162}
163
b6fad306 164int hostname_setup(bool really) {
e2054217
ZJS
165 _cleanup_free_ char *b = NULL;
166 const char *hn = NULL;
60e4fb42 167 HostnameSource source;
e2054217
ZJS
168 bool enoent = false;
169 int r;
170
171 r = proc_cmdline_get_key("systemd.hostname", 0, &b);
172 if (r < 0)
173 log_warning_errno(r, "Failed to retrieve system hostname from kernel command line, ignoring: %m");
174 else if (r > 0) {
60e4fb42 175 if (hostname_is_valid(b, true)) {
e2054217 176 hn = b;
60e4fb42
ZJS
177 source = HOSTNAME_TRANSIENT;
178 } else {
e2054217
ZJS
179 log_warning("Hostname specified on kernel command line is invalid, ignoring: %s", b);
180 b = mfree(b);
181 }
182 }
183
184 if (!hn) {
185 r = read_etc_hostname(NULL, &b);
186 if (r < 0) {
187 if (r == -ENOENT)
188 enoent = true;
189 else
190 log_warning_errno(r, "Failed to read configured hostname: %m");
60e4fb42 191 } else {
e2054217 192 hn = b;
60e4fb42
ZJS
193 source = HOSTNAME_STATIC;
194 }
e2054217
ZJS
195 }
196
197 if (isempty(hn)) {
198 /* Don't override the hostname if it is already set and not explicitly configured */
60e4fb42
ZJS
199
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);
e2054217 203 return 0;
60e4fb42 204 }
e2054217
ZJS
205
206 if (enoent)
60e4fb42 207 log_info("No hostname configured, using fallback hostname.");
e2054217
ZJS
208
209 hn = FALLBACK_HOSTNAME;
60e4fb42
ZJS
210 source = HOSTNAME_FALLBACK;
211
e2054217
ZJS
212 }
213
b6fad306 214 r = sethostname_idempotent_full(hn, really);
e2054217
ZJS
215 if (r < 0)
216 return log_warning_errno(r, "Failed to set hostname to <%s>: %m", hn);
b6fad306
ZJS
217 if (r == 0)
218 log_debug("Hostname was already set to <%s>.", hn);
219 else
220 log_info("Hostname %s to <%s>.",
221 really ? "set" : "would have been set",
222 hn);
223
60e4fb42
ZJS
224 if (really)
225 hostname_update_source_hint(hn, source);
226
b6fad306 227 return r;
e2054217 228}
60e4fb42
ZJS
229
230static const char* const hostname_source_table[] = {
231 [HOSTNAME_STATIC] = "static",
232 [HOSTNAME_TRANSIENT] = "transient",
233 [HOSTNAME_FALLBACK] = "fallback",
234};
235
236DEFINE_STRING_TABLE_LOOKUP_TO_STRING(hostname_source, HostnameSource);