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;
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;
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;
}
conf => <<EOF
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
},
);
.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
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
#ifndef _UDEV_H_
#define _UDEV_H_
+#include <sys/types.h>
#include <sys/param.h>
#include "libsysfs/sysfs/libsysfs.h"
int minor;
char devname[NAME_SIZE];
+ char tmp_node[NAME_SIZE];
int partitions;
int ignore_remove;
int config_line;
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];
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;
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', "
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);
}
}
}
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];
filename[NAME_SIZE-1] = '\0';
info("removing device node '%s'", filename);
- retval = secure_unlink(filename);
+ retval = unlink_secure(filename);
if (retval)
return retval;
for (i = 1; i <= num; i++) {
strfieldcpy(partitionname, filename);
strintcat(partitionname, i);
- secure_unlink(partitionname);
+ unlink_secure(partitionname);
}
}
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;
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);