]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libudev/libudev-util.c
tree-wide: drop 'This file is part of systemd' blurb
[thirdparty/systemd.git] / src / libudev / libudev-util.c
CommitLineData
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 */
29int 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
91int 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 107size_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 153int 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 182int 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 241unsigned 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 */
247uint64_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}