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