]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/hostname-util.c
util-lib: split out fd-related operations into fd-util.[ch]
[thirdparty/systemd.git] / src / basic / hostname-util.c
CommitLineData
958b66ea
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2015 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
958b66ea 22#include <ctype.h>
07630cea 23#include <sys/utsname.h>
958b66ea 24
3ffd4af2
LP
25#include "fd-util.h"
26#include "hostname-util.h"
07630cea 27#include "string-util.h"
958b66ea 28#include "util.h"
958b66ea
LP
29
30bool hostname_is_set(void) {
31 struct utsname u;
32
33 assert_se(uname(&u) >= 0);
34
35 if (isempty(u.nodename))
36 return false;
37
38 /* This is the built-in kernel default host name */
39 if (streq(u.nodename, "(none)"))
40 return false;
41
42 return true;
43}
44
45char* gethostname_malloc(void) {
46 struct utsname u;
47
48 assert_se(uname(&u) >= 0);
49
50 if (isempty(u.nodename) || streq(u.nodename, "(none)"))
51 return strdup(u.sysname);
52
53 return strdup(u.nodename);
54}
55
56static bool hostname_valid_char(char c) {
57 return
58 (c >= 'a' && c <= 'z') ||
59 (c >= 'A' && c <= 'Z') ||
60 (c >= '0' && c <= '9') ||
61 c == '-' ||
62 c == '_' ||
63 c == '.';
64}
65
8fb49443 66/**
b59abc4d 67 * Check if s looks like a valid host name or FQDN. This does not do
8fb49443
ZJS
68 * full DNS validation, but only checks if the name is composed of
69 * allowed characters and the length is not above the maximum allowed
70 * by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if
b59abc4d
LP
71 * allow_trailing_dot is true and at least two components are present
72 * in the name. Note that due to the restricted charset and length
73 * this call is substantially more conservative than
74 * dns_domain_is_valid().
8fb49443 75 */
b59abc4d
LP
76bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
77 unsigned n_dots = 0;
958b66ea
LP
78 const char *p;
79 bool dot;
80
81 if (isempty(s))
82 return false;
83
8fb49443 84 /* Doesn't accept empty hostnames, hostnames with
958b66ea
LP
85 * leading dots, and hostnames with multiple dots in a
86 * sequence. Also ensures that the length stays below
87 * HOST_NAME_MAX. */
88
89 for (p = s, dot = true; *p; p++) {
90 if (*p == '.') {
91 if (dot)
92 return false;
93
94 dot = true;
b59abc4d 95 n_dots ++;
958b66ea
LP
96 } else {
97 if (!hostname_valid_char(*p))
98 return false;
99
100 dot = false;
101 }
102 }
103
b59abc4d 104 if (dot && (n_dots < 2 || !allow_trailing_dot))
958b66ea
LP
105 return false;
106
b59abc4d
LP
107 if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on
108 * Linux, but DNS allows domain names
109 * up to 255 characters */
958b66ea
LP
110 return false;
111
112 return true;
113}
114
ae691c1d 115char* hostname_cleanup(char *s) {
958b66ea
LP
116 char *p, *d;
117 bool dot;
118
119 assert(s);
120
121 for (p = s, d = s, dot = true; *p; p++) {
122 if (*p == '.') {
123 if (dot)
124 continue;
125
126 *(d++) = '.';
127 dot = true;
128 } else if (hostname_valid_char(*p)) {
ae691c1d 129 *(d++) = *p;
958b66ea
LP
130 dot = false;
131 }
132
133 }
134
135 if (dot && d > s)
136 d[-1] = 0;
137 else
138 *d = 0;
139
140 strshorten(s, HOST_NAME_MAX);
141
142 return s;
143}
144
145bool is_localhost(const char *hostname) {
146 assert(hostname);
147
148 /* This tries to identify local host and domain names
149 * described in RFC6761 plus the redhatism of .localdomain */
150
90365b04
ZJS
151 return strcaseeq(hostname, "localhost") ||
152 strcaseeq(hostname, "localhost.") ||
153 strcaseeq(hostname, "localdomain.") ||
154 strcaseeq(hostname, "localdomain") ||
155 endswith_no_case(hostname, ".localhost") ||
156 endswith_no_case(hostname, ".localhost.") ||
157 endswith_no_case(hostname, ".localdomain") ||
158 endswith_no_case(hostname, ".localdomain.");
958b66ea
LP
159}
160
46a5e0e7
LP
161bool is_gateway_hostname(const char *hostname) {
162 assert(hostname);
163
164 /* This tries to identify the valid syntaxes for the our
165 * synthetic "gateway" host. */
166
167 return
168 strcaseeq(hostname, "gateway") ||
169 strcaseeq(hostname, "gateway.");
170}
171
958b66ea
LP
172int sethostname_idempotent(const char *s) {
173 char buf[HOST_NAME_MAX + 1] = {};
174
175 assert(s);
176
177 if (gethostname(buf, sizeof(buf)) < 0)
178 return -errno;
179
180 if (streq(buf, s))
181 return 0;
182
183 if (sethostname(s, strlen(s)) < 0)
184 return -errno;
185
186 return 1;
187}
139e5336
MP
188
189int read_hostname_config(const char *path, char **hostname) {
190 _cleanup_fclose_ FILE *f = NULL;
191 char l[LINE_MAX];
192 char *name = NULL;
193
194 assert(path);
195 assert(hostname);
196
197 f = fopen(path, "re");
198 if (!f)
199 return -errno;
200
201 /* may have comments, ignore them */
202 FOREACH_LINE(l, f, return -errno) {
203 truncate_nl(l);
204 if (l[0] != '\0' && l[0] != '#') {
205 /* found line with value */
ae691c1d 206 name = hostname_cleanup(l);
139e5336
MP
207 name = strdup(name);
208 if (!name)
209 return -ENOMEM;
210 break;
211 }
212 }
213
214 if (!name)
215 /* no non-empty line found */
216 return -ENOENT;
217
218 *hostname = name;
219 return 0;
220}