Skip to content

Commit

Permalink
Driver core: change add_uevent_var to use a struct
Browse files Browse the repository at this point in the history
This changes the uevent buffer functions to use a struct instead of a
long list of parameters. It does no longer require the caller to do the
proper buffer termination and size accounting, which is currently wrong
in some places. It fixes a known bug where parts of the uevent
environment are overwritten because of wrong index calculations.

Many thanks to Mathieu Desnoyers for finding bugs and improving the
error handling.

Signed-off-by: Kay Sievers <[email protected]>
Cc: Mathieu Desnoyers <[email protected]>
Cc: Cornelia Huck <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
kaysievers authored and gregkh committed Oct 12, 2007
1 parent 8380770 commit 7eff2e7
Show file tree
Hide file tree
Showing 47 changed files with 300 additions and 636 deletions.
3 changes: 1 addition & 2 deletions arch/ia64/sn/kernel/tiocx.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,7 @@ static int tiocx_match(struct device *dev, struct device_driver *drv)

}

static int tiocx_uevent(struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
static int tiocx_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return -ENODEV;
}
Expand Down
37 changes: 11 additions & 26 deletions arch/powerpc/kernel/of_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,26 +57,21 @@ ssize_t of_device_get_modalias(struct of_device *ofdev,
return tsize;
}

int of_device_uevent(struct device *dev,
char **envp, int num_envp, char *buffer, int buffer_size)
int of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct of_device *ofdev;
const char *compat;
int i = 0, length = 0, seen = 0, cplen, sl;
int seen = 0, cplen, sl;

if (!dev)
return -ENODEV;

ofdev = to_of_device(dev);

if (add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"OF_NAME=%s", ofdev->node->name))
if (add_uevent_var(env, "OF_NAME=%s", ofdev->node->name))
return -ENOMEM;

if (add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"OF_TYPE=%s", ofdev->node->type))
if (add_uevent_var(env, "OF_TYPE=%s", ofdev->node->type))
return -ENOMEM;

/* Since the compatible field can contain pretty much anything
Expand All @@ -85,9 +80,7 @@ int of_device_uevent(struct device *dev,

compat = of_get_property(ofdev->node, "compatible", &cplen);
while (compat && *compat && cplen > 0) {
if (add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"OF_COMPATIBLE_%d=%s", seen, compat))
if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat))
return -ENOMEM;

sl = strlen (compat) + 1;
Expand All @@ -96,25 +89,17 @@ int of_device_uevent(struct device *dev,
seen++;
}

if (add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"OF_COMPATIBLE_N=%d", seen))
if (add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen))
return -ENOMEM;

/* modalias is trickier, we add it in 2 steps */
if (add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"MODALIAS="))
if (add_uevent_var(env, "MODALIAS="))
return -ENOMEM;

sl = of_device_get_modalias(ofdev, &buffer[length-1],
buffer_size-length);
if (sl >= (buffer_size-length))
sl = of_device_get_modalias(ofdev, &env->buf[env->buflen-1],
sizeof(env->buf) - env->buflen);
if (sl >= (sizeof(env->buf) - env->buflen))
return -ENOMEM;

length += sl;

envp[i] = NULL;
env->buflen += sl;

return 0;
}
Expand Down
16 changes: 3 additions & 13 deletions arch/powerpc/kernel/vio.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,30 +317,20 @@ static int vio_bus_match(struct device *dev, struct device_driver *drv)
return (ids != NULL) && (vio_match_device(ids, vio_dev) != NULL);
}

static int vio_hotplug(struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
static int vio_hotplug(struct device *dev, struct kobj_uevent_env *env)
{
const struct vio_dev *vio_dev = to_vio_dev(dev);
struct device_node *dn;
const char *cp;
int length;

if (!num_envp)
return -ENOMEM;

dn = dev->archdata.of_node;
if (!dn)
return -ENODEV;
cp = of_get_property(dn, "compatible", &length);
cp = of_get_property(dn, "compatible", NULL);
if (!cp)
return -ENODEV;

envp[0] = buffer;
length = scnprintf(buffer, buffer_size, "MODALIAS=vio:T%sS%s",
vio_dev->type, cp);
if ((buffer_size - length) <= 0)
return -ENOMEM;
envp[1] = NULL;
add_uevent_var(env, "MODALIAS=vio:T%sS%s", vio_dev->type, cp);
return 0;
}

Expand Down
9 changes: 2 additions & 7 deletions arch/powerpc/platforms/ps3/system-bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -437,18 +437,13 @@ static void ps3_system_bus_shutdown(struct device *_dev)
dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
}

static int ps3_system_bus_uevent(struct device *_dev, char **envp,
int num_envp, char *buffer, int buffer_size)
static int ps3_system_bus_uevent(struct device *_dev, struct kobj_uevent_env *env)
{
struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
int i = 0, length = 0;

if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
&length, "MODALIAS=ps3:%d",
dev->match_id))
if (add_uevent_var(env, "MODALIAS=ps3:%d", dev->match_id))
return -ENOMEM;

envp[i] = NULL;
return 0;
}

Expand Down
35 changes: 8 additions & 27 deletions block/genhd.c
Original file line number Diff line number Diff line change
Expand Up @@ -540,61 +540,42 @@ static int block_uevent_filter(struct kset *kset, struct kobject *kobj)
return ((ktype == &ktype_block) || (ktype == &ktype_part));
}

static int block_uevent(struct kset *kset, struct kobject *kobj, char **envp,
int num_envp, char *buffer, int buffer_size)
static int block_uevent(struct kset *kset, struct kobject *kobj,
struct kobj_uevent_env *env)
{
struct kobj_type *ktype = get_ktype(kobj);
struct device *physdev;
struct gendisk *disk;
struct hd_struct *part;
int length = 0;
int i = 0;

if (ktype == &ktype_block) {
disk = container_of(kobj, struct gendisk, kobj);
add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
&length, "MINOR=%u", disk->first_minor);
add_uevent_var(env, "MINOR=%u", disk->first_minor);
} else if (ktype == &ktype_part) {
disk = container_of(kobj->parent, struct gendisk, kobj);
part = container_of(kobj, struct hd_struct, kobj);
add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
&length, "MINOR=%u",
add_uevent_var(env, "MINOR=%u",
disk->first_minor + part->partno);
} else
return 0;

add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
"MAJOR=%u", disk->major);
add_uevent_var(env, "MAJOR=%u", disk->major);

/* add physical device, backing this device */
physdev = disk->driverfs_dev;
if (physdev) {
char *path = kobject_get_path(&physdev->kobj, GFP_KERNEL);

add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
&length, "PHYSDEVPATH=%s", path);
add_uevent_var(env, "PHYSDEVPATH=%s", path);
kfree(path);

if (physdev->bus)
add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"PHYSDEVBUS=%s",
physdev->bus->name);
add_uevent_var(env, "PHYSDEVBUS=%s", physdev->bus->name);

if (physdev->driver)
add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"PHYSDEVDRIVER=%s",
physdev->driver->name);
add_uevent_var(env, physdev->driver->name);
}

/* terminate, set to next free slot, shrink available space */
envp[i] = NULL;
envp = &envp[i];
num_envp -= i;
buffer = &buffer[length];
buffer_size -= length;

return 0;
}

Expand Down
16 changes: 9 additions & 7 deletions drivers/acpi/scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -319,16 +319,18 @@ static int acpi_bus_match(struct device *dev, struct device_driver *drv)
return !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
}

static int acpi_device_uevent(struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct acpi_device *acpi_dev = to_acpi_device(dev);
int len;

strcpy(buffer, "MODALIAS=");
if (create_modalias(acpi_dev, buffer + 9, buffer_size - 9) > 0) {
envp[0] = buffer;
envp[1] = NULL;
}
if (add_uevent_var(env, "MODALIAS="))
return -ENOMEM;
len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
sizeof(env->buf) - env->buflen);
if (len >= (sizeof(env->buf) - env->buflen))
return -ENOMEM;
env->buflen += len;
return 0;
}

Expand Down
9 changes: 3 additions & 6 deletions drivers/amba/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,12 @@ static int amba_match(struct device *dev, struct device_driver *drv)
}

#ifdef CONFIG_HOTPLUG
static int amba_uevent(struct device *dev, char **envp, int nr_env, char *buf, int bufsz)
static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct amba_device *pcdev = to_amba_device(dev);
int retval = 0, i = 0, len = 0;
int retval = 0;

retval = add_uevent_var(envp, nr_env, &i,
buf, bufsz, &len,
"AMBA_ID=%08x", pcdev->periphid);
envp[i] = NULL;
retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid);
return retval;
}
#else
Expand Down
42 changes: 10 additions & 32 deletions drivers/base/class.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,7 @@ static void class_device_create_release(struct class_device *class_dev)

/* needed to allow these devices to have parent class devices */
static int class_device_create_uevent(struct class_device *class_dev,
char **envp, int num_envp,
char *buffer, int buffer_size)
struct kobj_uevent_env *env)
{
pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id);
return 0;
Expand Down Expand Up @@ -403,64 +402,43 @@ static void remove_deprecated_class_device_links(struct class_device *cd)
{ }
#endif

static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp,
int num_envp, char *buffer, int buffer_size)
static int class_uevent(struct kset *kset, struct kobject *kobj,
struct kobj_uevent_env *env)
{
struct class_device *class_dev = to_class_dev(kobj);
struct device *dev = class_dev->dev;
int i = 0;
int length = 0;
int retval = 0;

pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id);

if (MAJOR(class_dev->devt)) {
add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"MAJOR=%u", MAJOR(class_dev->devt));
add_uevent_var(env, "MAJOR=%u", MAJOR(class_dev->devt));

add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"MINOR=%u", MINOR(class_dev->devt));
add_uevent_var(env, "MINOR=%u", MINOR(class_dev->devt));
}

if (dev) {
const char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
if (path) {
add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"PHYSDEVPATH=%s", path);
add_uevent_var(env, "PHYSDEVPATH=%s", path);
kfree(path);
}

if (dev->bus)
add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"PHYSDEVBUS=%s", dev->bus->name);
add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);

if (dev->driver)
add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"PHYSDEVDRIVER=%s", dev->driver->name);
add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name);
}

/* terminate, set to next free slot, shrink available space */
envp[i] = NULL;
envp = &envp[i];
num_envp -= i;
buffer = &buffer[length];
buffer_size -= length;

if (class_dev->uevent) {
/* have the class device specific function add its stuff */
retval = class_dev->uevent(class_dev, envp, num_envp,
buffer, buffer_size);
retval = class_dev->uevent(class_dev, env);
if (retval)
pr_debug("class_dev->uevent() returned %d\n", retval);
} else if (class_dev->class->uevent) {
/* have the class specific function add its stuff */
retval = class_dev->class->uevent(class_dev, envp, num_envp,
buffer, buffer_size);
retval = class_dev->class->uevent(class_dev, env);
if (retval)
pr_debug("class->uevent() returned %d\n", retval);
}
Expand Down
Loading

0 comments on commit 7eff2e7

Please sign in to comment.