1/* 2 * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com> 3 * Copyright (C) 2003-2006 Kay Sievers <kay.sievers@vrfy.org> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License as published by the 7 * Free Software Foundation version 2 of the License. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License along 15 * with this program; if not, write to the Free Software Foundation, Inc., 16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 * 18 */ 19 20#include <stddef.h> 21#include <stdlib.h> 22#include <string.h> 23#include <stdio.h> 24#include <fcntl.h> 25#include <ctype.h> 26#include <unistd.h> 27#include <errno.h> 28#include <syslog.h> 29#include <fnmatch.h> 30#include <sys/wait.h> 31#include <sys/stat.h> 32 33#include "udev.h" 34#include "udev_rules.h" 35 36 37/* extract possible {attr} and move str behind it */ 38static char *get_format_attribute(char **str) 39{ 40 char *pos; 41 char *attr = NULL; 42 43 if (*str[0] == '{') { 44 pos = strchr(*str, '}'); 45 if (pos == NULL) { 46 err("missing closing brace for format"); 47 return NULL; 48 } 49 pos[0] = '\0'; 50 attr = *str+1; 51 *str = pos+1; 52 dbg("attribute='%s', str='%s'", attr, *str); 53 } 54 return attr; 55} 56 57/* extract possible format length and move str behind it*/ 58static int get_format_len(char **str) 59{ 60 int num; 61 char *tail; 62 63 if (isdigit(*str[0])) { 64 num = (int) strtoul(*str, &tail, 10); 65 if (num > 0) { 66 *str = tail; 67 dbg("format length=%i", num); 68 return num; 69 } else { 70 err("format parsing error '%s'", *str); 71 } 72 } 73 return -1; 74} 75 76static int get_key(char **line, char **key, char **value) 77{ 78 char *linepos; 79 char *temp; 80 81 linepos = *line; 82 if (linepos == NULL) 83 return -1; 84 85 /* skip whitespace */ 86 while (isspace(linepos[0])) 87 linepos++; 88 89 /* get the key */ 90 temp = strchr(linepos, '='); 91 if (temp == NULL || temp == linepos) 92 return -1; 93 temp[0] = '\0'; 94 *key = linepos; 95 linepos = &temp[1]; 96 97 /* get a quoted value */ 98 if (linepos[0] == '"' || linepos[0] == '\'') { 99 temp = strchr(&linepos[1], linepos[0]); 100 if (temp != NULL) { 101 temp[0] = '\0'; 102 *value = &linepos[1]; 103 goto out; 104 } 105 } 106 107 /* get the value*/ 108 temp = strchr(linepos, '\n'); 109 if (temp != NULL) 110 temp[0] = '\0'; 111 *value = linepos; 112out: 113 return 0; 114} 115 116static int import_keys_into_env(struct udevice *udev, const char *buf, size_t bufsize) 117{ 118 char line[LINE_SIZE]; 119 const char *bufline; 120 char *linepos; 121 char *variable; 122 char *value; 123 size_t cur; 124 size_t count; 125 int lineno; 126 127 /* loop through the whole buffer */ 128 lineno = 0; 129 cur = 0; 130 while (cur < bufsize) { 131 count = buf_get_line(buf, bufsize, cur); 132 bufline = &buf[cur]; 133 cur += count+1; 134 lineno++; 135 136 if (count >= sizeof(line)) { 137 err("line too long, conf line skipped %s, line %d", udev_config_filename, lineno); 138 continue; 139 } 140 141 /* eat the whitespace */ 142 while ((count > 0) && isspace(bufline[0])) { 143 bufline++; 144 count--; 145 } 146 if (count == 0) 147 continue; 148 149 /* see if this is a comment */ 150 if (bufline[0] == COMMENT_CHARACTER) 151 continue; 152 153 memcpy(line, bufline, count); 154 line[count] = '\0'; 155 156 linepos = line; 157 if (get_key(&linepos, &variable, &value) == 0) { 158 dbg("import '%s=%s'", variable, value); 159 160 /* handle device, renamed by external tool, returning new path */ 161 if (strcmp(variable, "DEVPATH") == 0) { 162 info("updating devpath from '%s' to '%s'", udev->dev->devpath, value); 163 sysfs_device_set_values(udev->dev, value, NULL, NULL); 164 } else 165 name_list_key_add(&udev->env_list, variable, value); 166 setenv(variable, value, 1); 167 } 168 } 169 170 return 0; 171} 172 173static int import_file_into_env(struct udevice *udev, const char *filename) 174{ 175 char *buf; 176 size_t bufsize; 177 178 if (file_map(filename, &buf, &bufsize) != 0) { 179 err("can't open '%s': %s", filename, strerror(errno)); 180 return -1; 181 } 182 import_keys_into_env(udev, buf, bufsize); 183 file_unmap(buf, bufsize); 184 185 return 0; 186} 187 188static int import_program_into_env(struct udevice *udev, const char *program) 189{ 190 char result[2048]; 191 size_t reslen; 192 193 if (run_program(program, udev->dev->subsystem, result, sizeof(result), &reslen, (udev_log_priority >= LOG_INFO)) != 0) 194 return -1; 195 return import_keys_into_env(udev, result, reslen); 196} 197 198static int import_parent_into_env(struct udevice *udev, const char *filter) 199{ 200 struct sysfs_device *dev_parent; 201 int rc = -1; 202 203 dev_parent = sysfs_device_get_parent(udev->dev); 204 if (dev_parent != NULL) { 205 struct udevice *udev_parent; 206 struct name_entry *name_loop; 207 208 dbg("found parent '%s', get the node name", dev_parent->devpath); 209 udev_parent = udev_device_init(NULL); 210 if (udev_parent == NULL) 211 return -1; 212 /* import the udev_db of the parent */ 213 if (udev_db_get_device(udev_parent, dev_parent->devpath) == 0) { 214 dbg("import stored parent env '%s'", udev_parent->name); 215 list_for_each_entry(name_loop, &udev_parent->env_list, node) { 216 char name[NAME_SIZE]; 217 char *pos; 218 219 strlcpy(name, name_loop->name, sizeof(name)); 220 pos = strchr(name, '='); 221 if (pos) { 222 pos[0] = '\0'; 223 pos++; 224 if (fnmatch(filter, name, 0) == 0) { 225 dbg("import key '%s'", name_loop->name); 226 name_list_add(&udev->env_list, name_loop->name, 0); 227 setenv(name, pos, 1); 228 } else 229 dbg("skip key '%s'", name_loop->name); 230 } 231 } 232 rc = 0; 233 } else 234 dbg("parent not found in database"); 235 udev_device_cleanup(udev_parent); 236 } 237 238 return rc; 239} 240 241#define WAIT_LOOP_PER_SECOND 50 242static int wait_for_sysfs(struct udevice *udev, const char *file, int timeout) 243{ 244 char devicepath[PATH_SIZE]; 245 char filepath[PATH_SIZE]; 246 struct stat stats; 247 int loop = timeout * WAIT_LOOP_PER_SECOND; 248 249 strlcpy(devicepath, sysfs_path, sizeof(devicepath)); 250 strlcat(devicepath, udev->dev->devpath, sizeof(devicepath)); 251 strlcpy(filepath, devicepath, sizeof(filepath)); 252 strlcat(filepath, "/", sizeof(filepath)); 253 strlcat(filepath, file, sizeof(filepath)); 254 255 dbg("will wait %i sec for '%s'", timeout, filepath); 256 while (--loop) { 257 /* lookup file */ 258 if (stat(filepath, &stats) == 0) { 259 info("file '%s' appeared after %i loops", filepath, (timeout * WAIT_LOOP_PER_SECOND) - loop-1); 260 return 0; 261 } 262 /* make sure, the device did not disappear in the meantime */ 263 if (stat(devicepath, &stats) != 0) { 264 info("device disappeared while waiting for '%s'", filepath); 265 return -2; 266 } 267 info("wait for '%s' for %i mseconds", filepath, 1000 / WAIT_LOOP_PER_SECOND); 268 usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND); 269 } 270 info("waiting for '%s' failed", filepath); 271 return -1; 272} 273 274/* handle "[$SUBSYSTEM/$KERNEL]<attribute>" lookup */ 275static int attr_get_by_subsys_id(const char *attrstr, char *devpath, size_t len, char **attr) 276{ 277 char subsys[NAME_SIZE]; 278 char *attrib; 279 char *id; 280 int found = 0; 281 282 if (attrstr[0] != '[') 283 goto out; 284 285 strlcpy(subsys, &attrstr[1], sizeof(subsys)); 286 287 attrib = strchr(subsys, ']'); 288 if (attrib == NULL) 289 goto out; 290 attrib[0] = '\0'; 291 attrib = &attrib[1]; 292 293 id = strchr(subsys, '/'); 294 if (id == NULL) 295 goto out; 296 id[0] = '\0'; 297 id = &id[1]; 298 299 if (sysfs_lookup_devpath_by_subsys_id(devpath, len, subsys, id)) { 300 if (attr != NULL) { 301 if (attrib[0] != '\0') 302 *attr = attrib; 303 else 304 *attr = NULL; 305 } 306 found = 1; 307 } 308out: 309 return found; 310} 311 312void udev_rules_apply_format(struct udevice *udev, char *string, size_t maxsize) 313{ 314 char temp[PATH_SIZE]; 315 char temp2[PATH_SIZE]; 316 char *head, *tail, *pos, *cpos, *attr, *rest; 317 int len; 318 int i; 319 int count; 320 enum subst_type { 321 SUBST_UNKNOWN, 322 SUBST_DEVPATH, 323 SUBST_KERNEL, 324 SUBST_KERNEL_NUMBER, 325 SUBST_ID, 326 SUBST_MAJOR, 327 SUBST_MINOR, 328 SUBST_RESULT, 329 SUBST_ATTR, 330 SUBST_PARENT, 331 SUBST_TEMP_NODE, 332 SUBST_ROOT, 333 SUBST_SYS, 334 SUBST_ENV, 335 }; 336 static const struct subst_map { 337 char *name; 338 char fmt; 339 enum subst_type type; 340 } map[] = { 341 { .name = "devpath", .fmt = 'p', .type = SUBST_DEVPATH }, 342 { .name = "number", .fmt = 'n', .type = SUBST_KERNEL_NUMBER }, 343 { .name = "kernel", .fmt = 'k', .type = SUBST_KERNEL }, 344 { .name = "id", .fmt = 'b', .type = SUBST_ID }, 345 { .name = "major", .fmt = 'M', .type = SUBST_MAJOR }, 346 { .name = "minor", .fmt = 'm', .type = SUBST_MINOR }, 347 { .name = "result", .fmt = 'c', .type = SUBST_RESULT }, 348 { .name = "attr", .fmt = 's', .type = SUBST_ATTR }, 349 { .name = "sysfs", .fmt = 's', .type = SUBST_ATTR }, 350 { .name = "parent", .fmt = 'P', .type = SUBST_PARENT }, 351 { .name = "tempnode", .fmt = 'N', .type = SUBST_TEMP_NODE }, 352 { .name = "root", .fmt = 'r', .type = SUBST_ROOT }, 353 { .name = "sys", .fmt = 'S', .type = SUBST_SYS }, 354 { .name = "env", .fmt = 'E', .type = SUBST_ENV }, 355 { NULL, '\0', 0 } 356 }; 357 enum subst_type type; 358 const struct subst_map *subst; 359 360 head = string; 361 while (1) { 362 len = -1; 363 while (head[0] != '\0') { 364 if (head[0] == '$') { 365 /* substitute named variable */ 366 if (head[1] == '\0') 367 break; 368 if (head[1] == '$') { 369 strlcpy(temp, head+2, sizeof(temp)); 370 strlcpy(head+1, temp, maxsize); 371 head++; 372 continue; 373 } 374 head[0] = '\0'; 375 for (subst = map; subst->name; subst++) { 376 if (strncasecmp(&head[1], subst->name, strlen(subst->name)) == 0) { 377 type = subst->type; 378 tail = head + strlen(subst->name)+1; 379 dbg("will substitute format name '%s'", subst->name); 380 goto found; 381 } 382 } 383 head[0] = '$'; 384 err("unknown format variable '%s'", head); 385 } else if (head[0] == '%') { 386 /* substitute format char */ 387 if (head[1] == '\0') 388 break; 389 if (head[1] == '%') { 390 strlcpy(temp, head+2, sizeof(temp)); 391 strlcpy(head+1, temp, maxsize); 392 head++; 393 continue; 394 } 395 head[0] = '\0'; 396 tail = head+1; 397 len = get_format_len(&tail); 398 for (subst = map; subst->name; subst++) { 399 if (tail[0] == subst->fmt) { 400 type = subst->type; 401 tail++; 402 dbg("will substitute format char '%c'", subst->fmt); 403 goto found; 404 } 405 } 406 head[0] = '%'; 407 err("unknown format char '%c'", tail[0]); 408 } 409 head++; 410 } 411 break; 412found: 413 attr = get_format_attribute(&tail); 414 strlcpy(temp, tail, sizeof(temp)); 415 dbg("format=%i, string='%s', tail='%s'", type ,string, tail); 416 417 switch (type) { 418 case SUBST_DEVPATH: 419 strlcat(string, udev->dev->devpath, maxsize); 420 dbg("substitute devpath '%s'", udev->dev->devpath); 421 break; 422 case SUBST_KERNEL: 423 strlcat(string, udev->dev->kernel, maxsize); 424 dbg("substitute kernel name '%s'", udev->dev->kernel); 425 break; 426 case SUBST_KERNEL_NUMBER: 427 strlcat(string, udev->dev->kernel_number, maxsize); 428 dbg("substitute kernel number '%s'", udev->dev->kernel_number); 429 break; 430 case SUBST_ID: 431 if (udev->dev_parent != NULL) { 432 strlcat(string, udev->dev_parent->kernel, maxsize); 433 dbg("substitute id '%s'", udev->dev_parent->kernel); 434 } 435 break; 436 case SUBST_MAJOR: 437 sprintf(temp2, "%d", major(udev->devt)); 438 strlcat(string, temp2, maxsize); 439 dbg("substitute major number '%s'", temp2); 440 break; 441 case SUBST_MINOR: 442 sprintf(temp2, "%d", minor(udev->devt)); 443 strlcat(string, temp2, maxsize); 444 dbg("substitute minor number '%s'", temp2); 445 break; 446 case SUBST_RESULT: 447 if (udev->program_result[0] == '\0') 448 break; 449 /* get part part of the result string */ 450 i = 0; 451 if (attr != NULL) 452 i = strtoul(attr, &rest, 10); 453 if (i > 0) { 454 dbg("request part #%d of result string", i); 455 cpos = udev->program_result; 456 while (--i) { 457 while (cpos[0] != '\0' && !isspace(cpos[0])) 458 cpos++; 459 while (isspace(cpos[0])) 460 cpos++; 461 } 462 if (i > 0) { 463 err("requested part of result string not found"); 464 break; 465 } 466 strlcpy(temp2, cpos, sizeof(temp2)); 467 /* %{2+}c copies the whole string from the second part on */ 468 if (rest[0] != '+') { 469 cpos = strchr(temp2, ' '); 470 if (cpos) 471 cpos[0] = '\0'; 472 } 473 strlcat(string, temp2, maxsize); 474 dbg("substitute part of result string '%s'", temp2); 475 } else { 476 strlcat(string, udev->program_result, maxsize); 477 dbg("substitute result string '%s'", udev->program_result); 478 } 479 break; 480 case SUBST_ATTR: 481 if (attr == NULL) 482 err("missing file parameter for attr"); 483 else { 484 char devpath[PATH_SIZE]; 485 char *attrib; 486 const char *value = NULL; 487 size_t size; 488 489 if (attr_get_by_subsys_id(attr, devpath, sizeof(devpath), &attrib)) { 490 if (attrib != NULL) 491 value = sysfs_attr_get_value(devpath, attrib); 492 else 493 break; 494 } 495 496 /* try the current device, other matches may have selected */ 497 if (value == NULL && udev->dev_parent != NULL && udev->dev_parent != udev->dev) 498 value = sysfs_attr_get_value(udev->dev_parent->devpath, attr); 499 500 /* look at all devices along the chain of parents */ 501 if (value == NULL) { 502 struct sysfs_device *dev_parent = udev->dev; 503 504 do { 505 dbg("looking at '%s'", dev_parent->devpath); 506 value = sysfs_attr_get_value(dev_parent->devpath, attr); 507 if (value != NULL) { 508 strlcpy(temp2, value, sizeof(temp2)); 509 break; 510 } 511 dev_parent = sysfs_device_get_parent(dev_parent); 512 } while (dev_parent != NULL); 513 } 514 515 if (value == NULL) 516 break; 517 518 /* strip trailing whitespace, and replace unwanted characters */ 519 size = strlcpy(temp2, value, sizeof(temp2)); 520 if (size >= sizeof(temp2)) 521 size = sizeof(temp2)-1; 522 while (size > 0 && isspace(temp2[size-1])) 523 temp2[--size] = '\0'; 524 count = replace_chars(temp2, ALLOWED_CHARS_INPUT); 525 if (count > 0) 526 info("%i character(s) replaced" , count); 527 strlcat(string, temp2, maxsize); 528 dbg("substitute sysfs value '%s'", temp2); 529 } 530 break; 531 case SUBST_PARENT: 532 { 533 struct sysfs_device *dev_parent; 534 535 dev_parent = sysfs_device_get_parent(udev->dev); 536 if (dev_parent != NULL) { 537 struct udevice *udev_parent; 538 539 dbg("found parent '%s', get the node name", dev_parent->devpath); 540 udev_parent = udev_device_init(NULL); 541 if (udev_parent != NULL) { 542 /* lookup the name in the udev_db with the DEVPATH of the parent */ 543 if (udev_db_get_device(udev_parent, dev_parent->devpath) == 0) { 544 strlcat(string, udev_parent->name, maxsize); 545 dbg("substitute parent node name'%s'", udev_parent->name); 546 } else 547 dbg("parent not found in database"); 548 udev_device_cleanup(udev_parent); 549 } 550 } 551 } 552 break; 553 case SUBST_TEMP_NODE: 554 if (udev->tmp_node[0] == '\0' && major(udev->devt) > 0) { 555 dbg("create temporary device node for callout"); 556 snprintf(udev->tmp_node, sizeof(udev->tmp_node), "%s/.tmp-%u-%u", 557 udev_root, major(udev->devt), minor(udev->devt)); 558 udev->tmp_node[sizeof(udev->tmp_node)-1] = '\0'; 559 udev_node_mknod(udev, udev->tmp_node, udev->devt, 0600, 0, 0); 560 } 561 strlcat(string, udev->tmp_node, maxsize); 562 dbg("substitute temporary device node name '%s'", udev->tmp_node); 563 break; 564 case SUBST_ROOT: 565 strlcat(string, udev_root, maxsize); 566 dbg("substitute udev_root '%s'", udev_root); 567 break; 568 case SUBST_SYS: 569 strlcat(string, sysfs_path, maxsize); 570 dbg("substitute sysfs_path '%s'", sysfs_path); 571 break; 572 case SUBST_ENV: 573 if (attr == NULL) { 574 dbg("missing attribute"); 575 break; 576 } 577 pos = getenv(attr); 578 if (pos == NULL) { 579 dbg("env '%s' not available", attr); 580 break; 581 } 582 dbg("substitute env '%s=%s'", attr, pos); 583 strlcat(string, pos, maxsize); 584 break; 585 default: 586 err("unknown substitution type=%i", type); 587 break; 588 } 589 /* possibly truncate to format-char specified length */ 590 if (len >= 0 && len < (int)strlen(head)) { 591 head[len] = '\0'; 592 dbg("truncate to %i chars, subtitution string becomes '%s'", len, head); 593 } 594 strlcat(string, temp, maxsize); 595 } 596} 597 598static char *key_val(struct udev_rule *rule, struct key *key) 599{ 600 return rule->buf + key->val_off; 601} 602 603static char *key_pair_name(struct udev_rule *rule, struct key_pair *pair) 604{ 605 return rule->buf + pair->key_name_off; 606} 607 608static int match_key(const char *key_name, struct udev_rule *rule, struct key *key, const char *val) 609{ 610 char value[PATH_SIZE]; 611 char *key_value; 612 char *pos; 613 int match = 0; 614 615 if (key->operation != KEY_OP_MATCH && 616 key->operation != KEY_OP_NOMATCH) 617 return 0; 618 619 /* look for a matching string, parts are separated by '|' */ 620 strlcpy(value, rule->buf + key->val_off, sizeof(value)); 621 key_value = value; 622 dbg("key %s value='%s'", key_name, key_value); 623 while (key_value) { 624 pos = strchr(key_value, '|'); 625 if (pos) { 626 pos[0] = '\0'; 627 pos++; 628 } 629 630 dbg("match %s '%s' <-> '%s'", key_name, key_value, val); 631 match = (fnmatch(key_value, val, 0) == 0); 632 if (match) 633 break; 634 635 key_value = pos; 636 } 637 638 if (match && (key->operation == KEY_OP_MATCH)) { 639 dbg("%s is true (matching value)", key_name); 640 return 0; 641 } 642 if (!match && (key->operation == KEY_OP_NOMATCH)) { 643 dbg("%s is true (non-matching value)", key_name); 644 return 0; 645 } 646 return -1; 647} 648 649/* match a single rule against a given device and possibly its parent devices */ 650static int match_rule(struct udevice *udev, struct udev_rule *rule) 651{ 652 int i; 653 654 if (match_key("ACTION", rule, &rule->action, udev->action)) 655 goto nomatch; 656 657 if (match_key("KERNEL", rule, &rule->kernel, udev->dev->kernel)) 658 goto nomatch; 659 660 if (match_key("SUBSYSTEM", rule, &rule->subsystem, udev->dev->subsystem)) 661 goto nomatch; 662 663 if (match_key("DEVPATH", rule, &rule->devpath, udev->dev->devpath)) 664 goto nomatch; 665 666 if (match_key("DRIVER", rule, &rule->driver, udev->dev->driver)) 667 goto nomatch; 668 669 /* match NAME against a value assigned by an earlier rule */ 670 if (match_key("NAME", rule, &rule->name, udev->name)) 671 goto nomatch; 672 673 for (i = 0; i < rule->env.count; i++) { 674 struct key_pair *pair = &rule->env.keys[i]; 675 676 /* we only check for matches, assignments will be handled later */ 677 if (pair->key.operation == KEY_OP_MATCH || 678 pair->key.operation == KEY_OP_NOMATCH) { 679 const char *key_name = key_pair_name(rule, pair); 680 const char *value = getenv(key_name); 681 682 if (!value) { 683 dbg("ENV{'%s'} is not set, treat as empty", key_name); 684 value = ""; 685 } 686 if (match_key("ENV", rule, &pair->key, value)) 687 goto nomatch; 688 } 689 } 690 691 if (rule->test.operation != KEY_OP_UNSET) { 692 char filename[PATH_SIZE]; 693 char devpath[PATH_SIZE]; 694 char *attr; 695 struct stat statbuf; 696 int match; 697 698 strlcpy(filename, key_val(rule, &rule->test), sizeof(filename)); 699 udev_rules_apply_format(udev, filename, sizeof(filename)); 700 701 if (attr_get_by_subsys_id(filename, devpath, sizeof(devpath), &attr)) { 702 strlcpy(filename, sysfs_path, sizeof(filename)); 703 strlcat(filename, devpath, sizeof(filename)); 704 if (attr != NULL) { 705 strlcat(filename, "/", sizeof(filename)); 706 strlcat(filename, attr, sizeof(filename)); 707 } 708 } 709 710 match = (stat(filename, &statbuf) == 0); 711 info("'%s' %s", filename, match ? "exists" : "does not exist"); 712 if (match && rule->test_mode_mask > 0) { 713 match = ((statbuf.st_mode & rule->test_mode_mask) > 0); 714 info("'%s' has mode=%#o and %s %#o", filename, statbuf.st_mode, 715 match ? "matches" : "does not match", 716 rule->test_mode_mask); 717 } 718 if (match && rule->test.operation == KEY_OP_NOMATCH) 719 goto nomatch; 720 if (!match && rule->test.operation == KEY_OP_MATCH) 721 goto nomatch; 722 dbg("TEST key is true"); 723 } 724 725 if (rule->wait_for_sysfs.operation != KEY_OP_UNSET) { 726 int found; 727 728 found = (wait_for_sysfs(udev, key_val(rule, &rule->wait_for_sysfs), 3) == 0); 729 if (!found && (rule->wait_for_sysfs.operation != KEY_OP_NOMATCH)) 730 goto nomatch; 731 } 732 733 /* check for matching sysfs attribute pairs */ 734 for (i = 0; i < rule->attr.count; i++) { 735 struct key_pair *pair = &rule->attr.keys[i]; 736 737 if (pair->key.operation == KEY_OP_MATCH || 738 pair->key.operation == KEY_OP_NOMATCH) { 739 const char *key_name = key_pair_name(rule, pair); 740 const char *key_value = key_val(rule, &pair->key); 741 char devpath[PATH_SIZE]; 742 char *attrib; 743 const char *value = NULL; 744 char val[VALUE_SIZE]; 745 size_t len; 746 747 if (attr_get_by_subsys_id(key_name, devpath, sizeof(devpath), &attrib)) { 748 if (attrib != NULL) 749 value = sysfs_attr_get_value(devpath, attrib); 750 else 751 goto nomatch; 752 } 753 if (value == NULL) 754 value = sysfs_attr_get_value(udev->dev->devpath, key_name); 755 if (value == NULL) 756 goto nomatch; 757 strlcpy(val, value, sizeof(val)); 758 759 /* strip trailing whitespace of value, if not asked to match for it */ 760 len = strlen(key_value); 761 if (len > 0 && !isspace(key_value[len-1])) { 762 len = strlen(val); 763 while (len > 0 && isspace(val[len-1])) 764 val[--len] = '\0'; 765 dbg("removed %zi trailing whitespace chars from '%s'", strlen(val)-len, val); 766 } 767 768 if (match_key("ATTR", rule, &pair->key, val)) 769 goto nomatch; 770 } 771 } 772 773 /* walk up the chain of parent devices and find a match */ 774 udev->dev_parent = udev->dev; 775 while (1) { 776 /* check for matching kernel device name */ 777 if (match_key("KERNELS", rule, &rule->kernels, udev->dev_parent->kernel)) 778 goto try_parent; 779 780 /* check for matching subsystem value */ 781 if (match_key("SUBSYSTEMS", rule, &rule->subsystems, udev->dev_parent->subsystem)) 782 goto try_parent; 783 784 /* check for matching driver */ 785 if (match_key("DRIVERS", rule, &rule->drivers, udev->dev_parent->driver)) 786 goto try_parent; 787 788 /* check for matching sysfs attribute pairs */ 789 for (i = 0; i < rule->attrs.count; i++) { 790 struct key_pair *pair = &rule->attrs.keys[i]; 791 792 if (pair->key.operation == KEY_OP_MATCH || 793 pair->key.operation == KEY_OP_NOMATCH) { 794 const char *key_name = key_pair_name(rule, pair); 795 const char *key_value = key_val(rule, &pair->key); 796 const char *value; 797 char val[VALUE_SIZE]; 798 size_t len; 799 800 value = sysfs_attr_get_value(udev->dev_parent->devpath, key_name); 801 if (value == NULL) 802 value = sysfs_attr_get_value(udev->dev->devpath, key_name); 803 if (value == NULL) 804 goto try_parent; 805 strlcpy(val, value, sizeof(val)); 806 807 /* strip trailing whitespace of value, if not asked to match for it */ 808 len = strlen(key_value); 809 if (len > 0 && !isspace(key_value[len-1])) { 810 len = strlen(val); 811 while (len > 0 && isspace(val[len-1])) 812 val[--len] = '\0'; 813 dbg("removed %zi trailing whitespace chars from '%s'", strlen(val)-len, val); 814 } 815 816 if (match_key("ATTRS", rule, &pair->key, val)) 817 goto try_parent; 818 } 819 } 820 821 /* found matching device */ 822 break; 823try_parent: 824 /* move to parent device */ 825 dbg("try parent sysfs device"); 826 udev->dev_parent = sysfs_device_get_parent(udev->dev_parent); 827 if (udev->dev_parent == NULL) 828 goto nomatch; 829 dbg("looking at dev_parent->devpath='%s'", udev->dev_parent->devpath); 830 dbg("looking at dev_parent->kernel='%s'", udev->dev_parent->kernel); 831 } 832 833 /* execute external program */ 834 if (rule->program.operation != KEY_OP_UNSET) { 835 char program[PATH_SIZE]; 836 char result[PATH_SIZE]; 837 838 strlcpy(program, key_val(rule, &rule->program), sizeof(program)); 839 udev_rules_apply_format(udev, program, sizeof(program)); 840 if (run_program(program, udev->dev->subsystem, result, sizeof(result), 841 NULL, (udev_log_priority >= LOG_INFO)) != 0) { 842 dbg("PROGRAM is false"); 843 udev->program_result[0] = '\0'; 844 if (rule->program.operation != KEY_OP_NOMATCH) 845 goto nomatch; 846 } else { 847 int count; 848 849 dbg("PROGRAM matches"); 850 remove_trailing_chars(result, '\n'); 851 if (rule->string_escape == ESCAPE_UNSET || 852 rule->string_escape == ESCAPE_REPLACE) { 853 count = replace_chars(result, ALLOWED_CHARS_INPUT); 854 if (count > 0) 855 info("%i character(s) replaced" , count); 856 } 857 dbg("result is '%s'", result); 858 strlcpy(udev->program_result, result, sizeof(udev->program_result)); 859 dbg("PROGRAM returned successful"); 860 if (rule->program.operation == KEY_OP_NOMATCH) 861 goto nomatch; 862 } 863 dbg("PROGRAM key is true"); 864 } 865 866 /* check for matching result of external program */ 867 if (match_key("RESULT", rule, &rule->result, udev->program_result)) 868 goto nomatch; 869 870 /* import variables returned from program or or file into environment */ 871 if (rule->import.operation != KEY_OP_UNSET) { 872 char import[PATH_SIZE]; 873 int rc = -1; 874 875 strlcpy(import, key_val(rule, &rule->import), sizeof(import)); 876 udev_rules_apply_format(udev, import, sizeof(import)); 877 dbg("check for IMPORT import='%s'", import); 878 if (rule->import_type == IMPORT_PROGRAM) { 879 rc = import_program_into_env(udev, import); 880 } else if (rule->import_type == IMPORT_FILE) { 881 dbg("import file import='%s'", import); 882 rc = import_file_into_env(udev, import); 883 } else if (rule->import_type == IMPORT_PARENT) { 884 dbg("import parent import='%s'", import); 885 rc = import_parent_into_env(udev, import); 886 } 887 if (rc != 0) { 888 dbg("IMPORT failed"); 889 if (rule->import.operation != KEY_OP_NOMATCH) 890 goto nomatch; 891 } else 892 dbg("IMPORT '%s' imported", key_val(rule, &rule->import)); 893 dbg("IMPORT key is true"); 894 } 895 896 /* rule matches, if we have ENV assignments export it */ 897 for (i = 0; i < rule->env.count; i++) { 898 struct key_pair *pair = &rule->env.keys[i]; 899 900 if (pair->key.operation == KEY_OP_ASSIGN) { 901 char temp_value[NAME_SIZE]; 902 const char *key_name = key_pair_name(rule, pair); 903 const char *value = key_val(rule, &pair->key); 904 905 /* make sure we don't write to the same string we possibly read from */ 906 strlcpy(temp_value, value, sizeof(temp_value)); 907 udev_rules_apply_format(udev, temp_value, NAME_SIZE); 908 909 if (temp_value[0] == '\0') { 910 name_list_key_remove(&udev->env_list, key_name); 911 unsetenv(key_name); 912 info("unset ENV '%s'", key_name); 913 } else { 914 char *key_value = name_list_key_add(&udev->env_list, key_name, temp_value); 915 916 if (key_value == NULL) 917 break; 918 putenv(key_value); 919 info("set ENV '%s'", key_value); 920 } 921 } 922 } 923 924 /* if we have ATTR assignments, write value to sysfs file */ 925 for (i = 0; i < rule->attr.count; i++) { 926 struct key_pair *pair = &rule->attr.keys[i]; 927 928 if (pair->key.operation == KEY_OP_ASSIGN) { 929 const char *key_name = key_pair_name(rule, pair); 930 char devpath[PATH_SIZE]; 931 char *attrib; 932 char attr[PATH_SIZE] = ""; 933 char value[NAME_SIZE]; 934 FILE *f; 935 936 if (attr_get_by_subsys_id(key_name, devpath, sizeof(devpath), &attrib)) { 937 if (attrib != NULL) { 938 strlcpy(attr, sysfs_path, sizeof(attr)); 939 strlcat(attr, devpath, sizeof(attr)); 940 strlcat(attr, "/", sizeof(attr)); 941 strlcat(attr, attrib, sizeof(attr)); 942 } 943 } 944 945 if (attr[0] == '\0') { 946 strlcpy(attr, sysfs_path, sizeof(attr)); 947 strlcat(attr, udev->dev->devpath, sizeof(attr)); 948 strlcat(attr, "/", sizeof(attr)); 949 strlcat(attr, key_name, sizeof(attr)); 950 } 951 952 strlcpy(value, key_val(rule, &pair->key), sizeof(value)); 953 udev_rules_apply_format(udev, value, sizeof(value)); 954 info("writing '%s' to sysfs file '%s'", value, attr); 955 f = fopen(attr, "w"); 956 if (f != NULL) { 957 if (!udev->test_run) 958 if (fprintf(f, "%s", value) <= 0) 959 err("error writing ATTR{%s}: %s", attr, strerror(errno)); 960 fclose(f); 961 } else 962 err("error opening ATTR{%s} for writing: %s", attr, strerror(errno)); 963 } 964 } 965 return 0; 966 967nomatch: 968 return -1; 969} 970 971int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev) 972{ 973 struct udev_rule *rule; 974 int name_set = 0; 975 976 dbg("udev->dev->devpath='%s'", udev->dev->devpath); 977 dbg("udev->dev->kernel='%s'", udev->dev->kernel); 978 979 /* look for a matching rule to apply */ 980 udev_rules_iter_init(rules); 981 while (1) { 982 rule = udev_rules_iter_next(rules); 983 if (rule == NULL) 984 break; 985 986 if (name_set && 987 (rule->name.operation == KEY_OP_ASSIGN || 988 rule->name.operation == KEY_OP_ASSIGN_FINAL || 989 rule->name.operation == KEY_OP_ADD)) { 990 dbg("node name already set, rule ignored"); 991 continue; 992 } 993 994 dbg("process rule"); 995 if (match_rule(udev, rule) == 0) { 996 /* apply options */ 997 if (rule->ignore_device) { 998 info("rule applied, '%s' is ignored", udev->dev->kernel); 999 udev->ignore_device = 1; 1000 return 0; 1001 } 1002 if (rule->ignore_remove) { 1003 udev->ignore_remove = 1; 1004 dbg("remove event should be ignored"); 1005 } 1006 if (rule->link_priority != 0) { 1007 udev->link_priority = rule->link_priority; 1008 info("link_priority=%i", udev->link_priority); 1009 } 1010 /* apply all_partitions option only at a main block device */ 1011 if (rule->partitions && 1012 strcmp(udev->dev->subsystem, "block") == 0 && udev->dev->kernel_number[0] == '\0') { 1013 udev->partitions = rule->partitions; 1014 dbg("creation of partition nodes requested"); 1015 } 1016 1017 /* apply permissions */ 1018 if (!udev->mode_final && rule->mode != 0000) { 1019 if (rule->mode_operation == KEY_OP_ASSIGN_FINAL) 1020 udev->mode_final = 1; 1021 udev->mode = rule->mode; 1022 dbg("applied mode=%#o to '%s'", rule->mode, udev->dev->kernel); 1023 } 1024 if (!udev->owner_final && rule->owner.operation != KEY_OP_UNSET) { 1025 if (rule->owner.operation == KEY_OP_ASSIGN_FINAL) 1026 udev->owner_final = 1; 1027 strlcpy(udev->owner, key_val(rule, &rule->owner), sizeof(udev->owner)); 1028 udev_rules_apply_format(udev, udev->owner, sizeof(udev->owner)); 1029 dbg("applied owner='%s' to '%s'", udev->owner, udev->dev->kernel); 1030 } 1031 if (!udev->group_final && rule->group.operation != KEY_OP_UNSET) { 1032 if (rule->group.operation == KEY_OP_ASSIGN_FINAL) 1033 udev->group_final = 1; 1034 strlcpy(udev->group, key_val(rule, &rule->group), sizeof(udev->group)); 1035 udev_rules_apply_format(udev, udev->group, sizeof(udev->group)); 1036 dbg("applied group='%s' to '%s'", udev->group, udev->dev->kernel); 1037 } 1038 1039 /* collect symlinks */ 1040 if (!udev->symlink_final && rule->symlink.operation != KEY_OP_UNSET) { 1041 char temp[PATH_SIZE]; 1042 char *pos, *next; 1043 int count; 1044 1045 if (rule->symlink.operation == KEY_OP_ASSIGN_FINAL) 1046 udev->symlink_final = 1; 1047 if (rule->symlink.operation == KEY_OP_ASSIGN || rule->symlink.operation == KEY_OP_ASSIGN_FINAL) { 1048 info("reset symlink list"); 1049 name_list_cleanup(&udev->symlink_list); 1050 } 1051 /* allow multiple symlinks separated by spaces */ 1052 strlcpy(temp, key_val(rule, &rule->symlink), sizeof(temp)); 1053 udev_rules_apply_format(udev, temp, sizeof(temp)); 1054 if (rule->string_escape == ESCAPE_UNSET || 1055 rule->string_escape == ESCAPE_REPLACE) { 1056 count = replace_chars(temp, ALLOWED_CHARS_FILE " "); 1057 if (count > 0) 1058 info("%i character(s) replaced" , count); 1059 } 1060 dbg("rule applied, added symlink(s) '%s'", temp); 1061 pos = temp; 1062 while (isspace(pos[0])) 1063 pos++; 1064 next = strchr(pos, ' '); 1065 while (next) { 1066 next[0] = '\0'; 1067 info("add symlink '%s'", pos); 1068 name_list_add(&udev->symlink_list, pos, 0); 1069 while (isspace(next[1])) 1070 next++; 1071 pos = &next[1]; 1072 next = strchr(pos, ' '); 1073 } 1074 if (pos[0] != '\0') { 1075 info("add symlink '%s'", pos); 1076 name_list_add(&udev->symlink_list, pos, 0); 1077 } 1078 } 1079 1080 /* set name, later rules with name set will be ignored */ 1081 if (rule->name.operation == KEY_OP_ASSIGN || 1082 rule->name.operation == KEY_OP_ASSIGN_FINAL || 1083 rule->name.operation == KEY_OP_ADD) { 1084 int count; 1085 1086 name_set = 1; 1087 strlcpy(udev->name, key_val(rule, &rule->name), sizeof(udev->name)); 1088 udev_rules_apply_format(udev, udev->name, sizeof(udev->name)); 1089 if (rule->string_escape == ESCAPE_UNSET || 1090 rule->string_escape == ESCAPE_REPLACE) { 1091 count = replace_chars(udev->name, ALLOWED_CHARS_FILE); 1092 if (count > 0) 1093 info("%i character(s) replaced", count); 1094 } 1095 1096 info("rule applied, '%s' becomes '%s'", udev->dev->kernel, udev->name); 1097 if (strcmp(udev->dev->subsystem, "net") != 0) 1098 dbg("name, '%s' is going to have owner='%s', group='%s', mode=%#o partitions=%i", 1099 udev->name, udev->owner, udev->group, udev->mode, udev->partitions); 1100 } 1101 1102 if (!udev->run_final && rule->run.operation != KEY_OP_UNSET) { 1103 if (rule->run.operation == KEY_OP_ASSIGN_FINAL) 1104 udev->run_final = 1; 1105 if (rule->run.operation == KEY_OP_ASSIGN || rule->run.operation == KEY_OP_ASSIGN_FINAL) { 1106 info("reset run list"); 1107 name_list_cleanup(&udev->run_list); 1108 } 1109 dbg("add run '%s'", key_val(rule, &rule->run)); 1110 name_list_add(&udev->run_list, key_val(rule, &rule->run), 0); 1111 } 1112 1113 if (rule->last_rule) { 1114 dbg("last rule to be applied"); 1115 break; 1116 } 1117 1118 if (rule->goto_label.operation != KEY_OP_UNSET) { 1119 dbg("moving forward to label '%s'", key_val(rule, &rule->goto_label)); 1120 udev_rules_iter_label(rules, key_val(rule, &rule->goto_label)); 1121 } 1122 } 1123 } 1124 1125 if (!name_set) { 1126 strlcpy(udev->name, udev->dev->kernel, sizeof(udev->name)); 1127 info("no node name set, will use kernel name '%s'", udev->name); 1128 } 1129 1130 if (udev->tmp_node[0] != '\0') { 1131 dbg("removing temporary device node"); 1132 unlink_secure(udev->tmp_node); 1133 udev->tmp_node[0] = '\0'; 1134 } 1135 1136 return 0; 1137} 1138 1139int udev_rules_get_run(struct udev_rules *rules, struct udevice *udev) 1140{ 1141 struct udev_rule *rule; 1142 1143 dbg("udev->kernel='%s'", udev->dev->kernel); 1144 1145 /* look for a matching rule to apply */ 1146 udev_rules_iter_init(rules); 1147 while (1) { 1148 rule = udev_rules_iter_next(rules); 1149 if (rule == NULL) 1150 break; 1151 1152 dbg("process rule"); 1153 if (rule->name.operation != KEY_OP_UNSET || rule->symlink.operation != KEY_OP_UNSET || 1154 rule->mode_operation != KEY_OP_UNSET || rule->owner.operation != KEY_OP_UNSET || 1155 rule->group.operation != KEY_OP_UNSET) { 1156 dbg("skip rule that names a device"); 1157 continue; 1158 } 1159 1160 if (match_rule(udev, rule) == 0) { 1161 if (rule->ignore_device) { 1162 info("rule applied, '%s' is ignored", udev->dev->kernel); 1163 udev->ignore_device = 1; 1164 return 0; 1165 } 1166 1167 if (!udev->run_final && rule->run.operation != KEY_OP_UNSET) { 1168 if (rule->run.operation == KEY_OP_ASSIGN || 1169 rule->run.operation == KEY_OP_ASSIGN_FINAL) { 1170 info("reset run list"); 1171 name_list_cleanup(&udev->run_list); 1172 } 1173 dbg("add run '%s'", key_val(rule, &rule->run)); 1174 name_list_add(&udev->run_list, key_val(rule, &rule->run), 0); 1175 if (rule->run.operation == KEY_OP_ASSIGN_FINAL) 1176 break; 1177 } 1178 1179 if (rule->last_rule) { 1180 dbg("last rule to be applied"); 1181 break; 1182 } 1183 1184 if (rule->goto_label.operation != KEY_OP_UNSET) { 1185 dbg("moving forward to label '%s'", key_val(rule, &rule->goto_label)); 1186 udev_rules_iter_label(rules, key_val(rule, &rule->goto_label)); 1187 } 1188 } 1189 } 1190 1191 return 0; 1192} 1193