summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--namedev.c1
-rw-r--r--namedev.h2
-rw-r--r--namedev_parse.c8
-rw-r--r--test/udev-test.pl25
-rw-r--r--udev.8.in7
-rw-r--r--udev.h1
-rw-r--r--udev_db.c18
-rw-r--r--udev_remove.c5
8 files changed, 62 insertions, 5 deletions
diff --git a/namedev.c b/namedev.c
index c5c7929ab2..69669709df 100644
--- a/namedev.c
+++ b/namedev.c
@@ -807,6 +807,7 @@ found:
goto done;
udev->partitions = dev->partitions;
+ udev->ignore_remove = dev->ignore_remove;
/* get permissions given in rule */
set_empty_perms(udev, dev->mode,
diff --git a/namedev.h b/namedev.h
index 7a98d66c24..8e552c8568 100644
--- a/namedev.h
+++ b/namedev.h
@@ -52,6 +52,7 @@ struct sysfs_class_device;
#define FIELD_MODE "MODE"
#define ATTR_PARTITIONS "all_partitions"
+#define ATTR_IGNORE_REMOVE "ignore_remove"
#define PARTITIONS_COUNT 15
#define MAX_SYSFS_PAIRS 5
@@ -90,6 +91,7 @@ struct config_device {
char group[GROUP_SIZE];
unsigned int mode;
int partitions;
+ int ignore_remove;
char config_file[NAME_SIZE];
int config_line;
};
diff --git a/namedev_parse.c b/namedev_parse.c
index 4afa85cfa9..cb1760fd57 100644
--- a/namedev_parse.c
+++ b/namedev_parse.c
@@ -278,10 +278,16 @@ static int namedev_parse_rules(const char *filename, void *data)
if (strncasecmp(temp2, FIELD_NAME, sizeof(FIELD_NAME)-1) == 0) {
attr = get_key_attribute(temp2 + sizeof(FIELD_NAME)-1);
- if (attr != NULL && strcasecmp(attr, ATTR_PARTITIONS) == 0) {
+ if (attr != NULL) {
+ if (strstr(attr, ATTR_PARTITIONS) != NULL) {
dbg_parse("creation of partition nodes requested");
dev.partitions = PARTITIONS_COUNT;
}
+ if (strstr(attr, ATTR_IGNORE_REMOVE) != NULL) {
+ dbg_parse("remove event should be ignored");
+ dev.ignore_remove = 1;
+ }
+ }
strfieldcpy(dev.name, temp3);
valid = 1;
continue;
diff --git a/test/udev-test.pl b/test/udev-test.pl
index 1e06df5220..d584579584 100644
--- a/test/udev-test.pl
+++ b/test/udev-test.pl
@@ -1105,7 +1105,28 @@ KERNEL="sda", NAME="cdrom%e"
EOF
},
{
- desc => "SUBSYSTEM test",
+ desc => "ignore remove event test",
+ subsys => "block",
+ devpath => "/block/sda",
+ exp_name => "node",
+ exp_error => "yes",
+ conf => <<EOF
+BUS="scsi", KERNEL="sda", NAME{ignore_remove}="node"
+EOF
+ },
+ {
+ desc => "ignore remove event test (with all partitions)",
+ subsys => "block",
+ devpath => "/block/sda",
+ exp_name => "node14",
+ exp_error => "yes",
+ option => "clear",
+ conf => <<EOF
+BUS="scsi", KERNEL="sda", NAME{ignore_remove, all_partitions}="node"
+EOF
+ },
+ {
+ desc => "SUBSYSTEM match test",
subsys => "block",
devpath => "/block/sda",
exp_name => "node",
@@ -1116,7 +1137,7 @@ BUS="scsi", KERNEL="sda", NAME="should_not_match2", SUBSYSTEM="vc"
EOF
},
{
- desc => "DRIVER test",
+ desc => "DRIVER match test",
subsys => "block",
devpath => "/block/sda",
exp_name => "node",
diff --git a/udev.8.in b/udev.8.in
index b5296b472d..728ddb1a45 100644
--- a/udev.8.in
+++ b/udev.8.in
@@ -216,6 +216,13 @@ If given with the attribute
.BR NAME{ all_partitions }
it will create all 15 partitions of a blockdevice.
This may be useful for removable media devices.
+.br
+If given with the attribute
+.BR NAME{ ignore_remove }
+it will will ignore any later remove event for this device.
+This may be useful as a workaround for broken device drivers.
+.sp
+Multiple attributes may be separated by comma.
.TP
.B SYMLINK
The name of a symlink targeting the node. Multiple symlinks may be
diff --git a/udev.h b/udev.h
index 73733ad3bb..d9a775ae91 100644
--- a/udev.h
+++ b/udev.h
@@ -57,6 +57,7 @@ struct udevice {
mode_t mode;
char symlink[NAME_SIZE];
int partitions;
+ int ignore_remove;
int config_line;
char config_file[NAME_SIZE];
long config_uptime;
diff --git a/udev_db.c b/udev_db.c
index f2a890ea42..e07e72b858 100644
--- a/udev_db.c
+++ b/udev_db.c
@@ -79,7 +79,8 @@ int udev_db_add_device(struct udevice *udev)
fprintf(f, "P:%s\n", udev->devpath);
fprintf(f, "N:%s\n", udev->name);
fprintf(f, "S:%s\n", udev->symlink);
- fprintf(f, "A:%d\n", udev->partitions);
+ fprintf(f, "A:%u\n", udev->partitions);
+ fprintf(f, "R:%u\n", udev->ignore_remove);
fclose(f);
@@ -111,21 +112,34 @@ static int parse_db_file(struct udevice *udev, const char *filename)
if (count > DEVPATH_SIZE)
count = DEVPATH_SIZE-1;
strncpy(udev->devpath, &bufline[2], count-2);
+ udev->devpath[count-2] = '\0';
break;
case 'N':
if (count > NAME_SIZE)
count = NAME_SIZE-1;
strncpy(udev->name, &bufline[2], count-2);
+ udev->name[count-2] = '\0';
break;
case 'S':
if (count > NAME_SIZE)
count = NAME_SIZE-1;
strncpy(udev->symlink, &bufline[2], count-2);
+ udev->symlink[count-2] = '\0';
break;
case 'A':
- strfieldcpy(line, &bufline[2]);
+ if (count > NAME_SIZE)
+ count = NAME_SIZE-1;
+ strncpy(line, &bufline[2], count-2);
+ line[count-2] = '\0';
udev->partitions = atoi(line);
break;
+ case 'R':
+ if (count > NAME_SIZE)
+ count = NAME_SIZE-1;
+ strncpy(line, &bufline[2], count-2);
+ line[count-2] = '\0';
+ udev->ignore_remove = atoi(line);
+ break;
}
}
diff --git a/udev_remove.c b/udev_remove.c
index 32cd785984..8887125dd8 100644
--- a/udev_remove.c
+++ b/udev_remove.c
@@ -185,6 +185,11 @@ int udev_remove_device(struct udevice *udev)
dbg("'%s' not found in database, falling back on default name", udev->name);
}
+ if (udev->ignore_remove) {
+ dbg("remove event for '%s' requested to be ignored by rule", udev->name);
+ return 0;
+ }
+
dbg("remove name='%s'", udev->name);
udev_db_delete_device(udev);