diff options
-rw-r--r-- | namedev.c | 21 | ||||
-rw-r--r-- | test/udev-test.pl | 18 | ||||
-rw-r--r-- | udev.8.in | 7 | ||||
-rw-r--r-- | udev.h | 3 | ||||
-rw-r--r-- | udev_add.c | 6 | ||||
-rw-r--r-- | udev_remove.c | 39 | ||||
-rw-r--r-- | udev_utils.c | 25 | ||||
-rw-r--r-- | udev_utils.h | 1 |
8 files changed, 80 insertions, 40 deletions
@@ -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 @@ -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 @@ -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); |