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