]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
88a6477e KS |
2 | /*** |
3 | This file is part of systemd. | |
4 | ||
5 | Copyright 2008-2012 Kay Sievers <kay@vrfy.org> | |
6 | ||
7 | systemd is free software; you can redistribute it and/or modify it | |
8 | under the terms of the GNU Lesser General Public License as published by | |
9 | the Free Software Foundation; either version 2.1 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | systemd is distributed in the hope that it will be useful, but | |
13 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | Lesser General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU Lesser General Public License | |
18 | along with systemd; If not, see <http://www.gnu.org/licenses/>. | |
19 | ***/ | |
eb1f0e66 | 20 | |
07630cea | 21 | #include <ctype.h> |
eb1f0e66 | 22 | #include <errno.h> |
07630cea LP |
23 | #include <stddef.h> |
24 | #include <stdlib.h> | |
eb1f0e66 | 25 | #include <string.h> |
07630cea | 26 | #include <unistd.h> |
eb1f0e66 | 27 | |
b4bbcaa9 TA |
28 | #include "libudev.h" |
29 | ||
07630cea LP |
30 | #include "MurmurHash2.h" |
31 | #include "device-nodes.h" | |
eb1f0e66 | 32 | #include "libudev-private.h" |
7ccbd1ae | 33 | #include "syslog-util.h" |
02a36bc9 | 34 | #include "utf8.h" |
eb1f0e66 | 35 | |
0bbe8838 KS |
36 | /** |
37 | * SECTION:libudev-util | |
38 | * @short_description: utils | |
21dbe43a KS |
39 | * |
40 | * Utilities useful when dealing with devices and device node names. | |
0bbe8838 KS |
41 | */ |
42 | ||
9e13dbae KS |
43 | /* handle "[<SUBSYSTEM>/<KERNEL>]<attribute>" format */ |
44 | int util_resolve_subsys_kernel(struct udev *udev, const char *string, | |
45 | char *result, size_t maxsize, int read_value) | |
46 | { | |
47 | char temp[UTIL_PATH_SIZE]; | |
48 | char *subsys; | |
49 | char *sysname; | |
50 | struct udev_device *dev; | |
51 | char *attr; | |
52 | ||
53 | if (string[0] != '[') | |
54 | return -1; | |
55 | ||
d5a89d7d | 56 | strscpy(temp, sizeof(temp), string); |
9e13dbae KS |
57 | |
58 | subsys = &temp[1]; | |
59 | ||
60 | sysname = strchr(subsys, '/'); | |
61 | if (sysname == NULL) | |
62 | return -1; | |
63 | sysname[0] = '\0'; | |
64 | sysname = &sysname[1]; | |
65 | ||
66 | attr = strchr(sysname, ']'); | |
67 | if (attr == NULL) | |
68 | return -1; | |
69 | attr[0] = '\0'; | |
70 | attr = &attr[1]; | |
71 | if (attr[0] == '/') | |
72 | attr = &attr[1]; | |
73 | if (attr[0] == '\0') | |
74 | attr = NULL; | |
75 | ||
76 | if (read_value && attr == NULL) | |
77 | return -1; | |
78 | ||
79 | dev = udev_device_new_from_subsystem_sysname(udev, subsys, sysname); | |
80 | if (dev == NULL) | |
81 | return -1; | |
82 | ||
83 | if (read_value) { | |
84 | const char *val; | |
85 | ||
86 | val = udev_device_get_sysattr_value(dev, attr); | |
87 | if (val != NULL) | |
d5a89d7d | 88 | strscpy(result, maxsize, val); |
9e13dbae KS |
89 | else |
90 | result[0] = '\0'; | |
ff49bc32 | 91 | log_debug("value '[%s/%s]%s' is '%s'", subsys, sysname, attr, result); |
9e13dbae KS |
92 | } else { |
93 | size_t l; | |
94 | char *s; | |
95 | ||
96 | s = result; | |
d5a89d7d | 97 | l = strpcpyl(&s, maxsize, udev_device_get_syspath(dev), NULL); |
9e13dbae | 98 | if (attr != NULL) |
d5a89d7d | 99 | strpcpyl(&s, l, "/", attr, NULL); |
ff49bc32 | 100 | log_debug("path '[%s/%s]%s' is '%s'", subsys, sysname, attr, result); |
9e13dbae KS |
101 | } |
102 | udev_device_unref(dev); | |
103 | return 0; | |
104 | } | |
955d98c9 | 105 | |
7a01f11a KS |
106 | int util_log_priority(const char *priority) |
107 | { | |
912541b0 KS |
108 | char *endptr; |
109 | int prio; | |
110 | ||
ee7122c0 ZJS |
111 | prio = strtoul(priority, &endptr, 10); |
112 | if (endptr[0] == '\0' || isspace(endptr[0])) { | |
113 | if (prio >= 0 && prio <= 7) | |
114 | return prio; | |
115 | else | |
116 | return -ERANGE; | |
117 | } | |
ba7408a6 TG |
118 | |
119 | return log_level_from_string(priority); | |
7a01f11a KS |
120 | } |
121 | ||
065db052 | 122 | size_t util_path_encode(const char *src, char *dest, size_t size) |
7a01f11a | 123 | { |
912541b0 KS |
124 | size_t i, j; |
125 | ||
126 | for (i = 0, j = 0; src[i] != '\0'; i++) { | |
127 | if (src[i] == '/') { | |
128 | if (j+4 >= size) { | |
129 | j = 0; | |
130 | break; | |
131 | } | |
132 | memcpy(&dest[j], "\\x2f", 4); | |
133 | j += 4; | |
134 | } else if (src[i] == '\\') { | |
135 | if (j+4 >= size) { | |
136 | j = 0; | |
137 | break; | |
138 | } | |
139 | memcpy(&dest[j], "\\x5c", 4); | |
140 | j += 4; | |
141 | } else { | |
142 | if (j+1 >= size) { | |
143 | j = 0; | |
144 | break; | |
145 | } | |
146 | dest[j] = src[i]; | |
147 | j++; | |
148 | } | |
149 | } | |
150 | dest[j] = '\0'; | |
151 | return j; | |
7a01f11a KS |
152 | } |
153 | ||
be452683 DS |
154 | /* |
155 | * Copy from 'str' to 'to', while removing all leading and trailing whitespace, | |
156 | * and replacing each run of consecutive whitespace with a single underscore. | |
157 | * The chars from 'str' are copied up to the \0 at the end of the string, or | |
158 | * at most 'len' chars. This appends \0 to 'to', at the end of the copied | |
159 | * characters. | |
160 | * | |
161 | * If 'len' chars are copied into 'to', the final \0 is placed at len+1 | |
162 | * (i.e. 'to[len] = \0'), so the 'to' buffer must have at least len+1 | |
163 | * chars available. | |
164 | * | |
165 | * Note this may be called with 'str' == 'to', i.e. to replace whitespace | |
166 | * in-place in a buffer. This function can handle that situation. | |
167 | */ | |
0bbe8838 | 168 | int util_replace_whitespace(const char *str, char *to, size_t len) |
92f43136 | 169 | { |
912541b0 KS |
170 | size_t i, j; |
171 | ||
172 | /* strip trailing whitespace */ | |
173 | len = strnlen(str, len); | |
174 | while (len && isspace(str[len-1])) | |
175 | len--; | |
176 | ||
177 | /* strip leading whitespace */ | |
178 | i = 0; | |
4835f563 | 179 | while ((i < len) && isspace(str[i])) |
912541b0 KS |
180 | i++; |
181 | ||
182 | j = 0; | |
183 | while (i < len) { | |
184 | /* substitute multiple whitespace with a single '_' */ | |
185 | if (isspace(str[i])) { | |
186 | while (isspace(str[i])) | |
187 | i++; | |
188 | to[j++] = '_'; | |
189 | } | |
190 | to[j++] = str[i++]; | |
191 | } | |
192 | to[j] = '\0'; | |
a9d99b32 | 193 | return j; |
92f43136 KS |
194 | } |
195 | ||
75250977 | 196 | /* allow chars in whitelist, plain ascii, hex-escaping and valid utf8 */ |
0bbe8838 | 197 | int util_replace_chars(char *str, const char *white) |
75250977 | 198 | { |
912541b0 KS |
199 | size_t i = 0; |
200 | int replaced = 0; | |
201 | ||
202 | while (str[i] != '\0') { | |
203 | int len; | |
204 | ||
8f6ce71f | 205 | if (whitelisted_char_for_devnode(str[i], white)) { |
912541b0 KS |
206 | i++; |
207 | continue; | |
208 | } | |
209 | ||
210 | /* accept hex encoding */ | |
211 | if (str[i] == '\\' && str[i+1] == 'x') { | |
212 | i += 2; | |
213 | continue; | |
214 | } | |
215 | ||
216 | /* accept valid utf8 */ | |
217 | len = utf8_encoded_valid_unichar(&str[i]); | |
218 | if (len > 1) { | |
219 | i += len; | |
220 | continue; | |
221 | } | |
222 | ||
223 | /* if space is allowed, replace whitespace with ordinary space */ | |
224 | if (isspace(str[i]) && white != NULL && strchr(white, ' ') != NULL) { | |
225 | str[i] = ' '; | |
226 | i++; | |
227 | replaced++; | |
228 | continue; | |
229 | } | |
230 | ||
231 | /* everything else is replaced with '_' */ | |
232 | str[i] = '_'; | |
233 | i++; | |
234 | replaced++; | |
235 | } | |
236 | return replaced; | |
75250977 | 237 | } |
92f43136 KS |
238 | |
239 | /** | |
0bbe8838 | 240 | * udev_util_encode_string: |
92f43136 KS |
241 | * @str: input string to be encoded |
242 | * @str_enc: output string to store the encoded input string | |
243 | * @len: maximum size of the output string, which may be | |
244 | * four times as long as the input string | |
245 | * | |
246 | * Encode all potentially unsafe characters of a string to the | |
0bbe8838 | 247 | * corresponding 2 char hex value prefixed by '\x'. |
92f43136 KS |
248 | * |
249 | * Returns: 0 if the entire string was copied, non-zero otherwise. | |
250 | **/ | |
54cf0b7f | 251 | _public_ int udev_util_encode_string(const char *str, char *str_enc, size_t len) |
92f43136 | 252 | { |
8f6ce71f | 253 | return encode_devnode_name(str, str_enc, len); |
92f43136 | 254 | } |
4b09a2fc | 255 | |
c7dff03e | 256 | unsigned int util_string_hash32(const char *str) |
e14bdd88 | 257 | { |
57d0e6b2 | 258 | return MurmurHash2(str, strlen(str), 0); |
28460195 | 259 | } |
c7dff03e | 260 | |
28460195 KS |
261 | /* get a bunch of bit numbers out of the hash, and set the bits in our bit field */ |
262 | uint64_t util_string_bloom64(const char *str) | |
263 | { | |
912541b0 KS |
264 | uint64_t bits = 0; |
265 | unsigned int hash = util_string_hash32(str); | |
266 | ||
267 | bits |= 1LLU << (hash & 63); | |
268 | bits |= 1LLU << ((hash >> 6) & 63); | |
269 | bits |= 1LLU << ((hash >> 12) & 63); | |
270 | bits |= 1LLU << ((hash >> 18) & 63); | |
271 | return bits; | |
e14bdd88 | 272 | } |