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