X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=udev_rules.c;h=eccea3b57c75c1a4aae4db773c2bdd1e4ff78e4f;hp=e2877abe70be961b112c84beac4390b64985815a;hb=573bdd7e7588b70105c2976859696037899e9d4d;hpb=19096c087f8e1fc9f60ceb948f8be9b179885569 diff --git a/udev_rules.c b/udev_rules.c index e2877abe7..eccea3b57 100644 --- a/udev_rules.c +++ b/udev_rules.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -349,11 +350,6 @@ static int import_keys_into_env(struct udevice *udev, const char *buf, size_t bu cur += count+1; lineno++; - if (count >= sizeof(line)) { - err("line too long, conf line skipped %s, line %d", udev_config_filename, lineno); - continue; - } - /* eat the whitespace */ while ((count > 0) && isspace(bufline[0])) { bufline++; @@ -366,6 +362,11 @@ static int import_keys_into_env(struct udevice *udev, const char *buf, size_t bu if (bufline[0] == COMMENT_CHARACTER) continue; + if (count >= sizeof(line)) { + err("line too long, conf line skipped %s, line %d", udev_config_filename, lineno); + continue; + } + memcpy(line, bufline, count); line[count] = '\0'; @@ -454,36 +455,49 @@ static int import_parent_into_env(struct udevice *udev, const char *filter) return rc; } -static int pass_env_to_socket(const char *sockname, const char *devpath, const char *action) +static int pass_env_to_socket(const char *sockpath, const char *devpath, const char *action) { int sock; struct sockaddr_un saddr; - socklen_t addrlen; + socklen_t saddrlen; + struct stat stats; char buf[2048]; size_t bufpos = 0; int i; ssize_t count; int retval = 0; - dbg("pass environment to socket '%s'", sockname); + dbg("pass environment to socket '%s'", sockpath); sock = socket(AF_LOCAL, SOCK_DGRAM, 0); memset(&saddr, 0x00, sizeof(struct sockaddr_un)); saddr.sun_family = AF_LOCAL; - /* abstract namespace only */ - strcpy(&saddr.sun_path[1], sockname); - addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path+1) + 1; + if (sockpath[0] == '@') { + /* abstract namespace socket requested */ + strlcpy(&saddr.sun_path[1], &sockpath[1], sizeof(saddr.sun_path)-1); + saddrlen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&saddr.sun_path[1]); + } else if (stat(sockpath, &stats) == 0 && S_ISSOCK(stats.st_mode)) { + /* existing socket file */ + strlcpy(saddr.sun_path, sockpath, sizeof(saddr.sun_path)); + saddrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path); + } else { + /* no socket file, assume abstract namespace socket */ + strlcpy(&saddr.sun_path[1], sockpath, sizeof(saddr.sun_path)-1); + saddrlen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&saddr.sun_path[1]); + } bufpos = snprintf(buf, sizeof(buf)-1, "%s@%s", action, devpath); bufpos++; - for (i = 0; environ[i] != NULL && bufpos < sizeof(buf); i++) { + for (i = 0; environ[i] != NULL && bufpos < (sizeof(buf)-1); i++) { bufpos += strlcpy(&buf[bufpos], environ[i], sizeof(buf) - bufpos-1); bufpos++; } + if (bufpos > sizeof(buf)) + bufpos = sizeof(buf); - count = sendto(sock, &buf, bufpos, 0, (struct sockaddr *)&saddr, addrlen); + count = sendto(sock, &buf, bufpos, 0, (struct sockaddr *)&saddr, saddrlen); if (count < 0) retval = -1; - info("passed %zi bytes to socket '%s', ", count, sockname); + info("passed %zi bytes to socket '%s', ", count, sockpath); close(sock); return retval; @@ -583,6 +597,44 @@ out: return found; } +static int attr_subst_subdir(char *attr, size_t len) +{ + char *pos; + int found = 0; + + pos = strstr(attr, "/*/"); + if (pos != NULL) { + char str[PATH_SIZE]; + DIR *dir; + + pos[1] = '\0'; + strlcpy(str, &pos[2], sizeof(str)); + dir = opendir(attr); + if (dir != NULL) { + struct dirent *dent; + + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + struct stat stats; + + if (dent->d_name[0] == '.') + continue; + strlcat(attr, dent->d_name, len); + strlcat(attr, str, len); + if (stat(attr, &stats) == 0) { + found = 1; + break; + } + pos[1] = '\0'; + } + closedir(dir); + } + if (!found) + strlcat(attr, str, len); + } + + return found; +} + void udev_rules_apply_format(struct udevice *udev, char *string, size_t maxsize) { char temp[PATH_SIZE]; @@ -604,6 +656,7 @@ void udev_rules_apply_format(struct udevice *udev, char *string, size_t maxsize) SUBST_ATTR, SUBST_PARENT, SUBST_TEMP_NODE, + SUBST_NAME, SUBST_ROOT, SUBST_SYS, SUBST_ENV, @@ -625,6 +678,7 @@ void udev_rules_apply_format(struct udevice *udev, char *string, size_t maxsize) { .name = "sysfs", .fmt = 's', .type = SUBST_ATTR }, { .name = "parent", .fmt = 'P', .type = SUBST_PARENT }, { .name = "tempnode", .fmt = 'N', .type = SUBST_TEMP_NODE }, + { .name = "name", .fmt = 'D', .type = SUBST_NAME }, { .name = "root", .fmt = 'r', .type = SUBST_ROOT }, { .name = "sys", .fmt = 'S', .type = SUBST_SYS }, { .name = "env", .fmt = 'E', .type = SUBST_ENV }, @@ -843,6 +897,10 @@ found: strlcat(string, udev->tmp_node, maxsize); dbg("substitute temporary device node name '%s'", udev->tmp_node); break; + case SUBST_NAME: + strlcat(string, udev->name, maxsize); + dbg("substitute udev->name '%s'", udev->name); + break; case SUBST_ROOT: strlcat(string, udev_root, maxsize); dbg("substitute udev_root '%s'", udev_root); @@ -986,7 +1044,8 @@ static int match_rule(struct udevice *udev, struct udev_rule *rule) } } - if (rule->test.operation != KEY_OP_UNSET) { + if (rule->test.operation == KEY_OP_MATCH || + rule->test.operation == KEY_OP_NOMATCH) { char filename[PATH_SIZE]; char devpath[PATH_SIZE]; char *attr; @@ -1003,8 +1062,18 @@ static int match_rule(struct udevice *udev, struct udev_rule *rule) strlcat(filename, "/", sizeof(filename)); strlcat(filename, attr, sizeof(filename)); } + } else if (filename[0] != '/') { + char tmp[PATH_SIZE]; + + strlcpy(tmp, sysfs_path, sizeof(tmp)); + strlcat(tmp, udev->dev->devpath, sizeof(tmp)); + strlcat(tmp, "/", sizeof(tmp)); + strlcat(tmp, filename, sizeof(tmp)); + strlcpy(filename, tmp, sizeof(filename)); } + attr_subst_subdir(filename, sizeof(filename)); + match = (stat(filename, &statbuf) == 0); info("'%s' %s", filename, match ? "exists" : "does not exist"); if (match && rule->test_mode_mask > 0) { @@ -1023,7 +1092,7 @@ static int match_rule(struct udevice *udev, struct udev_rule *rule) if (rule->wait_for_sysfs.operation != KEY_OP_UNSET) { int found; - found = (wait_for_sysfs(udev, key_val(rule, &rule->wait_for_sysfs), 3) == 0); + found = (wait_for_sysfs(udev, key_val(rule, &rule->wait_for_sysfs), 10) == 0); if (!found && (rule->wait_for_sysfs.operation != KEY_OP_NOMATCH)) goto nomatch; } @@ -1247,6 +1316,8 @@ try_parent: strlcat(attr, key_name, sizeof(attr)); } + attr_subst_subdir(attr, sizeof(attr)); + strlcpy(value, key_val(rule, &pair->key), sizeof(value)); udev_rules_apply_format(udev, value, sizeof(value)); info("writing '%s' to sysfs file '%s'", value, attr); @@ -1429,7 +1500,7 @@ int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev) } if (!name_set) { - info("no node name set, will use kernel name '%s'", udev->name); + info("no node name set, will use kernel name '%s'", udev->dev->kernel); strlcpy(udev->name, udev->dev->kernel, sizeof(udev->name)); } @@ -1456,9 +1527,14 @@ int udev_rules_get_run(struct udev_rules *rules, struct udevice *udev) break; dbg("process rule"); - if (rule->name.operation != KEY_OP_UNSET || rule->symlink.operation != KEY_OP_UNSET || - rule->mode_operation != KEY_OP_UNSET || rule->owner.operation != KEY_OP_UNSET || - rule->group.operation != KEY_OP_UNSET) { + if (rule->name.operation == KEY_OP_ASSIGN || + rule->name.operation == KEY_OP_ASSIGN_FINAL || + rule->name.operation == KEY_OP_ADD || + rule->symlink.operation == KEY_OP_ASSIGN || + rule->symlink.operation == KEY_OP_ASSIGN_FINAL || + rule->symlink.operation == KEY_OP_ADD || + rule->mode_operation != KEY_OP_UNSET || + rule->owner.operation != KEY_OP_UNSET || rule->group.operation != KEY_OP_UNSET) { dbg("skip rule that names a device"); continue; } @@ -1469,6 +1545,10 @@ int udev_rules_get_run(struct udev_rules *rules, struct udevice *udev) udev->ignore_device = 1; return 0; } + if (rule->ignore_remove) { + udev->ignore_remove = 1; + dbg("remove event should be ignored"); + } if (!udev->run_final && rule->run.operation != KEY_OP_UNSET) { struct name_entry *entry;