]> git.ipfire.org Git - thirdparty/systemd.git/blame - udev_rules.c
[PATCH] klibc: strlcpy/strlcat - don't alter destination if size == 0
[thirdparty/systemd.git] / udev_rules.c
CommitLineData
2232cac8 1/*
e5e322bc 2 * udev_rules.c
2232cac8
GKH
3 *
4 * Userspace devfs
5 *
6 * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
fd9efc00 7 * Copyright (C) 2003-2005 Kay Sievers <kay.sievers@vrfy.org>
2232cac8
GKH
8 *
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation version 2 of the License.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 */
24
25#include <stddef.h>
26#include <stdlib.h>
27#include <string.h>
28#include <stdio.h>
29#include <fcntl.h>
30#include <ctype.h>
31#include <unistd.h>
32#include <errno.h>
c27e6911 33#include <sys/wait.h>
dac056aa 34#include <sys/stat.h>
2232cac8 35
c80da508 36#include "libsysfs/sysfs/libsysfs.h"
2232cac8 37#include "list.h"
63f61c5c 38#include "udev_libc_wrapper.h"
2232cac8 39#include "udev.h"
9af5bb2f 40#include "udev_utils.h"
2232cac8 41#include "udev_version.h"
54988802 42#include "logging.h"
e5e322bc 43#include "udev_rules.h"
02fa9ae5 44#include "udev_db.h"
2232cac8 45
a27cd06c 46
9f1da361
KS
47/* compare string with pattern (supports * ? [0-9] [!A-Z]) */
48static int strcmp_pattern(const char *p, const char *s)
c124eafa 49{
8a08e4b1
KS
50 if (s[0] == '\0') {
51 while (p[0] == '*')
9f1da361 52 p++;
8a08e4b1 53 return (p[0] != '\0');
9f1da361 54 }
8a08e4b1 55 switch (p[0]) {
9f1da361
KS
56 case '[':
57 {
58 int not = 0;
59 p++;
8a08e4b1 60 if (p[0] == '!') {
9f1da361
KS
61 not = 1;
62 p++;
63 }
8a08e4b1 64 while ((p[0] != '\0') && (p[0] != ']')) {
9f1da361
KS
65 int match = 0;
66 if (p[1] == '-') {
8a08e4b1 67 if ((s[0] >= p[0]) && (s[0] <= p[2]))
9f1da361
KS
68 match = 1;
69 p += 3;
70 } else {
8a08e4b1 71 match = (p[0] == s[0]);
9f1da361
KS
72 p++;
73 }
74 if (match ^ not) {
8a08e4b1 75 while ((p[0] != '\0') && (p[0] != ']'))
9f1da361 76 p++;
8a08e4b1
KS
77 if (p[0] == ']')
78 return strcmp_pattern(p+1, s+1);
9f1da361
KS
79 }
80 }
81 }
82 break;
83 case '*':
84 if (strcmp_pattern(p, s+1))
85 return strcmp_pattern(p+1, s);
86 return 0;
87 case '\0':
8a08e4b1 88 if (s[0] == '\0') {
9f1da361
KS
89 return 0;
90 }
91 break;
92 default:
8a08e4b1 93 if ((p[0] == s[0]) || (p[0] == '?'))
9f1da361
KS
94 return strcmp_pattern(p+1, s+1);
95 break;
96 }
97 return 1;
c124eafa
KS
98}
99
a27cd06c
KS
100/* extract possible {attr} and move str behind it */
101static char *get_format_attribute(char **str)
102{
103 char *pos;
104 char *attr = NULL;
105
106 if (*str[0] == '{') {
107 pos = strchr(*str, '}');
108 if (pos == NULL) {
6b493a20 109 err("missing closing brace for format");
a27cd06c
KS
110 return NULL;
111 }
112 pos[0] = '\0';
113 attr = *str+1;
114 *str = pos+1;
115 dbg("attribute='%s', str='%s'", attr, *str);
116 }
117 return attr;
118}
119
120/* extract possible format length and move str behind it*/
121static int get_format_len(char **str)
122{
123 int num;
124 char *tail;
125
126 if (isdigit(*str[0])) {
127 num = (int) strtoul(*str, &tail, 10);
aebef544 128 if (num > 0) {
a27cd06c
KS
129 *str = tail;
130 dbg("format length=%i", num);
131 return num;
132 } else {
6b493a20 133 err("format parsing error '%s'", *str);
a27cd06c
KS
134 }
135 }
136 return -1;
137}
138
0a8dd7f3
DZ
139/** Finds the lowest positive N such that <name>N isn't present in
140 * $(udevroot) either as a file or a symlink.
141 *
142 * @param name Name to check for
143 * @return 0 if <name> didn't exist and N otherwise.
144 */
2b41e68a 145static int find_free_number(struct udevice *udev, const char *name)
0a8dd7f3 146{
63f61c5c
KS
147 char devpath[PATH_SIZE];
148 char filename[PATH_SIZE];
2b41e68a 149 int num = 0;
0a8dd7f3 150
63f61c5c 151 strlcpy(filename, name, sizeof(filename));
0a8dd7f3 152 while (1) {
2b41e68a 153 dbg("look for existing node '%s'", filename);
63f61c5c 154 if (udev_db_search_name(devpath, sizeof(devpath), filename) != 0) {
2b41e68a
KS
155 dbg("free num=%d", num);
156 return num;
157 }
0a8dd7f3 158
2b41e68a
KS
159 num++;
160 if (num > 1000) {
161 info("find_free_number gone crazy (num=%d), aborted", num);
162 return -1;
163 }
63f61c5c
KS
164 snprintf(filename, sizeof(filename), "%s%d", name, num);
165 filename[sizeof(filename)-1] = '\0';
2b41e68a 166 }
0a8dd7f3
DZ
167}
168
18614ab2
KS
169static int find_sysfs_attribute(struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device,
170 const char *name, char *value, size_t len)
171{
172 struct sysfs_attribute *tmpattr;
173
174 dbg("look for device attribute '%s'", name);
175 if (class_dev) {
176 tmpattr = sysfs_get_classdev_attr(class_dev, name);
177 if (tmpattr)
178 goto attr_found;
179 }
180 if (sysfs_device) {
181 tmpattr = sysfs_get_device_attr(sysfs_device, name);
182 if (tmpattr)
183 goto attr_found;
184 }
185
186 return -1;
187
188attr_found:
189 strlcpy(value, tmpattr->value, len);
190 remove_trailing_char(value, '\n');
191
192 dbg("found attribute '%s'", tmpattr->path);
193 return 0;
194}
195
831f800d 196static void apply_format(struct udevice *udev, char *string, size_t maxsize,
b821330f 197 struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device)
f3b04a2e 198{
63f61c5c
KS
199 char temp[PATH_SIZE];
200 char temp2[PATH_SIZE];
03fd7a3a 201 char *tail, *pos, *cpos, *attr, *rest;
63ead27c 202 int len;
88f09368 203 int i;
a27cd06c 204 char c;
0a8dd7f3 205 unsigned int next_free_number;
69aa6dfb 206 struct sysfs_class_device *class_dev_parent;
f3b04a2e 207
8ffb636f 208 pos = string;
f3b04a2e 209 while (1) {
a36a3c3a
KS
210 pos = strchr(pos, '%');
211 if (pos == NULL)
a27cd06c 212 break;
b1c5e333 213
a36a3c3a
KS
214 pos[0] = '\0';
215 tail = pos+1;
216 len = get_format_len(&tail);
217 c = tail[0];
63f61c5c 218 strlcpy(temp, tail+1, sizeof(temp));
a36a3c3a
KS
219 tail = temp;
220 dbg("format=%c, string='%s', tail='%s'",c , string, tail);
a27cd06c
KS
221 attr = get_format_attribute(&tail);
222
223 switch (c) {
c1ab0461 224 case 'p':
63f61c5c 225 strlcat(string, udev->devpath, maxsize);
c1ab0461
KS
226 dbg("substitute kernel name '%s'", udev->kernel_name);
227 break;
a27cd06c 228 case 'b':
63f61c5c 229 strlcat(string, udev->bus_id, maxsize);
a27cd06c
KS
230 dbg("substitute bus_id '%s'", udev->bus_id);
231 break;
232 case 'k':
63f61c5c 233 strlcat(string, udev->kernel_name, maxsize);
a27cd06c
KS
234 dbg("substitute kernel name '%s'", udev->kernel_name);
235 break;
236 case 'n':
63f61c5c 237 strlcat(string, udev->kernel_number, maxsize);
a27cd06c 238 dbg("substitute kernel number '%s'", udev->kernel_number);
f3b04a2e 239 break;
a27cd06c 240 case 'm':
03fd7a3a 241 sprintf(temp2, "%d", minor(udev->devt));
63f61c5c 242 strlcat(string, temp2, maxsize);
03fd7a3a 243 dbg("substitute minor number '%s'", temp2);
a27cd06c 244 break;
c58e36c0 245 case 'M':
03fd7a3a 246 sprintf(temp2, "%d", major(udev->devt));
63f61c5c 247 strlcat(string, temp2, maxsize);
03fd7a3a 248 dbg("substitute major number '%s'", temp2);
a27cd06c
KS
249 break;
250 case 'c':
b821330f 251 if (udev->program_result[0] == '\0')
f3b04a2e 252 break;
88f09368 253 /* get part part of the result string */
63ead27c 254 i = 0;
88f09368 255 if (attr != NULL)
558f80ba 256 i = strtoul(attr, &rest, 10);
88f09368 257 if (i > 0) {
03fd7a3a
KS
258 dbg("request part #%d of result string", i);
259 cpos = udev->program_result;
260 while (--i) {
261 while (cpos[0] != '\0' && !isspace(cpos[0]))
262 cpos++;
263 while (isspace(cpos[0]))
264 cpos++;
b1c5e333 265 }
9fe3f9a9 266 if (i > 0) {
6b493a20 267 err("requested part of result string not found");
9fe3f9a9 268 break;
a27cd06c 269 }
63f61c5c 270 strlcpy(temp2, cpos, sizeof(temp2));
03fd7a3a
KS
271 /* %{2+}c copies the whole string from the second part on */
272 if (rest[0] != '+') {
273 cpos = strchr(temp2, ' ');
274 if (cpos)
275 cpos[0] = '\0';
276 }
63f61c5c 277 strlcat(string, temp2, maxsize);
27c3403d 278 dbg("substitute part of result string '%s'", temp2);
a27cd06c 279 } else {
63f61c5c 280 strlcat(string, udev->program_result, maxsize);
a27cd06c 281 dbg("substitute result string '%s'", udev->program_result);
f3b04a2e 282 }
f3b04a2e 283 break;
a27cd06c 284 case 's':
5e39f90b 285 if (attr == NULL) {
a27cd06c 286 dbg("missing attribute");
5e39f90b
KS
287 break;
288 }
18614ab2 289 if (find_sysfs_attribute(class_dev, sysfs_device, attr, temp2, sizeof(temp2)) != 0) {
6b493a20 290 dbg("sysfs attribute '%s' not found", attr);
5e39f90b
KS
291 break;
292 }
18614ab2
KS
293 /* strip trailing whitespace of sysfs value */
294 i = strlen(temp2);
295 while (i > 0 && isspace(temp2[i-1]))
296 temp2[--i] = '\0';
297 replace_untrusted_chars(temp2);
298 strlcat(string, temp2, maxsize);
299 dbg("substitute sysfs value '%s'", temp2);
a27cd06c
KS
300 break;
301 case '%':
63f61c5c 302 strlcat(string, "%", maxsize);
a36a3c3a 303 pos++;
a27cd06c 304 break;
0a8dd7f3
DZ
305 case 'e':
306 next_free_number = find_free_number(udev, string);
307 if (next_free_number > 0) {
2b41e68a 308 sprintf(temp2, "%d", next_free_number);
63f61c5c 309 strlcat(string, temp2, maxsize);
0a8dd7f3
DZ
310 }
311 break;
69aa6dfb 312 case 'P':
8f2f6e42
KS
313 if (!class_dev)
314 break;
69aa6dfb
KS
315 class_dev_parent = sysfs_get_classdev_parent(class_dev);
316 if (class_dev_parent != NULL) {
317 struct udevice udev_parent;
318
319 dbg("found parent '%s', get the node name", class_dev_parent->path);
e48fc108 320 udev_init_device(&udev_parent, NULL, NULL);
69aa6dfb 321 /* lookup the name in the udev_db with the DEVPATH of the parent */
e48fc108 322 if (udev_db_get_device(&udev_parent, &class_dev_parent->path[strlen(sysfs_path)]) == 0) {
63f61c5c 323 strlcat(string, udev_parent.name, maxsize);
69aa6dfb
KS
324 dbg("substitute parent node name'%s'", udev_parent.name);
325 } else
326 dbg("parent not found in database");
e48fc108 327 udev_cleanup_device(&udev_parent);
69aa6dfb
KS
328 }
329 break;
c1ab0461
KS
330 case 'N':
331 if (udev->tmp_node[0] == '\0') {
332 dbg("create temporary device node for callout");
63f61c5c
KS
333 snprintf(udev->tmp_node, sizeof(udev->tmp_node), "%s/.tmp-%u-%u",
334 udev_root, major(udev->devt), minor(udev->devt));
335 udev->tmp_node[sizeof(udev->tmp_node)-1] = '\0';
7e720bd4 336 udev_make_node(udev, udev->tmp_node, udev->devt, 0600, 0, 0);
c1ab0461 337 }
63f61c5c 338 strlcat(string, udev->tmp_node, maxsize);
c1ab0461
KS
339 dbg("substitute temporary device node name '%s'", udev->tmp_node);
340 break;
69aa6dfb 341 case 'r':
63f61c5c 342 strlcat(string, udev_root, maxsize);
69aa6dfb
KS
343 dbg("substitute udev_root '%s'", udev_root);
344 break;
a27cd06c 345 default:
6b493a20 346 err("unknown substitution type '%%%c'", c);
a27cd06c
KS
347 break;
348 }
63ead27c
KS
349 /* truncate to specified length */
350 if (len > 0)
351 pos[len] = '\0';
352
63f61c5c 353 strlcat(string, tail, maxsize);
f3b04a2e
GKH
354 }
355}
356
af4b05d4 357static int execute_program(struct udevice *udev, const char *path, char *value, int len)
c27e6911
PM
358{
359 int retval;
35b38379 360 int count;
c27e6911
PM
361 int status;
362 int fds[2];
363 pid_t pid;
20524642 364 char *pos;
63f61c5c
KS
365 char arg[PATH_SIZE];
366 char *argv[(sizeof(arg) / 2) + 1];
bc434511 367 int i;
c27e6911 368
63f61c5c 369 strlcpy(arg, path, sizeof(arg));
35b38379
KS
370 i = 0;
371 if (strchr(path, ' ')) {
35b38379
KS
372 pos = arg;
373 while (pos != NULL) {
374 if (pos[0] == '\'') {
375 /* don't separate if in apostrophes */
376 pos++;
377 argv[i] = strsep(&pos, "\'");
a75e2c14 378 while (pos && pos[0] == ' ')
35b38379 379 pos++;
a75e2c14 380 } else {
35b38379
KS
381 argv[i] = strsep(&pos, " ");
382 }
383 dbg("arg[%i] '%s'", i, argv[i]);
384 i++;
385 }
f608f8ac
KS
386 argv[i] = NULL;
387 dbg("execute '%s' with parsed arguments", arg);
388 } else {
389 argv[0] = arg;
af4b05d4 390 argv[1] = udev->subsystem;
f608f8ac
KS
391 argv[2] = NULL;
392 dbg("execute '%s' with subsystem '%s' argument", arg, argv[1]);
35b38379 393 }
f608f8ac 394
c27e6911
PM
395 retval = pipe(fds);
396 if (retval != 0) {
6b493a20 397 err("pipe failed");
c27e6911
PM
398 return -1;
399 }
35b38379 400
c27e6911 401 pid = fork();
2a25816f
KS
402 switch(pid) {
403 case 0:
18614ab2 404 /* child dup2 write side of pipe to STDOUT */
6e3e3c34 405 dup2(fds[1], STDOUT_FILENO);
f608f8ac 406 retval = execv(arg, argv);
35b38379 407
28ce66de 408 info(KEY_PROGRAM " execution of '%s' failed", path);
2a25816f
KS
409 exit(1);
410 case -1:
6b493a20 411 err("fork of '%s' failed", path);
2a25816f
KS
412 return -1;
413 default:
8f43a65e 414 /* parent reads from fds[0] */
c27e6911
PM
415 close(fds[1]);
416 retval = 0;
35b38379 417 i = 0;
c27e6911 418 while (1) {
35b38379 419 count = read(fds[0], value + i, len - i-1);
18614ab2
KS
420 if (count < 0) {
421 err("read failed with '%s'", strerror(errno));
422 retval = -1;
423 }
424
425 if (count == 0)
c27e6911 426 break;
35b38379
KS
427
428 i += count;
429 if (i >= len-1) {
6b493a20 430 err("result len %d too short", len);
c27e6911 431 retval = -1;
35b38379 432 break;
c27e6911
PM
433 }
434 }
35b38379 435 value[i] = '\0';
35b38379
KS
436
437 close(fds[0]);
e920fed3 438 waitpid(pid, &status, 0);
35b38379 439
c27e6911 440 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) {
ac28b86d 441 dbg("exec program status 0x%x", status);
c27e6911
PM
442 retval = -1;
443 }
444 }
a8b01705 445
18614ab2
KS
446 if (!retval) {
447 remove_trailing_char(value, '\n');
448 dbg("result is '%s'", value);
449 replace_untrusted_chars(value);
450 } else
451 value[0] = '\0';
a27cd06c 452
18614ab2 453 return retval;
a27cd06c
KS
454}
455
79f651f4 456static int compare_sysfs_attribute(struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device, struct key_pair *pair)
a27cd06c 457{
18614ab2 458 char value[VALUE_SIZE];
d5f91372 459 int i;
a27cd06c 460
18614ab2
KS
461 if (find_sysfs_attribute(class_dev, sysfs_device, pair->name, value, sizeof(value)) != 0)
462 return -1;
a27cd06c 463
d5f91372 464 /* strip trailing whitespace of value, if not asked to match for it */
18614ab2
KS
465 if (!isspace(pair->value[strlen(pair->value)-1])) {
466 i = strlen(value);
467 while (i > 0 && isspace(value[i-1]))
468 value[--i] = '\0';
469 dbg("removed %i trailing whitespace chars from '%s'", strlen(value)-i, value);
d5f91372
KS
470 }
471
18614ab2
KS
472 dbg("compare attribute '%s' value '%s' with '%s'", pair->name, value, pair->value);
473 if (strcmp_pattern(pair->value, value) != 0)
474 return -1;
a8b01705 475
18614ab2 476 dbg("found matching attribute '%s' with value '%s'", pair->name, pair->value);
a8b01705
GKH
477 return 0;
478}
479
e5e322bc 480static int match_rule(struct udevice *udev, struct udev_rule *rule,
5f72c470 481 struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device)
dac056aa 482{
e5e322bc 483 if (rule->kernel[0] != '\0') {
28ce66de 484 dbg("check for " KEY_KERNEL " rule->kernel='%s' class_dev->name='%s'",
e5e322bc
KS
485 rule->kernel, class_dev->name);
486 if (strcmp_pattern(rule->kernel, class_dev->name) != 0) {
28ce66de
KS
487 dbg(KEY_KERNEL " is not matching");
488 if (rule->kernel_operation != KEY_OP_NOMATCH)
489 goto exit;
490 } else {
491 dbg(KEY_KERNEL " matches");
492 if (rule->kernel_operation == KEY_OP_NOMATCH)
493 goto exit;
ac28b86d 494 }
28ce66de 495 dbg(KEY_KERNEL " key is true");
03a9875b 496 }
ca1cc0fe 497
e5e322bc 498 if (rule->subsystem[0] != '\0') {
28ce66de 499 dbg("check for " KEY_SUBSYSTEM " rule->subsystem='%s' class_dev->name='%s'",
e5e322bc
KS
500 rule->subsystem, class_dev->name);
501 if (strcmp_pattern(rule->subsystem, udev->subsystem) != 0) {
28ce66de
KS
502 dbg(KEY_SUBSYSTEM " is not matching");
503 if (rule->subsystem_operation != KEY_OP_NOMATCH)
504 goto exit;
505 } else {
506 dbg(KEY_SUBSYSTEM " matches");
507 if (rule->subsystem_operation == KEY_OP_NOMATCH)
508 goto exit;
6818c51d 509 }
28ce66de 510 dbg(KEY_SUBSYSTEM " key is true");
03a9875b 511 }
6818c51d 512
3e5958de
KS
513 if (rule->env_pair_count) {
514 int i;
515
516 dbg("check for " KEY_ENV " pairs");
517 for (i = 0; i < rule->env_pair_count; i++) {
518 struct key_pair *pair;
519 const char *value;
520
521 pair = &rule->env_pair[i];
522 value = getenv(pair->name);
523 if (!value) {
524 dbg(KEY_ENV "{'%s'} is not found", pair->name);
525 goto exit;
526 }
527 if (strcmp_pattern(pair->value, value) != 0) {
528 dbg(KEY_ENV "{'%s'} is not matching", pair->name);
529 if (pair->operation != KEY_OP_NOMATCH)
530 goto exit;
531 } else {
532 dbg(KEY_ENV "{'%s'} matches", pair->name);
533 if (pair->operation == KEY_OP_NOMATCH)
534 goto exit;
535 }
536 }
537 dbg(KEY_ENV " key is true");
538 }
539
e57e7bc1 540 /* walk up the chain of physical devices and find a match */
03a9875b 541 while (1) {
2092fbcd 542 /* check for matching driver */
e5e322bc 543 if (rule->driver[0] != '\0') {
2b40452a
KS
544 if (sysfs_device == NULL) {
545 dbg("device has no sysfs_device");
ca4c984c 546 goto exit;
2b40452a 547 }
28ce66de 548 dbg("check for " KEY_DRIVER " rule->driver='%s' sysfs_device->driver_name='%s'",
e5e322bc
KS
549 rule->driver, sysfs_device->driver_name);
550 if (strcmp_pattern(rule->driver, sysfs_device->driver_name) != 0) {
28ce66de
KS
551 dbg(KEY_DRIVER " is not matching");
552 if (rule->driver_operation != KEY_OP_NOMATCH)
553 goto try_parent;
554 } else {
555 dbg(KEY_DRIVER " matches");
556 if (rule->driver_operation == KEY_OP_NOMATCH)
557 goto try_parent;
2092fbcd 558 }
28ce66de 559 dbg(KEY_DRIVER " key is true");
2092fbcd
KS
560 }
561
82b16983 562 /* check for matching bus value */
e5e322bc 563 if (rule->bus[0] != '\0') {
82b16983 564 if (sysfs_device == NULL) {
2b40452a 565 dbg("device has no sysfs_device");
ca4c984c 566 goto exit;
82b16983 567 }
28ce66de 568 dbg("check for " KEY_BUS " rule->bus='%s' sysfs_device->bus='%s'",
e5e322bc
KS
569 rule->bus, sysfs_device->bus);
570 if (strcmp_pattern(rule->bus, sysfs_device->bus) != 0) {
28ce66de
KS
571 dbg(KEY_BUS " is not matching");
572 if (rule->bus_operation != KEY_OP_NOMATCH)
573 goto try_parent;
574 } else {
575 dbg(KEY_BUS " matches");
576 if (rule->bus_operation == KEY_OP_NOMATCH)
577 goto try_parent;
82b16983 578 }
28ce66de 579 dbg(KEY_BUS " key is true");
82b16983
KS
580 }
581
ac28b86d 582 /* check for matching bus id */
e5e322bc 583 if (rule->id[0] != '\0') {
2b40452a
KS
584 if (sysfs_device == NULL) {
585 dbg("device has no sysfs_device");
ca4c984c 586 goto exit;
2b40452a 587 }
28ce66de 588 dbg("check " KEY_ID);
d6d1a18d 589 if (strcmp_pattern(rule->id, sysfs_device->bus_id) != 0) {
28ce66de
KS
590 dbg(KEY_ID " is not matching");
591 if (rule->id_operation != KEY_OP_NOMATCH)
592 goto try_parent;
593 } else {
594 dbg(KEY_ID " matches");
595 if (rule->id_operation == KEY_OP_NOMATCH)
596 goto try_parent;
ac28b86d 597 }
28ce66de 598 dbg(KEY_ID " key is true");
ac28b86d 599 }
ca1cc0fe 600
ac28b86d 601 /* check for matching sysfs pairs */
3e5958de
KS
602 if (rule->sysfs_pair_count) {
603 int i;
604
28ce66de 605 dbg("check " KEY_SYSFS " pairs");
3e5958de
KS
606 for (i = 0; i < rule->sysfs_pair_count; i++) {
607 struct key_pair *pair;
608
609 pair = &rule->sysfs_pair[i];
610 if (compare_sysfs_attribute(class_dev, sysfs_device, pair) != 0) {
611 dbg(KEY_SYSFS "{'%s'} is not matching", pair->name);
612 if (pair->operation != KEY_OP_NOMATCH)
613 goto try_parent;
614 } else {
615 dbg(KEY_SYSFS "{'%s'} matches", pair->name);
616 if (pair->operation == KEY_OP_NOMATCH)
617 goto try_parent;
618 }
ac28b86d 619 }
28ce66de 620 dbg(KEY_SYSFS " keys are true");
ac28b86d
KS
621 }
622
e57e7bc1
KS
623 /* found matching physical device */
624 break;
c5118442
KS
625try_parent:
626 dbg("try parent sysfs device");
724257d9
GKH
627 sysfs_device = sysfs_get_device_parent(sysfs_device);
628 if (sysfs_device == NULL)
82b16983 629 goto exit;
ca4c984c
KS
630 dbg("look at sysfs_device->path='%s'", sysfs_device->path);
631 dbg("look at sysfs_device->bus_id='%s'", sysfs_device->bus_id);
724257d9 632 }
82b16983 633
e57e7bc1 634 /* execute external program */
e5e322bc 635 if (rule->program[0] != '\0') {
63f61c5c 636 char program[PATH_SIZE];
e57e7bc1 637
28ce66de 638 dbg("check " KEY_PROGRAM);
e5e322bc 639 strlcpy(program, rule->program, sizeof(program));
e57e7bc1 640 apply_format(udev, program, sizeof(program), class_dev, sysfs_device);
63f61c5c 641 if (execute_program(udev, program, udev->program_result, sizeof(udev->program_result)) != 0) {
28ce66de
KS
642 dbg(KEY_PROGRAM " returned nonzero");
643 if (rule->program_operation != KEY_OP_NOMATCH)
644 goto exit;
645 } else {
646 dbg(KEY_PROGRAM " returned successful");
647 if (rule->program_operation == KEY_OP_NOMATCH)
648 goto exit;
e57e7bc1 649 }
28ce66de 650 dbg(KEY_PROGRAM " key is true");
e57e7bc1
KS
651 }
652
653 /* check for matching result of external program */
e5e322bc 654 if (rule->result[0] != '\0') {
28ce66de 655 dbg("check for " KEY_RESULT " rule->result='%s', udev->program_result='%s'",
e5e322bc
KS
656 rule->result, udev->program_result);
657 if (strcmp_pattern(rule->result, udev->program_result) != 0) {
28ce66de
KS
658 dbg(KEY_RESULT " is not matching");
659 if (rule->result_operation != KEY_OP_NOMATCH)
660 goto exit;
661 } else {
662 dbg(KEY_RESULT " matches");
663 if (rule->result_operation == KEY_OP_NOMATCH)
664 goto exit;
e57e7bc1 665 }
28ce66de 666 dbg(KEY_RESULT " key is true");
e57e7bc1
KS
667 }
668
669 /* rule matches */
670 return 0;
671
82b16983
KS
672exit:
673 return -1;
724257d9
GKH
674}
675
e5e322bc 676int udev_rules_get_name(struct udevice *udev, struct sysfs_class_device *class_dev)
724257d9 677{
707680b1 678 struct sysfs_class_device *class_dev_parent;
724257d9 679 struct sysfs_device *sysfs_device = NULL;
e5e322bc 680 struct udev_rule *rule;
724257d9 681
707680b1
KS
682 dbg("class_dev->name='%s'", class_dev->name);
683
684 /* Figure out where the "device"-symlink is at. For char devices this will
685 * always be in the class_dev->path. On block devices, only the main block
686 * device will have the device symlink in it's path. All partition devices
687 * need to look at the symlink in its parent directory.
688 */
689 class_dev_parent = sysfs_get_classdev_parent(class_dev);
690 if (class_dev_parent != NULL) {
691 dbg("given class device has a parent, use this instead");
692 sysfs_device = sysfs_get_classdev_device(class_dev_parent);
693 } else {
694 sysfs_device = sysfs_get_classdev_device(class_dev);
695 }
724257d9 696
724257d9 697 if (sysfs_device) {
7a947ce5 698 dbg("found devices device: path='%s', bus_id='%s', bus='%s'",
707680b1 699 sysfs_device->path, sysfs_device->bus_id, sysfs_device->bus);
63f61c5c 700 strlcpy(udev->bus_id, sysfs_device->bus_id, sizeof(udev->bus_id));
724257d9
GKH
701 }
702
9ed47a9f 703 dbg("udev->kernel_name='%s'", udev->kernel_name);
724257d9
GKH
704
705 /* look for a matching rule to apply */
e5e322bc 706 list_for_each_entry(rule, &udev_rule_list, node) {
724257d9 707 dbg("process rule");
e5e322bc 708 if (match_rule(udev, rule, class_dev, sysfs_device) == 0) {
e9390146 709
fd9efc00 710 /* apply options */
e5e322bc 711 if (rule->ignore_device) {
fd9efc00 712 info("configured rule in '%s[%i]' applied, '%s' is ignored",
e5e322bc 713 rule->config_file, rule->config_line, udev->kernel_name);
fd9efc00
KS
714 return -1;
715 }
e5e322bc 716 if (rule->ignore_remove) {
b821330f 717 udev->ignore_remove = 1;
e5e322bc 718 dbg("remove event should be ignored");
fd9efc00
KS
719 }
720 /* apply all_partitions option only at a main block device */
e5e322bc
KS
721 if (rule->partitions && udev->type == DEV_BLOCK && udev->kernel_number[0] == '\0') {
722 udev->partitions = rule->partitions;
fd9efc00
KS
723 dbg("creation of partition nodes requested");
724 }
725
38875577 726 /* apply permissions */
e5e322bc
KS
727 if (rule->mode != 0000) {
728 udev->mode = rule->mode;
38875577
MB
729 dbg("applied mode=%#o to '%s'", udev->mode, udev->kernel_name);
730 }
e5e322bc
KS
731 if (rule->owner[0] != '\0') {
732 strlcpy(udev->owner, rule->owner, sizeof(udev->owner));
38875577
MB
733 apply_format(udev, udev->owner, sizeof(udev->owner), class_dev, sysfs_device);
734 dbg("applied owner='%s' to '%s'", udev->owner, udev->kernel_name);
735 }
e5e322bc
KS
736 if (rule->group[0] != '\0') {
737 strlcpy(udev->group, rule->group, sizeof(udev->group));
38875577
MB
738 apply_format(udev, udev->group, sizeof(udev->group), class_dev, sysfs_device);
739 dbg("applied group='%s' to '%s'", udev->group, udev->kernel_name);
740 }
741
9ed47a9f 742 /* collect symlinks */
e5e322bc 743 if (rule->symlink[0] != '\0') {
63f61c5c 744 char temp[PATH_SIZE];
e48fc108 745 char *pos, *next;
ddd5b5dc 746
3908058c 747 info("configured rule in '%s[%i]' applied, added symlink '%s'",
e5e322bc
KS
748 rule->config_file, rule->config_line, rule->symlink);
749 strlcpy(temp, rule->symlink, sizeof(temp));
ddd5b5dc 750 apply_format(udev, temp, sizeof(temp), class_dev, sysfs_device);
e48fc108
KS
751
752 /* add multiple symlinks separated by spaces */
753 pos = temp;
754 next = strchr(temp, ' ');
755 while (next) {
756 next[0] = '\0';
6b493a20 757 info("add symlink '%s'", pos);
e48fc108
KS
758 name_list_add(&udev->symlink_list, pos, 0);
759 pos = &next[1];
760 next = strchr(pos, ' ');
761 }
6b493a20 762 info("add symlink '%s'", pos);
e48fc108 763 name_list_add(&udev->symlink_list, pos, 0);
97ed02ee 764 }
765
5f72c470 766 /* rule matches */
e5e322bc 767 if (rule->name[0] != '\0') {
e9390146 768 info("configured rule in '%s[%i]' applied, '%s' becomes '%s'",
e5e322bc 769 rule->config_file, rule->config_line, udev->kernel_name, rule->name);
5f72c470 770
e5e322bc 771 strlcpy(udev->name, rule->name, sizeof(udev->name));
5f72c470 772 apply_format(udev, udev->name, sizeof(udev->name), class_dev, sysfs_device);
e5e322bc
KS
773 strlcpy(udev->config_file, rule->config_file, sizeof(udev->config_file));
774 udev->config_line = rule->config_line;
65ab1334 775
e6764498 776 if (udev->type != DEV_NET)
fd9efc00
KS
777 dbg("name, '%s' is going to have owner='%s', group='%s', mode=%#o partitions=%i",
778 udev->name, udev->owner, udev->group, udev->mode, udev->partitions);
5f72c470 779
b821330f 780 break;
97ed02ee 781 }
3b6ed8bb
KS
782
783 if (rule->last_rule) {
784 dbg("last rule to be applied");
785 break;
786 }
787
724257d9 788 }
ac28b86d 789 }
c2405f50 790
b821330f
KS
791 if (udev->name[0] == '\0') {
792 /* no rule matched, so we use the kernel name */
63f61c5c 793 strlcpy(udev->name, udev->kernel_name, sizeof(udev->name));
6b493a20 794 info("no rule found, use kernel name '%s'", udev->name);
b821330f 795 }
7bd22a78 796
c1ab0461
KS
797 if (udev->tmp_node[0] != '\0') {
798 dbg("removing temporary device node");
799 unlink_secure(udev->tmp_node);
800 udev->tmp_node[0] = '\0';
801 }
802
120d45d0 803 return 0;
185a35a4 804}