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