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