aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/core.c
diff options
context:
space:
mode:
authorKay Sievers <kay.sievers@vrfy.org>2007-08-14 09:15:12 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-10-12 17:51:01 -0400
commit7eff2e7a8b65c25920207324e56611150eb1cd9a (patch)
tree02a0eeba9d25d996233e30c18f258dfae0ae2139 /drivers/base/core.c
parent8380770c842faef3001e44662953d64ad9a93663 (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.c84
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
144static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, 144static 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 }
299out: 265out:
300 free_page((unsigned long)data); 266 kfree(env);
301 return count; 267 return count;
302} 268}
303 269