]> git.ipfire.org Git - thirdparty/systemd.git/blame - udev/lib/libudev-util.c
edd_id: add cciss devices
[thirdparty/systemd.git] / udev / lib / libudev-util.c
CommitLineData
eb1f0e66
KS
1/*
2 * libudev - interface to udev device information
3 *
4 * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
5 *
4061ab9f
KS
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
eb1f0e66
KS
10 */
11
eb1f0e66
KS
12#include <stdio.h>
13#include <stdlib.h>
14#include <stddef.h>
15#include <unistd.h>
16#include <errno.h>
17#include <string.h>
18#include <dirent.h>
75250977 19#include <ctype.h>
93b0f384 20#include <fcntl.h>
eb1f0e66
KS
21#include <sys/stat.h>
22
23#include "libudev.h"
24#include "libudev-private.h"
eb1f0e66 25
5c5cad79 26static ssize_t get_sys_link(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size)
eb1f0e66 27{
3eb46ec6 28 char path[UTIL_PATH_SIZE];
eb1f0e66
KS
29 ssize_t len;
30 const char *pos;
31
8753fadf 32 util_strlcpy(path, syspath, sizeof(path));
3eb46ec6
KS
33 util_strlcat(path, "/", sizeof(path));
34 util_strlcat(path, slink, sizeof(path));
eb1f0e66
KS
35 len = readlink(path, path, sizeof(path));
36 if (len < 0 || len >= (ssize_t) sizeof(path))
37 return -1;
38 path[len] = '\0';
39 pos = strrchr(path, '/');
40 if (pos == NULL)
41 return -1;
42 pos = &pos[1];
86b57788 43 dbg(udev, "resolved link to: '%s'\n", pos);
5c5cad79 44 return util_strlcpy(value, pos, size);
eb1f0e66 45}
95d90c4f 46
8753fadf 47ssize_t util_get_sys_subsystem(struct udev *udev, const char *syspath, char *subsystem, size_t size)
95d90c4f 48{
8753fadf 49 return get_sys_link(udev, "subsystem", syspath, subsystem, size);
95d90c4f
KS
50}
51
8753fadf 52ssize_t util_get_sys_driver(struct udev *udev, const char *syspath, char *driver, size_t size)
95d90c4f 53{
8753fadf 54 return get_sys_link(udev, "driver", syspath, driver, size);
95d90c4f
KS
55}
56
8753fadf 57int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size)
b21b95d7 58{
3eb46ec6
KS
59 char link_target[UTIL_PATH_SIZE];
60
b21b95d7
KS
61 int len;
62 int i;
63 int back;
64
8753fadf 65 len = readlink(syspath, link_target, sizeof(link_target));
b21b95d7
KS
66 if (len <= 0)
67 return -1;
68 link_target[len] = '\0';
8753fadf 69 dbg(udev, "path link '%s' points to '%s'\n", syspath, link_target);
b21b95d7
KS
70
71 for (back = 0; strncmp(&link_target[back * 3], "../", 3) == 0; back++)
72 ;
8753fadf 73 dbg(udev, "base '%s', tail '%s', back %i\n", syspath, &link_target[back * 3], back);
b21b95d7 74 for (i = 0; i <= back; i++) {
8753fadf 75 char *pos = strrchr(syspath, '/');
b21b95d7
KS
76
77 if (pos == NULL)
78 return -1;
79 pos[0] = '\0';
80 }
8753fadf
KS
81 dbg(udev, "after moving back '%s'\n", syspath);
82 util_strlcat(syspath, "/", size);
83 util_strlcat(syspath, &link_target[back * 3], size);
b21b95d7
KS
84 return 0;
85}
7a01f11a 86
7a01f11a
KS
87int util_log_priority(const char *priority)
88{
89 char *endptr;
90 int prio;
91
92 prio = strtol(priority, &endptr, 10);
93 if (endptr[0] == '\0')
94 return prio;
95 if (strncasecmp(priority, "err", 3) == 0)
96 return LOG_ERR;
97 if (strcasecmp(priority, "info") == 0)
98 return LOG_INFO;
99 if (strcasecmp(priority, "debug") == 0)
100 return LOG_DEBUG;
101 return 0;
102}
103
3e5bafc9 104size_t util_path_encode(char *s, size_t size)
7a01f11a 105{
3e5bafc9 106 char t[(size * 4)+1];
7a01f11a
KS
107 size_t i, j;
108
3e5bafc9 109 for (i = 0, j = 0; s[i] != '\0' && i < size; i++) {
7a01f11a
KS
110 if (s[i] == '/') {
111 memcpy(&t[j], "\\x2f", 4);
112 j += 4;
113 } else if (s[i] == '\\') {
114 memcpy(&t[j], "\\x5c", 4);
115 j += 4;
116 } else {
117 t[j] = s[i];
118 j++;
119 }
120 }
3e5bafc9
KS
121 if (i >= size)
122 return 0;
123 if (j >= size)
124 return 0;
125 memcpy(s, t, j);
126 s[j] = '\0';
7a01f11a
KS
127 return j;
128}
129
130size_t util_path_decode(char *s)
131{
132 size_t i, j;
133
134 for (i = 0, j = 0; s[i] != '\0'; j++) {
135 if (memcmp(&s[i], "\\x2f", 4) == 0) {
136 s[j] = '/';
137 i += 4;
3e5bafc9 138 } else if (memcmp(&s[i], "\\x5c", 4) == 0) {
7a01f11a
KS
139 s[j] = '\\';
140 i += 4;
141 } else {
142 s[j] = s[i];
143 i++;
144 }
145 }
146 s[j] = '\0';
147 return j;
148}
149
150void util_remove_trailing_chars(char *path, char c)
151{
152 size_t len;
153
154 if (path == NULL)
155 return;
156 len = strlen(path);
157 while (len > 0 && path[len-1] == c)
158 path[--len] = '\0';
159}
3eb46ec6
KS
160
161size_t util_strlcpy(char *dst, const char *src, size_t size)
162{
163 size_t bytes = 0;
164 char *q = dst;
165 const char *p = src;
166 char ch;
167
168 while ((ch = *p++)) {
169 if (bytes+1 < size)
170 *q++ = ch;
171 bytes++;
172 }
173
174 /* If size == 0 there is no space for a final null... */
175 if (size)
176 *q = '\0';
177 return bytes;
178}
179
180size_t util_strlcat(char *dst, const char *src, size_t size)
181{
182 size_t bytes = 0;
183 char *q = dst;
184 const char *p = src;
185 char ch;
186
187 while (bytes < size && *q) {
188 q++;
189 bytes++;
190 }
191 if (bytes == size)
192 return (bytes + strlen(src));
193
194 while ((ch = *p++)) {
195 if (bytes+1 < size)
196 *q++ = ch;
197 bytes++;
198 }
199
200 *q = '\0';
201 return bytes;
202}
75250977
KS
203
204/* count of characters used to encode one unicode char */
205static int utf8_encoded_expected_len(const char *str)
206{
207 unsigned char c = (unsigned char)str[0];
208
209 if (c < 0x80)
210 return 1;
211 if ((c & 0xe0) == 0xc0)
212 return 2;
213 if ((c & 0xf0) == 0xe0)
214 return 3;
215 if ((c & 0xf8) == 0xf0)
216 return 4;
217 if ((c & 0xfc) == 0xf8)
218 return 5;
219 if ((c & 0xfe) == 0xfc)
220 return 6;
221 return 0;
222}
223
224/* decode one unicode char */
225static int utf8_encoded_to_unichar(const char *str)
226{
227 int unichar;
228 int len;
229 int i;
230
231 len = utf8_encoded_expected_len(str);
232 switch (len) {
233 case 1:
234 return (int)str[0];
235 case 2:
236 unichar = str[0] & 0x1f;
237 break;
238 case 3:
239 unichar = (int)str[0] & 0x0f;
240 break;
241 case 4:
242 unichar = (int)str[0] & 0x07;
243 break;
244 case 5:
245 unichar = (int)str[0] & 0x03;
246 break;
247 case 6:
248 unichar = (int)str[0] & 0x01;
249 break;
250 default:
251 return -1;
252 }
253
254 for (i = 1; i < len; i++) {
255 if (((int)str[i] & 0xc0) != 0x80)
256 return -1;
257 unichar <<= 6;
258 unichar |= (int)str[i] & 0x3f;
259 }
260
261 return unichar;
262}
263
264/* expected size used to encode one unicode char */
265static int utf8_unichar_to_encoded_len(int unichar)
266{
267 if (unichar < 0x80)
268 return 1;
269 if (unichar < 0x800)
270 return 2;
271 if (unichar < 0x10000)
272 return 3;
273 if (unichar < 0x200000)
274 return 4;
275 if (unichar < 0x4000000)
276 return 5;
277 return 6;
278}
279
280/* check if unicode char has a valid numeric range */
281static int utf8_unichar_valid_range(int unichar)
282{
283 if (unichar > 0x10ffff)
284 return 0;
285 if ((unichar & 0xfffff800) == 0xd800)
286 return 0;
287 if ((unichar > 0xfdcf) && (unichar < 0xfdf0))
288 return 0;
289 if ((unichar & 0xffff) == 0xffff)
290 return 0;
291 return 1;
292}
293
294/* validate one encoded unicode char and return its length */
295static int utf8_encoded_valid_unichar(const char *str)
296{
297 int len;
298 int unichar;
299 int i;
300
301 len = utf8_encoded_expected_len(str);
302 if (len == 0)
303 return -1;
304
305 /* ascii is valid */
306 if (len == 1)
307 return 1;
308
309 /* check if expected encoded chars are available */
310 for (i = 0; i < len; i++)
311 if ((str[i] & 0x80) != 0x80)
312 return -1;
313
314 unichar = utf8_encoded_to_unichar(str);
315
316 /* check if encoded length matches encoded value */
317 if (utf8_unichar_to_encoded_len(unichar) != len)
318 return -1;
319
320 /* check if value has valid range */
321 if (!utf8_unichar_valid_range(unichar))
322 return -1;
323
324 return len;
325}
326
92f43136
KS
327int udev_util_replace_whitespace(const char *str, char *to, size_t len)
328{
329 size_t i, j;
330
331 /* strip trailing whitespace */
332 len = strnlen(str, len);
333 while (len && isspace(str[len-1]))
334 len--;
335
336 /* strip leading whitespace */
337 i = 0;
338 while (isspace(str[i]) && (i < len))
339 i++;
340
341 j = 0;
342 while (i < len) {
343 /* substitute multiple whitespace with a single '_' */
344 if (isspace(str[i])) {
345 while (isspace(str[i]))
346 i++;
347 to[j++] = '_';
348 }
349 to[j++] = str[i++];
350 }
351 to[j] = '\0';
352 return 0;
353}
354
355static int is_whitelisted(char c, const char *white)
356{
357 if ((c >= '0' && c <= '9') ||
358 (c >= 'A' && c <= 'Z') ||
359 (c >= 'a' && c <= 'z') ||
360 strchr("#+-.:=@_", c) != NULL ||
361 (white != NULL && strchr(white, c) != NULL))
362 return 1;
363 return 0;
364}
365
75250977 366/* allow chars in whitelist, plain ascii, hex-escaping and valid utf8 */
92f43136 367int udev_util_replace_chars(char *str, const char *white)
75250977
KS
368{
369 size_t i = 0;
370 int replaced = 0;
371
372 while (str[i] != '\0') {
373 int len;
374
92f43136 375 if (is_whitelisted(str[i], white)) {
75250977
KS
376 i++;
377 continue;
378 }
379
380 /* accept hex encoding */
381 if (str[i] == '\\' && str[i+1] == 'x') {
382 i += 2;
383 continue;
384 }
385
386 /* accept valid utf8 */
387 len = utf8_encoded_valid_unichar(&str[i]);
388 if (len > 1) {
389 i += len;
390 continue;
391 }
392
393 /* if space is allowed, replace whitespace with ordinary space */
bbfaec2b 394 if (isspace(str[i]) && white != NULL && strchr(white, ' ') != NULL) {
75250977
KS
395 str[i] = ' ';
396 i++;
397 replaced++;
398 continue;
399 }
400
401 /* everything else is replaced with '_' */
402 str[i] = '_';
403 i++;
404 replaced++;
405 }
75250977
KS
406 return replaced;
407}
92f43136
KS
408
409/**
410 * util_encode_string:
411 * @str: input string to be encoded
412 * @str_enc: output string to store the encoded input string
413 * @len: maximum size of the output string, which may be
414 * four times as long as the input string
415 *
416 * Encode all potentially unsafe characters of a string to the
417 * corresponding hex value prefixed by '\x'.
418 *
419 * Returns: 0 if the entire string was copied, non-zero otherwise.
420 **/
421int udev_util_encode_string(const char *str, char *str_enc, size_t len)
422{
423 size_t i, j;
424
425 if (str == NULL || str_enc == NULL || len == 0)
426 return -1;
427
428 str_enc[0] = '\0';
429 for (i = 0, j = 0; str[i] != '\0'; i++) {
430 int seqlen;
431
432 seqlen = utf8_encoded_valid_unichar(&str[i]);
433 if (seqlen > 1) {
434 memcpy(&str_enc[j], &str[i], seqlen);
435 j += seqlen;
436 i += (seqlen-1);
437 } else if (str[i] == '\\' || !is_whitelisted(str[i], NULL)) {
438 sprintf(&str_enc[j], "\\x%02x", (unsigned char) str[i]);
439 j += 4;
440 } else {
441 str_enc[j] = str[i];
442 j++;
443 }
444 if (j+3 >= len)
445 goto err;
446 }
447 str_enc[j] = '\0';
448 return 0;
449err:
450 return -1;
451}
4b09a2fc
AJ
452
453void util_set_fd_cloexec(int fd)
454{
455 int flags;
456
457 flags = fcntl(fd, F_GETFD);
458 if (flags < 0)
459 flags = FD_CLOEXEC;
460 else
461 flags |= FD_CLOEXEC;
462 fcntl(fd, F_SETFD, flags);
463}
e14bdd88
KS
464
465unsigned int util_crc32(const unsigned char *buf, size_t len)
466{
467 unsigned int crc;
468 const unsigned char *end;
469 static const unsigned int crc32_table[256] = {
470 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
471 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
472 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
473 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
474 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
475 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
476 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
477 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
478 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
479 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
480 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
481 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
482 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
483 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
484 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
485 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
486 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
487 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
488 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
489 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
490 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
491 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
492 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
493 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
494 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
495 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
496 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
497 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
498 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
499 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
500 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
501 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
502 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
503 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
504 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
505 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
506 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
507 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
508 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
509 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
510 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
511 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
512 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
513 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
514 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
515 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
516 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
517 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
518 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
519 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
520 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
521 0x2d02ef8d
522 };
523
524 crc = 0xffffffff;
525 for (end = buf + len; buf < end; ++buf)
526 crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
527 return ~crc;
528}