summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--namedev.c21
-rw-r--r--test/udev-test.pl18
-rw-r--r--udev.8.in7
-rw-r--r--udev.h3
-rw-r--r--udev_add.c6
-rw-r--r--udev_remove.c39
-rw-r--r--udev_utils.c25
-rw-r--r--udev_utils.h1
8 files changed, 80 insertions, 40 deletions
diff --git a/namedev.c b/namedev.c
index 0c5d0509f9..332e2d57d8 100644
--- a/namedev.c
+++ b/namedev.c
@@ -201,6 +201,12 @@ static void apply_format(struct udevice *udev, char *string, size_t maxsize,
switch (c) {
+ case 'p':
+ if (strlen(udev->devpath) == 0)
+ break;
+ strfieldcatmax(string, udev->devpath, maxsize);
+ dbg("substitute kernel name '%s'", udev->kernel_name);
+ break;
case 'b':
if (strlen(udev->bus_id) == 0)
break;
@@ -290,6 +296,15 @@ static void apply_format(struct udevice *udev, char *string, size_t maxsize,
strfieldcatmax(string, temp2, maxsize);
}
break;
+ case 'N':
+ if (udev->tmp_node[0] == '\0') {
+ dbg("create temporary device node for callout");
+ snprintf(udev->tmp_node, NAME_SIZE-1, "%s/.tmp-%u-%u", udev_root, udev->major, udev->minor);
+ udev_make_node(udev, udev->tmp_node, udev->major, udev->minor, 0600, 0, 0);
+ }
+ strfieldcatmax(string, udev->tmp_node, maxsize);
+ dbg("substitute temporary device node name '%s'", udev->tmp_node);
+ break;
default:
dbg("unknown substitution type '%%%c'", c);
break;
@@ -787,5 +802,11 @@ int namedev_name_device(struct udevice *udev, struct sysfs_class_device *class_d
dbg("no rule found, use kernel name '%s'", udev->name);
exit:
+ if (udev->tmp_node[0] != '\0') {
+ dbg("removing temporary device node");
+ unlink_secure(udev->tmp_node);
+ udev->tmp_node[0] = '\0';
+ }
+
return 0;
}
diff --git a/test/udev-test.pl b/test/udev-test.pl
index 67c0672759..fa1e4affc6 100644
--- a/test/udev-test.pl
+++ b/test/udev-test.pl
@@ -1068,6 +1068,24 @@ BUS="scsi", KERNEL="sda", NAME="should_not_match", DRIVER="sd-wrong"
BUS="scsi", KERNEL="sda", NAME="node", DRIVER="sd"
EOF
},
+ {
+ desc => "temporary node creation test",
+ subsys => "block",
+ devpath => "/block/sda",
+ exp_name => "sda",
+ conf => <<EOF
+BUS="scsi", KERNEL="sda", PROGRAM="/usr/bin/test -b %N" NAME="%N"
+EOF
+ },
+ {
+ desc => "devpath substitution test",
+ subsys => "block",
+ devpath => "/block/sda",
+ exp_name => "sda",
+ conf => <<EOF
+BUS="scsi", KERNEL="sda", PROGRAM="/bin/echo %p", RESULT="/block/sda" NAME="%k"
+EOF
+ },
);
# set env
diff --git a/udev.8.in b/udev.8.in
index aaaf231636..51c55bc5a6 100644
--- a/udev.8.in
+++ b/udev.8.in
@@ -188,6 +188,9 @@ For example, 'sda3' has a "kernel number" of '3'.
.B %k
The "kernel name" for the device.
.TP
+.B %p
+The devpath for the device.
+.TP
.B %M
The kernel major number for the device.
.TP
@@ -211,6 +214,10 @@ If the number is followed by the + char this part plus
all remaining parts of the result string are substituted:
.BI %c{ N+ }
.TP
+.B %N
+The name of a created temporary device node to provide access to the
+device from a external program.
+.TP
.BI %s{ filename }
The content of a sysfs attribute.
.TP
diff --git a/udev.h b/udev.h
index 07385ccec5..5beec64557 100644
--- a/udev.h
+++ b/udev.h
@@ -23,6 +23,7 @@
#ifndef _UDEV_H_
#define _UDEV_H_
+#include <sys/types.h>
#include <sys/param.h>
#include "libsysfs/sysfs/libsysfs.h"
@@ -59,6 +60,7 @@ struct udevice {
int minor;
char devname[NAME_SIZE];
+ char tmp_node[NAME_SIZE];
int partitions;
int ignore_remove;
int config_line;
@@ -75,6 +77,7 @@ extern int udev_remove_device(struct udevice *udev);
extern void udev_init_config(void);
extern int udev_start(void);
extern void udev_multiplex_directory(struct udevice *udev, const char *basedir, const char *suffix);
+extern int udev_make_node(struct udevice *udev, const char *file, int major, int minor, mode_t mode, uid_t uid, gid_t gid);
extern char sysfs_path[SYSFS_PATH_MAX];
extern char udev_root[PATH_MAX];
diff --git a/udev_add.c b/udev_add.c
index 24a20bba9b..a495902ab2 100644
--- a/udev_add.c
+++ b/udev_add.c
@@ -67,7 +67,7 @@ error:
return -1;
}
-static int make_node(struct udevice *udev, char *file, int major, int minor, unsigned int mode, uid_t uid, gid_t gid)
+int udev_make_node(struct udevice *udev, const char *file, int major, int minor, mode_t mode, uid_t uid, gid_t gid)
{
struct stat stats;
int retval = 0;
@@ -183,7 +183,7 @@ static int create_node(struct udevice *udev)
if (!udev->test_run) {
info("creating device node '%s'", filename);
- if (make_node(udev, filename, udev->major, udev->minor, udev->mode, uid, gid) != 0)
+ if (udev_make_node(udev, filename, udev->major, udev->minor, udev->mode, uid, gid) != 0)
goto error;
} else {
info("creating device node '%s', major = '%d', minor = '%d', "
@@ -198,7 +198,7 @@ static int create_node(struct udevice *udev)
for (i = 1; i <= udev->partitions; i++) {
strfieldcpy(partitionname, filename);
strintcat(partitionname, i);
- make_node(udev, partitionname, udev->major, udev->minor + i, udev->mode, uid, gid);
+ udev_make_node(udev, partitionname, udev->major, udev->minor + i, udev->mode, uid, gid);
}
}
}
diff --git a/udev_remove.c b/udev_remove.c
index 142503589a..e1af3dbef6 100644
--- a/udev_remove.c
+++ b/udev_remove.c
@@ -67,41 +67,6 @@ static int delete_path(const char *path)
return 0;
}
-/** Remove all permissions on the device node, before
- * unlinking it. This fixes a security issue.
- * If the user created a hard-link to the device node,
- * he can't use it any longer, because he lost permission
- * to do so.
- */
-static int secure_unlink(const char *filename)
-{
- int retval;
-
- retval = chown(filename, 0, 0);
- if (retval) {
- dbg("chown(%s, 0, 0) failed with error '%s'",
- filename, strerror(errno));
- /* We continue nevertheless.
- * I think it's very unlikely for chown
- * to fail here, if the file exists.
- */
- }
- retval = chmod(filename, 0000);
- if (retval) {
- dbg("chmod(%s, 0000) failed with error '%s'",
- filename, strerror(errno));
- /* We continue nevertheless. */
- }
- retval = unlink(filename);
- if (errno == ENOENT)
- retval = 0;
- if (retval) {
- dbg("unlink(%s) failed with error '%s'",
- filename, strerror(errno));
- }
- return retval;
-}
-
static int delete_node(struct udevice *udev)
{
char filename[NAME_SIZE];
@@ -116,7 +81,7 @@ static int delete_node(struct udevice *udev)
filename[NAME_SIZE-1] = '\0';
info("removing device node '%s'", filename);
- retval = secure_unlink(filename);
+ retval = unlink_secure(filename);
if (retval)
return retval;
@@ -131,7 +96,7 @@ static int delete_node(struct udevice *udev)
for (i = 1; i <= num; i++) {
strfieldcpy(partitionname, filename);
strintcat(partitionname, i);
- secure_unlink(partitionname);
+ unlink_secure(partitionname);
}
}
diff --git a/udev_utils.c b/udev_utils.c
index 5b0355d0e9..ca46258def 100644
--- a/udev_utils.c
+++ b/udev_utils.c
@@ -112,6 +112,31 @@ int create_path(const char *path)
return mkdir(p, 0755);
}
+/* Reset permissions on the device node, before unlinking it to make sure,
+ * that permisions of possible hard links will be removed to.
+ */
+int unlink_secure(const char *filename)
+{
+ int retval;
+
+ retval = chown(filename, 0, 0);
+ if (retval)
+ dbg("chown(%s, 0, 0) failed with error '%s'", filename, strerror(errno));
+
+ retval = chmod(filename, 0000);
+ if (retval)
+ dbg("chmod(%s, 0000) failed with error '%s'", filename, strerror(errno));
+
+ retval = unlink(filename);
+ if (errno == ENOENT)
+ retval = 0;
+
+ if (retval)
+ dbg("unlink(%s) failed with error '%s'", filename, strerror(errno));
+
+ return retval;
+}
+
int parse_get_pair(char **orig_string, char **left, char **right)
{
char *temp;
diff --git a/udev_utils.h b/udev_utils.h
index 5d2c9c580c..19061f16f6 100644
--- a/udev_utils.h
+++ b/udev_utils.h
@@ -80,6 +80,7 @@ extern void udev_init_device(struct udevice *udev, const char* devpath, const ch
extern int kernel_release_satisfactory(unsigned int version, unsigned int patchlevel, unsigned int sublevel);
extern int create_path(const char *path);
extern int parse_get_pair(char **orig_string, char **left, char **right);
+extern int unlink_secure(const char *filename);
extern int file_map(const char *filename, char **buf, size_t *bufsize);
extern void file_unmap(char *buf, size_t bufsize);
extern size_t buf_get_line(const char *buf, size_t buflen, size_t cur);