/*
- * udev_rules.c
- *
* Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
* Copyright (C) 2003-2006 Kay Sievers <kay.sievers@vrfy.org>
*
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include <unistd.h>
#include <errno.h>
#include <syslog.h>
+#include <fnmatch.h>
#include <sys/wait.h>
#include <sys/stat.h>
if (pos) {
pos[0] = '\0';
pos++;
- if (strcmp_pattern(filter, name) == 0) {
+ if (fnmatch(filter, name, 0) == 0) {
dbg("import key '%s'", name_loop->name);
name_list_add(&udev->env_list, name_loop->name, 0);
setenv(name, pos, 1);
}
break;
case SUBST_ATTR:
- if (attr == NULL) {
- dbg("missing attribute");
- break;
- } else {
- struct sysfs_device *dev_parent;
- const char *value;
+ if (attr == NULL)
+ err("missing file parameter for attr");
+ else {
+ const char *value = NULL;
+ size_t size;
+
+ /* first try the current device, other matches may have selected */
+ if (udev->dev_parent != NULL && udev->dev_parent != udev->dev)
+ value = sysfs_attr_get_value(udev->dev_parent->devpath, attr);
+
+ /* look at all devices along the chain of parents */
+ if (value == NULL) {
+ struct sysfs_device *dev_parent = udev->dev;
+
+ do {
+ dbg("looking at '%s'", dev_parent->devpath);
+ value = sysfs_attr_get_value(dev_parent->devpath, attr);
+ if (value != NULL) {
+ strlcpy(temp2, value, sizeof(temp2));
+ break;
+ }
+ dev_parent = sysfs_device_get_parent(dev_parent);
+ } while (dev_parent != NULL);
+ }
- dev_parent = udev->dev;
- do {
- dbg("looking at '%s'", dev_parent->devpath);
- value = sysfs_attr_get_value(dev_parent->devpath, attr);
- if (value != NULL) {
- strlcpy(temp2, value, sizeof(temp2));
- break;
- }
- dev_parent = sysfs_device_get_parent(dev_parent);
- } while (dev_parent != NULL);
+ if (value == NULL)
+ break;
- /* strip trailing whitespace of sysfs value */
- i = strlen(temp2);
- while (i > 0 && isspace(temp2[i-1]))
- temp2[--i] = '\0';
+ /* strip trailing whitespace and replace untrusted characters of sysfs value */
+ size = strlcpy(temp2, value, sizeof(temp2));
+ if (size >= sizeof(temp2))
+ size = sizeof(temp2)-1;
+ while (size > 0 && isspace(temp2[size-1]))
+ temp2[--size] = '\0';
count = replace_untrusted_chars(temp2);
- if (count)
+ if (count > 0)
info("%i untrusted character(s) replaced" , count);
strlcat(string, temp2, maxsize);
dbg("substitute sysfs value '%s'", temp2);
pos++;
}
dbg("match %s '%s' <-> '%s'", key_name, key_value, val);
- match = (strcmp_pattern(key_value, val) == 0);
+ match = (fnmatch(key_value, val, 0) == 0);
if (match && (key->operation != KEY_OP_NOMATCH)) {
dbg("%s is true (matching value)", key_name);
return 0;
int found;
found = (wait_for_sysfs(udev, key_val(rule, &rule->wait_for_sysfs), 3) == 0);
- if (!found && (rule->wait_for_sysfs.operation != KEY_OP_NOMATCH)) {
- dbg("WAIT_FOR_SYSFS failed");
+ if (!found && (rule->wait_for_sysfs.operation != KEY_OP_NOMATCH))
goto nomatch;
- }
}
- /* check for matching sysfs attrubute pairs */
- if (rule->attr.count) {
- dbg("check %i ATTR keys", rule->attr.count);
- for (i = 0; i < rule->attr.count; i++) {
- struct key_pair *pair = &rule->attr.keys[i];
+ /* check for matching sysfs attribute pairs */
+ for (i = 0; i < rule->attr.count; i++) {
+ struct key_pair *pair = &rule->attr.keys[i];
+
+ if (pair->key.operation == KEY_OP_MATCH ||
+ pair->key.operation == KEY_OP_NOMATCH) {
const char *key_name = key_pair_name(rule, pair);
const char *key_value = key_val(rule, &pair->key);
const char *value;
if (match_key("ATTR", rule, &pair->key, val))
goto nomatch;
}
- dbg("all %i ATTR keys matched", rule->attr.count);
}
/* walk up the chain of parent devices and find a match */
if (match_key("DRIVERS", rule, &rule->drivers, udev->dev_parent->driver))
goto try_parent;
- /* check for matching sysfs attrubute pairs */
- if (rule->attrs.count) {
- dbg("check %i ATTRS keys", rule->attrs.count);
- for (i = 0; i < rule->attrs.count; i++) {
- struct key_pair *pair = &rule->attrs.keys[i];
+ /* check for matching sysfs attribute pairs */
+ for (i = 0; i < rule->attrs.count; i++) {
+ struct key_pair *pair = &rule->attrs.keys[i];
+
+ if (pair->key.operation == KEY_OP_MATCH ||
+ pair->key.operation == KEY_OP_NOMATCH) {
const char *key_name = key_pair_name(rule, pair);
const char *key_value = key_val(rule, &pair->key);
const char *value;
if (match_key("ATTRS", rule, &pair->key, val))
goto try_parent;
}
- dbg("all %i ATTRS keys matched", rule->attrs.count);
}
/* found matching device */
struct key_pair *pair = &rule->env.keys[i];
if (pair->key.operation == KEY_OP_ASSIGN) {
+ char temp_value[NAME_SIZE];
const char *key_name = key_pair_name(rule, pair);
const char *value = key_val(rule, &pair->key);
- char *key_value = name_list_key_add(&udev->env_list, key_name, value);
+ char *key_value;
+
+ /* make sure we don't write to the same string we possibly read from */
+ strlcpy(temp_value, value, sizeof(temp_value));
+ udev_rules_apply_format(udev, temp_value, NAME_SIZE);
+
+ key_value = name_list_key_add(&udev->env_list, key_name, temp_value);
if (key_value == NULL)
break;
- udev_rules_apply_format(udev, key_value, NAME_SIZE);
putenv(key_value);
dbg("export ENV '%s'", key_value);
}
}
+ /* if we have ATTR assignements 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);
+ const char *key_value = key_val(rule, &pair->key);
+ char attr[PATH_SIZE];
+ FILE *f;
+
+ strlcpy(attr, sysfs_path, sizeof(attr));
+ strlcat(attr, udev->dev->devpath, sizeof(attr));
+ strlcat(attr, "/", sizeof(attr));
+ strlcat(attr, key_name, sizeof(attr));
+ dbg("write '%s' to '%s'", key_value, attr);
+ f = fopen(attr, "w");
+ if (f != NULL) {
+ if (fprintf(f, "%s\n", key_value) <= 0)
+ err("error writing ATTR{%s}: %s", attr, strerror(errno));
+ fclose(f);
+ } else
+ err("error opening ATTR{%s} for writing: %s", attr, strerror(errno));
+ }
+ }
return 0;
nomatch: