chiark / gitweb /
8f6a5b4316e4103c48e37cc5d681c63df0510267
[elogind.git] / src / basic / hostname-util.c
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
22 #include <sys/utsname.h>
23 #include <ctype.h>
24
25 #include "util.h"
26 #include "hostname-util.h"
27
28 /// UNNEEDED by elogind
29 #if 0
30 bool 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
45 char* 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 #endif // 0
56
57 static bool hostname_valid_char(char c) {
58         return
59                 (c >= 'a' && c <= 'z') ||
60                 (c >= 'A' && c <= 'Z') ||
61                 (c >= '0' && c <= '9') ||
62                 c == '-' ||
63                 c == '_' ||
64                 c == '.';
65 }
66
67 bool hostname_is_valid(const char *s) {
68         const char *p;
69         bool dot;
70
71         if (isempty(s))
72                 return false;
73
74         /* Doesn't accept empty hostnames, hostnames with trailing or
75          * leading dots, and hostnames with multiple dots in a
76          * sequence. Also ensures that the length stays below
77          * HOST_NAME_MAX. */
78
79         for (p = s, dot = true; *p; p++) {
80                 if (*p == '.') {
81                         if (dot)
82                                 return false;
83
84                         dot = true;
85                 } else {
86                         if (!hostname_valid_char(*p))
87                                 return false;
88
89                         dot = false;
90                 }
91         }
92
93         if (dot)
94                 return false;
95
96         if (p-s > HOST_NAME_MAX)
97                 return false;
98
99         return true;
100 }
101
102 char* hostname_cleanup(char *s, bool lowercase) {
103         char *p, *d;
104         bool dot;
105
106         assert(s);
107
108         for (p = s, d = s, dot = true; *p; p++) {
109                 if (*p == '.') {
110                         if (dot)
111                                 continue;
112
113                         *(d++) = '.';
114                         dot = true;
115                 } else if (hostname_valid_char(*p)) {
116                         *(d++) = lowercase ? tolower(*p) : *p;
117                         dot = false;
118                 }
119
120         }
121
122         if (dot && d > s)
123                 d[-1] = 0;
124         else
125                 *d = 0;
126
127         strshorten(s, HOST_NAME_MAX);
128
129         return s;
130 }
131
132 bool is_localhost(const char *hostname) {
133         assert(hostname);
134
135         /* This tries to identify local host and domain names
136          * described in RFC6761 plus the redhatism of .localdomain */
137
138         return streq(hostname, "localhost") ||
139                streq(hostname, "localhost.") ||
140                streq(hostname, "localdomain.") ||
141                streq(hostname, "localdomain") ||
142                endswith(hostname, ".localhost") ||
143                endswith(hostname, ".localhost.") ||
144                endswith(hostname, ".localdomain") ||
145                endswith(hostname, ".localdomain.");
146 }
147
148 /// UNNEEDED by elogind
149 #if 0
150 int sethostname_idempotent(const char *s) {
151         char buf[HOST_NAME_MAX + 1] = {};
152
153         assert(s);
154
155         if (gethostname(buf, sizeof(buf)) < 0)
156                 return -errno;
157
158         if (streq(buf, s))
159                 return 0;
160
161         if (sethostname(s, strlen(s)) < 0)
162                 return -errno;
163
164         return 1;
165 }
166
167 int read_hostname_config(const char *path, char **hostname) {
168         _cleanup_fclose_ FILE *f = NULL;
169         char l[LINE_MAX];
170         char *name = NULL;
171
172         assert(path);
173         assert(hostname);
174
175         f = fopen(path, "re");
176         if (!f)
177                 return -errno;
178
179         /* may have comments, ignore them */
180         FOREACH_LINE(l, f, return -errno) {
181                 truncate_nl(l);
182                 if (l[0] != '\0' && l[0] != '#') {
183                         /* found line with value */
184                         name = hostname_cleanup(l, false);
185                         name = strdup(name);
186                         if (!name)
187                                 return -ENOMEM;
188                         break;
189                 }
190         }
191
192         if (!name)
193                 /* no non-empty line found */
194                 return -ENOENT;
195
196         *hostname = name;
197         return 0;
198 }
199 #endif // 0