diff options
author | Kay Sievers <kay.sievers@vrfy.org> | 2007-08-14 09:15:12 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-10-12 17:51:01 -0400 |
commit | 7eff2e7a8b65c25920207324e56611150eb1cd9a (patch) | |
tree | 02a0eeba9d25d996233e30c18f258dfae0ae2139 /drivers/base | |
parent | 8380770c842faef3001e44662953d64ad9a93663 (diff) |
Driver core: change add_uevent_var to use a struct
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 <kay.sievers@vrfy.org>
Cc: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Cc: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/class.c | 42 | ||||
-rw-r--r-- | drivers/base/core.c | 84 | ||||
-rw-r--r-- | drivers/base/firmware_class.c | 11 | ||||
-rw-r--r-- | drivers/base/memory.c | 3 | ||||
-rw-r--r-- | drivers/base/platform.c | 6 |
5 files changed, 41 insertions, 105 deletions
diff --git a/drivers/base/class.c b/drivers/base/class.c index 4d2222618b78..ecd6336bffea 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c | |||
@@ -180,8 +180,7 @@ static void class_device_create_release(struct class_device *class_dev) | |||
180 | 180 | ||
181 | /* needed to allow these devices to have parent class devices */ | 181 | /* needed to allow these devices to have parent class devices */ |
182 | static int class_device_create_uevent(struct class_device *class_dev, | 182 | static int class_device_create_uevent(struct class_device *class_dev, |
183 | char **envp, int num_envp, | 183 | struct kobj_uevent_env *env) |
184 | char *buffer, int buffer_size) | ||
185 | { | 184 | { |
186 | pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id); | 185 | pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id); |
187 | return 0; | 186 | return 0; |
@@ -403,64 +402,43 @@ static void remove_deprecated_class_device_links(struct class_device *cd) | |||
403 | { } | 402 | { } |
404 | #endif | 403 | #endif |
405 | 404 | ||
406 | static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp, | 405 | static int class_uevent(struct kset *kset, struct kobject *kobj, |
407 | int num_envp, char *buffer, int buffer_size) | 406 | struct kobj_uevent_env *env) |
408 | { | 407 | { |
409 | struct class_device *class_dev = to_class_dev(kobj); | 408 | struct class_device *class_dev = to_class_dev(kobj); |
410 | struct device *dev = class_dev->dev; | 409 | struct device *dev = class_dev->dev; |
411 | int i = 0; | ||
412 | int length = 0; | ||
413 | int retval = 0; | 410 | int retval = 0; |
414 | 411 | ||
415 | pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id); | 412 | pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id); |
416 | 413 | ||
417 | if (MAJOR(class_dev->devt)) { | 414 | if (MAJOR(class_dev->devt)) { |
418 | add_uevent_var(envp, num_envp, &i, | 415 | add_uevent_var(env, "MAJOR=%u", MAJOR(class_dev->devt)); |
419 | buffer, buffer_size, &length, | ||
420 | "MAJOR=%u", MAJOR(class_dev->devt)); | ||
421 | 416 | ||
422 | add_uevent_var(envp, num_envp, &i, | 417 | add_uevent_var(env, "MINOR=%u", MINOR(class_dev->devt)); |
423 | buffer, buffer_size, &length, | ||
424 | "MINOR=%u", MINOR(class_dev->devt)); | ||
425 | } | 418 | } |
426 | 419 | ||
427 | if (dev) { | 420 | if (dev) { |
428 | const char *path = kobject_get_path(&dev->kobj, GFP_KERNEL); | 421 | const char *path = kobject_get_path(&dev->kobj, GFP_KERNEL); |
429 | if (path) { | 422 | if (path) { |
430 | add_uevent_var(envp, num_envp, &i, | 423 | add_uevent_var(env, "PHYSDEVPATH=%s", path); |
431 | buffer, buffer_size, &length, | ||
432 | "PHYSDEVPATH=%s", path); | ||
433 | kfree(path); | 424 | kfree(path); |
434 | } | 425 | } |
435 | 426 | ||
436 | if (dev->bus) | 427 | if (dev->bus) |
437 | add_uevent_var(envp, num_envp, &i, | 428 | add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); |
438 | buffer, buffer_size, &length, | ||
439 | "PHYSDEVBUS=%s", dev->bus->name); | ||
440 | 429 | ||
441 | if (dev->driver) | 430 | if (dev->driver) |
442 | add_uevent_var(envp, num_envp, &i, | 431 | add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name); |
443 | buffer, buffer_size, &length, | ||
444 | "PHYSDEVDRIVER=%s", dev->driver->name); | ||
445 | } | 432 | } |
446 | 433 | ||
447 | /* terminate, set to next free slot, shrink available space */ | ||
448 | envp[i] = NULL; | ||
449 | envp = &envp[i]; | ||
450 | num_envp -= i; | ||
451 | buffer = &buffer[length]; | ||
452 | buffer_size -= length; | ||
453 | |||
454 | if (class_dev->uevent) { | 434 | if (class_dev->uevent) { |
455 | /* have the class device specific function add its stuff */ | 435 | /* have the class device specific function add its stuff */ |
456 | retval = class_dev->uevent(class_dev, envp, num_envp, | 436 | retval = class_dev->uevent(class_dev, env); |
457 | buffer, buffer_size); | ||
458 | if (retval) | 437 | if (retval) |
459 | pr_debug("class_dev->uevent() returned %d\n", retval); | 438 | pr_debug("class_dev->uevent() returned %d\n", retval); |
460 | } else if (class_dev->class->uevent) { | 439 | } else if (class_dev->class->uevent) { |
461 | /* have the class specific function add its stuff */ | 440 | /* have the class specific function add its stuff */ |
462 | retval = class_dev->class->uevent(class_dev, envp, num_envp, | 441 | retval = class_dev->class->uevent(class_dev, env); |
463 | buffer, buffer_size); | ||
464 | if (retval) | 442 | if (retval) |
465 | pr_debug("class->uevent() returned %d\n", retval); | 443 | pr_debug("class->uevent() returned %d\n", retval); |
466 | } | 444 | } |
diff --git a/drivers/base/core.c b/drivers/base/core.c index ec86d6fc2360..d487c032dc4a 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -141,33 +141,23 @@ static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj) | |||
141 | return NULL; | 141 | return NULL; |
142 | } | 142 | } |
143 | 143 | ||
144 | static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, | 144 | static int dev_uevent(struct kset *kset, struct kobject *kobj, |
145 | int num_envp, char *buffer, int buffer_size) | 145 | struct kobj_uevent_env *env) |
146 | { | 146 | { |
147 | struct device *dev = to_dev(kobj); | 147 | struct device *dev = to_dev(kobj); |
148 | int i = 0; | ||
149 | int length = 0; | ||
150 | int retval = 0; | 148 | int retval = 0; |
151 | 149 | ||
152 | /* add the major/minor if present */ | 150 | /* add the major/minor if present */ |
153 | if (MAJOR(dev->devt)) { | 151 | if (MAJOR(dev->devt)) { |
154 | add_uevent_var(envp, num_envp, &i, | 152 | add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt)); |
155 | buffer, buffer_size, &length, | 153 | add_uevent_var(env, "MINOR=%u", MINOR(dev->devt)); |
156 | "MAJOR=%u", MAJOR(dev->devt)); | ||
157 | add_uevent_var(envp, num_envp, &i, | ||
158 | buffer, buffer_size, &length, | ||
159 | "MINOR=%u", MINOR(dev->devt)); | ||
160 | } | 154 | } |
161 | 155 | ||
162 | if (dev->type && dev->type->name) | 156 | if (dev->type && dev->type->name) |
163 | add_uevent_var(envp, num_envp, &i, | 157 | add_uevent_var(env, "DEVTYPE=%s", dev->type->name); |
164 | buffer, buffer_size, &length, | ||
165 | "DEVTYPE=%s", dev->type->name); | ||
166 | 158 | ||
167 | if (dev->driver) | 159 | if (dev->driver) |
168 | add_uevent_var(envp, num_envp, &i, | 160 | add_uevent_var(env, "DRIVER=%s", dev->driver->name); |
169 | buffer, buffer_size, &length, | ||
170 | "DRIVER=%s", dev->driver->name); | ||
171 | 161 | ||
172 | #ifdef CONFIG_SYSFS_DEPRECATED | 162 | #ifdef CONFIG_SYSFS_DEPRECATED |
173 | if (dev->class) { | 163 | if (dev->class) { |
@@ -181,59 +171,43 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, | |||
181 | 171 | ||
182 | path = kobject_get_path(&parent->kobj, GFP_KERNEL); | 172 | path = kobject_get_path(&parent->kobj, GFP_KERNEL); |
183 | if (path) { | 173 | if (path) { |
184 | add_uevent_var(envp, num_envp, &i, | 174 | add_uevent_var(env, "PHYSDEVPATH=%s", path); |
185 | buffer, buffer_size, &length, | ||
186 | "PHYSDEVPATH=%s", path); | ||
187 | kfree(path); | 175 | kfree(path); |
188 | } | 176 | } |
189 | 177 | ||
190 | add_uevent_var(envp, num_envp, &i, | 178 | add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name); |
191 | buffer, buffer_size, &length, | ||
192 | "PHYSDEVBUS=%s", parent->bus->name); | ||
193 | 179 | ||
194 | if (parent->driver) | 180 | if (parent->driver) |
195 | add_uevent_var(envp, num_envp, &i, | 181 | add_uevent_var(env, "PHYSDEVDRIVER=%s", |
196 | buffer, buffer_size, &length, | 182 | parent->driver->name); |
197 | "PHYSDEVDRIVER=%s", parent->driver->name); | ||
198 | } | 183 | } |
199 | } else if (dev->bus) { | 184 | } else if (dev->bus) { |
200 | add_uevent_var(envp, num_envp, &i, | 185 | add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); |
201 | buffer, buffer_size, &length, | ||
202 | "PHYSDEVBUS=%s", dev->bus->name); | ||
203 | 186 | ||
204 | if (dev->driver) | 187 | if (dev->driver) |
205 | add_uevent_var(envp, num_envp, &i, | 188 | add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name); |
206 | buffer, buffer_size, &length, | ||
207 | "PHYSDEVDRIVER=%s", dev->driver->name); | ||
208 | } | 189 | } |
209 | #endif | 190 | #endif |
210 | 191 | ||
211 | /* terminate, set to next free slot, shrink available space */ | 192 | /* have the bus specific function add its stuff */ |
212 | envp[i] = NULL; | ||
213 | envp = &envp[i]; | ||
214 | num_envp -= i; | ||
215 | buffer = &buffer[length]; | ||
216 | buffer_size -= length; | ||
217 | |||
218 | if (dev->bus && dev->bus->uevent) { | 193 | if (dev->bus && dev->bus->uevent) { |
219 | /* have the bus specific function add its stuff */ | 194 | retval = dev->bus->uevent(dev, env); |
220 | retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size); | ||
221 | if (retval) | 195 | if (retval) |
222 | pr_debug ("%s: bus uevent() returned %d\n", | 196 | pr_debug ("%s: bus uevent() returned %d\n", |
223 | __FUNCTION__, retval); | 197 | __FUNCTION__, retval); |
224 | } | 198 | } |
225 | 199 | ||
200 | /* have the class specific function add its stuff */ | ||
226 | if (dev->class && dev->class->dev_uevent) { | 201 | if (dev->class && dev->class->dev_uevent) { |
227 | /* have the class specific function add its stuff */ | 202 | retval = dev->class->dev_uevent(dev, env); |
228 | retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size); | ||
229 | if (retval) | 203 | if (retval) |
230 | pr_debug("%s: class uevent() returned %d\n", | 204 | pr_debug("%s: class uevent() returned %d\n", |
231 | __FUNCTION__, retval); | 205 | __FUNCTION__, retval); |
232 | } | 206 | } |
233 | 207 | ||
208 | /* have the device type specific fuction add its stuff */ | ||
234 | if (dev->type && dev->type->uevent) { | 209 | if (dev->type && dev->type->uevent) { |
235 | /* have the device type specific fuction add its stuff */ | 210 | retval = dev->type->uevent(dev, env); |
236 | retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size); | ||
237 | if (retval) | 211 | if (retval) |
238 | pr_debug("%s: dev_type uevent() returned %d\n", | 212 | pr_debug("%s: dev_type uevent() returned %d\n", |
239 | __FUNCTION__, retval); | 213 | __FUNCTION__, retval); |
@@ -253,9 +227,7 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, | |||
253 | { | 227 | { |
254 | struct kobject *top_kobj; | 228 | struct kobject *top_kobj; |
255 | struct kset *kset; | 229 | struct kset *kset; |
256 | char *envp[32]; | 230 | struct kobj_uevent_env *env = NULL; |
257 | char *data = NULL; | ||
258 | char *pos; | ||
259 | int i; | 231 | int i; |
260 | size_t count = 0; | 232 | size_t count = 0; |
261 | int retval; | 233 | int retval; |
@@ -278,26 +250,20 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, | |||
278 | if (!kset->uevent_ops->filter(kset, &dev->kobj)) | 250 | if (!kset->uevent_ops->filter(kset, &dev->kobj)) |
279 | goto out; | 251 | goto out; |
280 | 252 | ||
281 | data = (char *)get_zeroed_page(GFP_KERNEL); | 253 | env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); |
282 | if (!data) | 254 | if (!env) |
283 | return -ENOMEM; | 255 | return -ENOMEM; |
284 | 256 | ||
285 | /* let the kset specific function add its keys */ | 257 | /* let the kset specific function add its keys */ |
286 | pos = data; | 258 | retval = kset->uevent_ops->uevent(kset, &dev->kobj, env); |
287 | memset(envp, 0, sizeof(envp)); | ||
288 | retval = kset->uevent_ops->uevent(kset, &dev->kobj, | ||
289 | envp, ARRAY_SIZE(envp), | ||
290 | pos, PAGE_SIZE); | ||
291 | if (retval) | 259 | if (retval) |
292 | goto out; | 260 | goto out; |
293 | 261 | ||
294 | /* copy keys to file */ | 262 | /* copy keys to file */ |
295 | for (i = 0; envp[i]; i++) { | 263 | for (i = 0; i < env->envp_idx; i++) |
296 | pos = &buf[count]; | 264 | count += sprintf(&buf[count], "%s\n", env->envp[i]); |
297 | count += sprintf(pos, "%s\n", envp[i]); | ||
298 | } | ||
299 | out: | 265 | out: |
300 | free_page((unsigned long)data); | 266 | kfree(env); |
301 | return count; | 267 | return count; |
302 | } | 268 | } |
303 | 269 | ||
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index b24efd4e3e3d..4a1b9bfc5471 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c | |||
@@ -88,19 +88,14 @@ static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store); | |||
88 | 88 | ||
89 | static void fw_dev_release(struct device *dev); | 89 | static void fw_dev_release(struct device *dev); |
90 | 90 | ||
91 | static int firmware_uevent(struct device *dev, char **envp, int num_envp, | 91 | static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env) |
92 | char *buffer, int buffer_size) | ||
93 | { | 92 | { |
94 | struct firmware_priv *fw_priv = dev_get_drvdata(dev); | 93 | struct firmware_priv *fw_priv = dev_get_drvdata(dev); |
95 | int i = 0, len = 0; | ||
96 | 94 | ||
97 | if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, | 95 | if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->fw_id)) |
98 | "FIRMWARE=%s", fw_priv->fw_id)) | ||
99 | return -ENOMEM; | 96 | return -ENOMEM; |
100 | if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, | 97 | if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout)) |
101 | "TIMEOUT=%i", loading_timeout)) | ||
102 | return -ENOMEM; | 98 | return -ENOMEM; |
103 | envp[i] = NULL; | ||
104 | 99 | ||
105 | return 0; | 100 | return 0; |
106 | } | 101 | } |
diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 74b96795d2f5..cb99daeae936 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c | |||
@@ -34,8 +34,7 @@ static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj) | |||
34 | return MEMORY_CLASS_NAME; | 34 | return MEMORY_CLASS_NAME; |
35 | } | 35 | } |
36 | 36 | ||
37 | static int memory_uevent(struct kset *kset, struct kobject *kobj, char **envp, | 37 | static int memory_uevent(struct kset *kset, struct kobj_uevent_env *env) |
38 | int num_envp, char *buffer, int buffer_size) | ||
39 | { | 38 | { |
40 | int retval = 0; | 39 | int retval = 0; |
41 | 40 | ||
diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 9bfc434d1327..a2e3910196e0 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c | |||
@@ -529,13 +529,11 @@ static struct device_attribute platform_dev_attrs[] = { | |||
529 | __ATTR_NULL, | 529 | __ATTR_NULL, |
530 | }; | 530 | }; |
531 | 531 | ||
532 | static int platform_uevent(struct device *dev, char **envp, int num_envp, | 532 | static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) |
533 | char *buffer, int buffer_size) | ||
534 | { | 533 | { |
535 | struct platform_device *pdev = to_platform_device(dev); | 534 | struct platform_device *pdev = to_platform_device(dev); |
536 | 535 | ||
537 | envp[0] = buffer; | 536 | add_uevent_var(env, "MODALIAS=platform:%s", pdev->name); |
538 | snprintf(buffer, buffer_size, "MODALIAS=platform:%s", pdev->name); | ||
539 | return 0; | 537 | return 0; |
540 | } | 538 | } |
541 | 539 | ||