- dbg(event->udev, "result is '%s'\n", result);
- util_strlcpy(event->program_result, result, sizeof(event->program_result));
- dbg(event->udev, "PROGRAM returned successful\n");
- if (rule->program.operation == KEY_OP_NOMATCH)
- goto nomatch;
- }
- dbg(event->udev, "PROGRAM key is true\n");
- }
-
- /* check for matching result of external program */
- if (match_key(event->udev, "RESULT", rule, &rule->result, event->program_result))
- goto nomatch;
-
- /* import variables returned from program or or file into properties */
- if (rule->import.operation != KEY_OP_UNSET) {
- char import[UTIL_PATH_SIZE];
- int rc = -1;
-
- util_strlcpy(import, key_val(rule, &rule->import), sizeof(import));
- udev_event_apply_format(event, import, sizeof(import));
- dbg(event->udev, "check for IMPORT import='%s'\n", import);
- if (rule->import_type == IMPORT_PROGRAM) {
- rc = import_program_into_env(event->dev, import);
- } else if (rule->import_type == IMPORT_FILE) {
- dbg(event->udev, "import file import='%s'\n", import);
- rc = import_file_into_env(event->dev, import);
- } else if (rule->import_type == IMPORT_PARENT) {
- dbg(event->udev, "import parent import='%s'\n", import);
- rc = import_parent_into_env(event->dev, import);
- }
- if (rc != 0) {
- dbg(event->udev, "IMPORT failed\n");
- if (rule->import.operation != KEY_OP_NOMATCH)
- goto nomatch;
- } else
- dbg(event->udev, "IMPORT '%s' imported\n", key_val(rule, &rule->import));
- dbg(event->udev, "IMPORT key is true\n");
- }
-
- /* rule matches, if we have ENV assignments export it */
- for (i = 0; i < rule->env.count; i++) {
- struct key_pair *pair = &rule->env.keys[i];
-
- if (pair->key.operation == KEY_OP_ASSIGN) {
- char temp_value[UTIL_NAME_SIZE];
- const char *key_name = key_pair_name(rule, pair);
- const char *value = key_val(rule, &pair->key);
-
- /* make sure we don't write to the same string we possibly read from */
- util_strlcpy(temp_value, value, sizeof(temp_value));
- udev_event_apply_format(event, temp_value, sizeof(temp_value));
-
- if (temp_value[0] != '\0') {
- struct udev_list_entry *entry;
-
- info(event->udev, "set ENV '%s=%s'\n", key_name, temp_value);
- entry = udev_device_add_property(dev, key_name, temp_value);
- /* store in db */
- udev_list_entry_set_flag(entry, 1);
- }
- }
- }
-
- /* if we have ATTR assignments, write value to sysfs file */
- for (i = 0; i < rule->attr.count; i++) {
- struct key_pair *pair = &rule->attr.keys[i];
-
- if (pair->key.operation == KEY_OP_ASSIGN) {
- const char *key_name = key_pair_name(rule, pair);
- char attr[UTIL_PATH_SIZE];
- char value[UTIL_NAME_SIZE];
- FILE *f;
-
- util_strlcpy(attr, key_name, sizeof(attr));
- if (udev_event_apply_subsys_kernel(event, key_name, attr, sizeof(attr), 0) != 0) {
- util_strlcpy(attr, udev_device_get_syspath(dev), sizeof(attr));
- util_strlcat(attr, "/", sizeof(attr));
- util_strlcat(attr, key_name, sizeof(attr));
- }
-
- attr_subst_subdir(attr, sizeof(attr));
-
- util_strlcpy(value, key_val(rule, &pair->key), sizeof(value));
- udev_event_apply_format(event, value, sizeof(value));
- info(event->udev, "writing '%s' to sysfs file '%s'\n", value, attr);
- f = fopen(attr, "w");
- if (f != NULL) {
- if (!event->test)
- if (fprintf(f, "%s", value) <= 0)
- err(event->udev, "error writing ATTR{%s}: %m\n", attr);
- fclose(f);
- } else
- err(event->udev, "error opening ATTR{%s} for writing: %m\n", attr);
- }
- }
- return 0;
-
-nomatch:
- return -1;
-}
-
-int udev_rules_get_name(struct udev_rules *rules, struct udev_event *event)
-{
- struct udev_device *dev = event->dev;
- struct udev_rules_iter iter;
- struct udev_rule *rule;
- int name_set = 0;
-
- dbg(event->udev, "device: '%s'\n", udev_device_get_syspath(dev));
-
- /* look for a matching rule to apply */
- udev_rules_iter_init(&iter, rules);
- while (1) {
- rule = udev_rules_iter_next(&iter);
- if (rule == NULL)
- break;
-
- if (name_set &&
- (rule->name.operation == KEY_OP_ASSIGN ||
- rule->name.operation == KEY_OP_ASSIGN_FINAL ||
- rule->name.operation == KEY_OP_ADD)) {
- dbg(event->udev, "node name already set, rule ignored\n");
- continue;
- }
-
- dbg(event->udev, "process rule\n");
- if (match_rule(event, rule) == 0) {
- /* apply options */
- if (rule->ignore_device) {
- info(event->udev, "rule applied, '%s' is ignored\n", udev_device_get_sysname(dev));
- event->ignore_device = 1;
- return 0;
- }
- if (rule->ignore_remove) {
- udev_device_set_ignore_remove(dev, 1);
- dbg(event->udev, "remove event should be ignored\n");
- }
- if (rule->link_priority != 0) {
- udev_device_set_devlink_priority(dev, rule->link_priority);
- info(event->udev, "devlink_priority=%i\n", rule->link_priority);
- }
- if (rule->event_timeout >= 0) {
- udev_device_set_event_timeout(dev, rule->event_timeout);
- info(event->udev, "event_timeout=%i\n", rule->event_timeout);
- }
- /* apply all_partitions option only at a disk device */
- if (rule->partitions > 0 &&
- strcmp(udev_device_get_subsystem(dev), "block") == 0 &&
- udev_device_get_sysnum(dev) == NULL) {
- udev_device_set_num_fake_partitions(dev, rule->partitions);
- dbg(event->udev, "creation of partition nodes requested\n");
- }
-
- /* apply permissions */
- if (!event->mode_final && rule->mode.operation != KEY_OP_UNSET) {
- if (rule->mode.operation == KEY_OP_ASSIGN_FINAL)
- event->mode_final = 1;
- char buf[20];
- util_strlcpy(buf, key_val(rule, &rule->mode), sizeof(buf));
- udev_event_apply_format(event, buf, sizeof(buf));
- event->mode = strtol(buf, NULL, 8);
- dbg(event->udev, "applied mode=%#o to '%s'\n",
- event->mode, udev_device_get_sysname(dev));
- }
- if (!event->owner_final && rule->owner.operation != KEY_OP_UNSET) {
- if (rule->owner.operation == KEY_OP_ASSIGN_FINAL)
- event->owner_final = 1;
- util_strlcpy(event->owner, key_val(rule, &rule->owner), sizeof(event->owner));
- udev_event_apply_format(event, event->owner, sizeof(event->owner));
- dbg(event->udev, "applied owner='%s' to '%s'\n",
- event->owner, udev_device_get_sysname(dev));
- }
- if (!event->group_final && rule->group.operation != KEY_OP_UNSET) {
- if (rule->group.operation == KEY_OP_ASSIGN_FINAL)
- event->group_final = 1;
- util_strlcpy(event->group, key_val(rule, &rule->group), sizeof(event->group));
- udev_event_apply_format(event, event->group, sizeof(event->group));
- dbg(event->udev, "applied group='%s' to '%s'\n",
- event->group, udev_device_get_sysname(dev));
- }
-
- /* collect symlinks */
- if (!event->devlink_final &&
- (rule->symlink.operation == KEY_OP_ASSIGN ||
- rule->symlink.operation == KEY_OP_ASSIGN_FINAL ||
- rule->symlink.operation == KEY_OP_ADD)) {
- char temp[UTIL_PATH_SIZE];
- char filename[UTIL_PATH_SIZE];
- char *pos, *next;
- int count = 0;
-
- if (rule->symlink.operation == KEY_OP_ASSIGN_FINAL)
- event->devlink_final = 1;
- if (rule->symlink.operation == KEY_OP_ASSIGN ||
- rule->symlink.operation == KEY_OP_ASSIGN_FINAL) {
- info(event->udev, "reset symlink list\n");
- udev_device_cleanup_devlinks_list(dev);
- }
- /* allow multiple symlinks separated by spaces */
- util_strlcpy(temp, key_val(rule, &rule->symlink), sizeof(temp));
- udev_event_apply_format(event, temp, sizeof(temp));
- if (rule->string_escape == ESCAPE_UNSET)
- count = util_replace_chars(temp, ALLOWED_CHARS_FILE " ");
- else if (rule->string_escape == ESCAPE_REPLACE)
- count = util_replace_chars(temp, ALLOWED_CHARS_FILE);
- if (count > 0)
- info(event->udev, "%i character(s) replaced\n" , count);
- dbg(event->udev, "rule applied, added symlink(s) '%s'\n", temp);
- pos = temp;
- while (isspace(pos[0]))
- pos++;
- next = strchr(pos, ' ');
- while (next) {
- next[0] = '\0';
- info(event->udev, "add symlink '%s'\n", pos);
- util_strlcpy(filename, udev_get_dev_path(event->udev), sizeof(filename));
- util_strlcat(filename, "/", sizeof(filename));
- util_strlcat(filename, pos, sizeof(filename));
- udev_device_add_devlink(dev, filename);
- while (isspace(next[1]))
- next++;
- pos = &next[1];
- next = strchr(pos, ' ');
- }
- if (pos[0] != '\0') {
- info(event->udev, "add symlink '%s'\n", pos);
- util_strlcpy(filename, udev_get_dev_path(event->udev), sizeof(filename));
- util_strlcat(filename, "/", sizeof(filename));
- util_strlcat(filename, pos, sizeof(filename));
- udev_device_add_devlink(dev, filename);
- }
- }
-
- /* set name, later rules with name set will be ignored */
- if (rule->name.operation == KEY_OP_ASSIGN ||
- rule->name.operation == KEY_OP_ASSIGN_FINAL ||
- rule->name.operation == KEY_OP_ADD) {
- int count;
-
- name_set = 1;
- util_strlcpy(event->name, key_val(rule, &rule->name), sizeof(event->name));
- udev_event_apply_format(event, event->name, sizeof(event->name));
- if (rule->string_escape == ESCAPE_UNSET ||
- rule->string_escape == ESCAPE_REPLACE) {
- count = util_replace_chars(event->name, ALLOWED_CHARS_FILE);
- if (count > 0)
- info(event->udev, "%i character(s) replaced\n", count);
- }
-
- info(event->udev, "rule applied, '%s' becomes '%s'\n",
- udev_device_get_sysname(dev), event->name);
- if (strcmp(udev_device_get_subsystem(dev), "net") != 0)
- dbg(event->udev, "'%s' owner='%s', group='%s', mode=%#o partitions=%i\n",
- event->name, event->owner, event->group, event->mode,
- udev_device_get_num_fake_partitions(dev));
- }
-
- if (!event->run_final && rule->run.operation != KEY_OP_UNSET) {
- struct udev_list_entry *list_entry;
-
- if (rule->run.operation == KEY_OP_ASSIGN_FINAL)
- event->run_final = 1;
- if (rule->run.operation == KEY_OP_ASSIGN || rule->run.operation == KEY_OP_ASSIGN_FINAL) {
- info(event->udev, "reset run list\n");
- udev_list_cleanup_entries(event->udev, &event->run_list);
- }
- dbg(event->udev, "add run '%s'\n", key_val(rule, &rule->run));
- list_entry = udev_list_entry_add(event->udev, &event->run_list,
- key_val(rule, &rule->run), NULL, 1, 0);
- if (rule->run_ignore_error && list_entry != NULL)
- udev_list_entry_set_flag(list_entry, 1);
- }
-
- if (rule->last_rule) {
- dbg(event->udev, "last rule to be applied\n");
- break;
- }
-
- if (rule->goto_label.operation != KEY_OP_UNSET) {
- dbg(event->udev, "moving forward to label '%s'\n", key_val(rule, &rule->goto_label));
- udev_rules_iter_goto(&iter, rule->goto_rule_off);
- }
- }
- }
-
- if (!name_set) {
- info(event->udev, "no node name set, will use kernel name '%s'\n",
- udev_device_get_sysname(dev));
- util_strlcpy(event->name, udev_device_get_sysname(dev), sizeof(event->name));
- }
-
- if (event->tmp_node[0] != '\0') {
- dbg(event->udev, "removing temporary device node\n");
- unlink_secure(event->udev, event->tmp_node);
- event->tmp_node[0] = '\0';
- }
- return 0;
-}
-
-int udev_rules_get_run(struct udev_rules *rules, struct udev_event *event)
-{
- struct udev_device *dev = event->dev;
- struct udev_rules_iter iter;
- struct udev_rule *rule;
-
- dbg(event->udev, "sysname: '%s'\n", udev_device_get_sysname(dev));
-
- /* look for a matching rule to apply */
- udev_rules_iter_init(&iter, rules);
- while (1) {
- rule = udev_rules_iter_next(&iter);
- if (rule == NULL)
- break;
-
- dbg(event->udev, "process rule\n");
- 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(event->udev, "skip rule that names a device\n");
- continue;
- }
-
- if (match_rule(event, rule) == 0) {
- if (rule->ignore_device) {
- info(event->udev, "rule applied, '%s' is ignored\n", udev_device_get_sysname(dev));
- event->ignore_device = 1;
- return 0;
- }
- if (rule->ignore_remove) {
- udev_device_set_ignore_remove(dev, 1);
- dbg(event->udev, "remove event should be ignored\n");
- }
-
- if (!event->run_final && rule->run.operation != KEY_OP_UNSET) {
- struct udev_list_entry *list_entry;
-
- if (rule->run.operation == KEY_OP_ASSIGN ||
- rule->run.operation == KEY_OP_ASSIGN_FINAL) {
- info(event->udev, "reset run list\n");
- udev_list_cleanup_entries(event->udev, &event->run_list);
- }
- dbg(event->udev, "add run '%s'\n", key_val(rule, &rule->run));
- list_entry = udev_list_entry_add(event->udev, &event->run_list,
- key_val(rule, &rule->run), NULL, 1, 0);
- if (rule->run_ignore_error && list_entry != NULL)
- udev_list_entry_set_flag(list_entry, 1);
- if (rule->run.operation == KEY_OP_ASSIGN_FINAL)
- break;
- }
-
- if (rule->last_rule) {
- dbg(event->udev, "last rule to be applied\n");
- break;
- }
-
- if (rule->goto_label.operation != KEY_OP_UNSET) {
- dbg(event->udev, "moving forward to label '%s'\n", key_val(rule, &rule->goto_label));
- udev_rules_iter_goto(&iter, rule->goto_rule_off);
- }
- }
- }
-
- return 0;
-}
-
-static int get_key(struct udev_rules *rules, char **line, char **key, enum key_operation *operation, char **value)
-{
- char *linepos;
- char *temp;
-
- linepos = *line;
- if (linepos == NULL && linepos[0] == '\0')
- return -1;
-
- /* skip whitespace */
- while (isspace(linepos[0]) || linepos[0] == ',')
- linepos++;
-
- /* get the key */
- if (linepos[0] == '\0')
- return -1;
- *key = linepos;
-
- while (1) {
- linepos++;
- if (linepos[0] == '\0')
- return -1;
- if (isspace(linepos[0]))
- break;
- if (linepos[0] == '=')
- break;
- if ((linepos[0] == '+') || (linepos[0] == '!') || (linepos[0] == ':'))
- if (linepos[1] == '=')
- break;
- }
-
- /* remember end of key */
- temp = linepos;
-
- /* skip whitespace after key */
- while (isspace(linepos[0]))
- linepos++;
- if (linepos[0] == '\0')
- return -1;
-
- /* get operation type */
- if (linepos[0] == '=' && linepos[1] == '=') {
- *operation = KEY_OP_MATCH;
- linepos += 2;
- dbg(rules->udev, "match:\n");
- } else if (linepos[0] == '!' && linepos[1] == '=') {
- *operation = KEY_OP_NOMATCH;
- linepos += 2;
- dbg(rules->udev, "nomatch:\n");
- } else if (linepos[0] == '+' && linepos[1] == '=') {
- *operation = KEY_OP_ADD;
- linepos += 2;
- dbg(rules->udev, "add:\n");
- } else if (linepos[0] == '=') {
- *operation = KEY_OP_ASSIGN;
- linepos++;
- dbg(rules->udev, "assign:\n");
- } else if (linepos[0] == ':' && linepos[1] == '=') {
- *operation = KEY_OP_ASSIGN_FINAL;
- linepos += 2;
- dbg(rules->udev, "assign_final:\n");
- } else
- return -1;
-
- /* terminate key */
- temp[0] = '\0';
-
- /* skip whitespace after operator */
- while (isspace(linepos[0]))
- linepos++;
- if (linepos[0] == '\0')
- return -1;
-
- /* get the value*/
- if (linepos[0] == '"')
- linepos++;
- else
- return -1;
- *value = linepos;
-
- temp = strchr(linepos, '"');
- if (!temp)
- return -1;
- temp[0] = '\0';
- temp++;
- dbg(rules->udev, "'%s'-'%s'\n", *key, *value);
-
- /* move line to next key */
- *line = temp;
- return 0;
-}
-
-/* extract possible KEY{attr} */
-static char *get_key_attribute(struct udev_rules *rules, char *str)
-{
- char *pos;
- char *attr;
-
- attr = strchr(str, '{');
- if (attr != NULL) {
- attr++;
- pos = strchr(attr, '}');
- if (pos == NULL) {
- err(rules->udev, "missing closing brace for format\n");
- return NULL;
- }
- pos[0] = '\0';
- dbg(rules->udev, "attribute='%s'\n", attr);
- return attr;
- }
-
- return NULL;
-}
-
-static int add_rule_key(struct udev_rule *rule, struct key *key,
- enum key_operation operation, const char *value)
-{
- size_t val_len = strnlen(value, UTIL_PATH_SIZE);
-
- key->operation = operation;
-
- key->val_off = rule->bufsize;
- util_strlcpy(rule->buf + rule->bufsize, value, val_len+1);
- rule->bufsize += val_len+1;
-
- return 0;
-}
-
-static int add_rule_key_pair(struct udev_rules *rules, struct udev_rule *rule, struct key_pairs *pairs,
- enum key_operation operation, const char *key, const char *value)
-{
- size_t key_len = strnlen(key, UTIL_PATH_SIZE);
-
- if (pairs->count >= PAIRS_MAX) {
- err(rules->udev, "skip, too many keys of the same type in a single rule\n");
- return -1;
- }
-
- add_rule_key(rule, &pairs->keys[pairs->count].key, operation, value);
-
- /* add the key-name of the pair */
- pairs->keys[pairs->count].key_name_off = rule->bufsize;
- util_strlcpy(rule->buf + rule->bufsize, key, key_len+1);
- rule->bufsize += key_len+1;
-
- pairs->count++;
-
- return 0;
-}
-
-static int add_to_rules(struct udev_rules *rules, char *line, const char *filename, unsigned int lineno)
-{
- char buf[sizeof(struct udev_rule) + UTIL_LINE_SIZE];
- struct udev_rule *rule;
- size_t rule_size;
- int valid;
- char *linepos;
- char *attr;
- size_t padding;
- int physdev = 0;
-
- memset(buf, 0x00, sizeof(buf));
- rule = (struct udev_rule *) buf;
- rule->event_timeout = -1;
- linepos = line;
- valid = 0;
-
- /* get all the keys */
- while (1) {
- char *key;
- char *value;
- enum key_operation operation = KEY_OP_UNSET;
-
- if (get_key(rules, &linepos, &key, &operation, &value) != 0)
- break;
-
- if (strcasecmp(key, "ACTION") == 0) {
- if (operation != KEY_OP_MATCH &&
- operation != KEY_OP_NOMATCH) {
- err(rules->udev, "invalid ACTION operation\n");
- goto invalid;
- }
- add_rule_key(rule, &rule->action, operation, value);
- valid = 1;
- continue;
- }
-
- if (strcasecmp(key, "DEVPATH") == 0) {
- if (operation != KEY_OP_MATCH &&
- operation != KEY_OP_NOMATCH) {
- err(rules->udev, "invalid DEVPATH operation\n");
- goto invalid;
- }
- add_rule_key(rule, &rule->devpath, operation, value);
- valid = 1;
- continue;
- }
-
- if (strcasecmp(key, "KERNEL") == 0) {
- if (operation != KEY_OP_MATCH &&
- operation != KEY_OP_NOMATCH) {
- err(rules->udev, "invalid KERNEL operation\n");
- goto invalid;
- }
- add_rule_key(rule, &rule->kernel, operation, value);
- valid = 1;
- continue;