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