chiark / gitweb /
Prep v221: Update and clean up build system to sync with upstream
[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 bool hostname_is_set(void) {
29         struct utsname u;
30
31         assert_se(uname(&u) >= 0);
32
33         if (isempty(u.nodename))
34                 return false;
35
36         /* This is the built-in kernel default host name */
37         if (streq(u.nodename, "(none)"))
38                 return false;
39
40         return true;
41 }
42
43 char* gethostname_malloc(void) {
44         struct utsname u;
45
46         assert_se(uname(&u) >= 0);
47
48         if (isempty(u.nodename) || streq(u.nodename, "(none)"))
49                 return strdup(u.sysname);
50
51         return strdup(u.nodename);
52 }
53
54 static bool hostname_valid_char(char c) {
55         return
56                 (c >= 'a' && c <= 'z') ||
57                 (c >= 'A' && c <= 'Z') ||
58                 (c >= '0' && c <= '9') ||
59                 c == '-' ||
60                 c == '_' ||
61                 c == '.';
62 }
63
64 bool hostname_is_valid(const char *s) {
65         const char *p;
66         bool dot;
67
68         if (isempty(s))
69                 return false;
70
71         /* Doesn't accept empty hostnames, hostnames with trailing or
72          * leading dots, and hostnames with multiple dots in a
73          * sequence. Also ensures that the length stays below
74          * HOST_NAME_MAX. */
75
76         for (p = s, dot = true; *p; p++) {
77                 if (*p == '.') {
78                         if (dot)
79                                 return false;
80
81                         dot = true;
82                 } else {
83                         if (!hostname_valid_char(*p))
84                                 return false;
85
86                         dot = false;
87                 }
88         }
89
90         if (dot)
91                 return false;
92
93         if (p-s > HOST_NAME_MAX)
94                 return false;
95
96         return true;
97 }
98
99 char* hostname_cleanup(char *s, bool lowercase) {
100         char *p, *d;
101         bool dot;
102
103         assert(s);
104
105         for (p = s, d = s, dot = true; *p; p++) {
106                 if (*p == '.') {
107                         if (dot)
108                                 continue;
109
110                         *(d++) = '.';
111                         dot = true;
112                 } else if (hostname_valid_char(*p)) {
113                         *(d++) = lowercase ? tolower(*p) : *p;
114                         dot = false;
115                 }
116
117         }
118
119         if (dot && d > s)
120                 d[-1] = 0;
121         else
122                 *d = 0;
123
124         strshorten(s, HOST_NAME_MAX);
125
126         return s;
127 }
128
129 bool is_localhost(const char *hostname) {
130         assert(hostname);
131
132         /* This tries to identify local host and domain names
133          * described in RFC6761 plus the redhatism of .localdomain */
134
135         return streq(hostname, "localhost") ||
136                streq(hostname, "localhost.") ||
137                streq(hostname, "localdomain.") ||
138                streq(hostname, "localdomain") ||
139                endswith(hostname, ".localhost") ||
140                endswith(hostname, ".localhost.") ||
141                endswith(hostname, ".localdomain") ||
142                endswith(hostname, ".localdomain.");
143 }
144
145 int sethostname_idempotent(const char *s) {
146         char buf[HOST_NAME_MAX + 1] = {};
147
148         assert(s);
149
150         if (gethostname(buf, sizeof(buf)) < 0)
151                 return -errno;
152
153         if (streq(buf, s))
154                 return 0;
155
156         if (sethostname(s, strlen(s)) < 0)
157                 return -errno;
158
159         return 1;
160 }
161
162 int read_hostname_config(const char *path, char **hostname) {
163         _cleanup_fclose_ FILE *f = NULL;
164         char l[LINE_MAX];
165         char *name = NULL;
166
167         assert(path);
168         assert(hostname);
169
170         f = fopen(path, "re");
171         if (!f)
172                 return -errno;
173
174         /* may have comments, ignore them */
175         FOREACH_LINE(l, f, return -errno) {
176                 truncate_nl(l);
177                 if (l[0] != '\0' && l[0] != '#') {
178                         /* found line with value */
179                         name = hostname_cleanup(l, false);
180                         name = strdup(name);
181                         if (!name)
182                                 return -ENOMEM;
183                         break;
184                 }
185         }
186
187         if (!name)
188                 /* no non-empty line found */
189                 return -ENOENT;
190
191         *hostname = name;
192         return 0;
193 }