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/core.c | |
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/core.c')
-rw-r--r-- | drivers/base/core.c | 84 |
1 files changed, 25 insertions, 59 deletions
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 | ||