]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libudev/libudev-util.c
libudev-util: adjust type of returned value by util_string_hash32()
[thirdparty/systemd.git] / src / libudev / libudev-util.c
CommitLineData
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
26int 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 87int 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 102size_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 147int 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 175int 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 232uint32_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 237uint64_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}