Blame view

lib/kobject_uevent.c 14.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  /*
   * kernel userspace event delivery
   *
   * Copyright (C) 2004 Red Hat, Inc.  All rights reserved.
   * Copyright (C) 2004 Novell, Inc.  All rights reserved.
   * Copyright (C) 2004 IBM, Inc. All rights reserved.
   *
   * Licensed under the GNU GPL v2.
   *
   * Authors:
   *	Robert Love		<rml@novell.com>
   *	Kay Sievers		<kay.sievers@vrfy.org>
   *	Arjan van de Ven	<arjanv@redhat.com>
   *	Greg Kroah-Hartman	<greg@kroah.com>
   */
  
  #include <linux/spinlock.h>
2d38f9a4f   Denis V. Lunev   [NETNS]: Do no in...
18
19
  #include <linux/string.h>
  #include <linux/kobject.h>
8bc3bcc93   Paul Gortmaker   lib: reduce the u...
20
21
  #include <linux/export.h>
  #include <linux/kmod.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
22
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
  #include <linux/socket.h>
  #include <linux/skbuff.h>
  #include <linux/netlink.h>
f36776faf   Peter Rajnoha   kobject: support ...
26
27
  #include <linux/uuid.h>
  #include <linux/ctype.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  #include <net/sock.h>
07e98962f   Eric W. Biederman   kobject: Send hot...
29
  #include <net/net_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31

cd030c4cb   Cornelia Huck   kobject: fix link...
32
  u64 uevent_seqnum;
86d56134f   Michael Marineau   kobject: Make sup...
33
  #ifdef CONFIG_UEVENT_HELPER
6a8d8abb6   Kay Sievers   Driver core: add ...
34
  char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
86d56134f   Michael Marineau   kobject: Make sup...
35
  #endif
07e98962f   Eric W. Biederman   kobject: Send hot...
36
37
38
39
40
41
  #ifdef CONFIG_NET
  struct uevent_sock {
  	struct list_head list;
  	struct sock *sk;
  };
  static LIST_HEAD(uevent_sock_list);
cd030c4cb   Cornelia Huck   kobject: fix link...
42
  #endif
7b60a18da   Andrew Vagin   uevent: send even...
43
44
  /* This lock protects uevent_seqnum and uevent_sock_list */
  static DEFINE_MUTEX(uevent_sock_mutex);
5c5daf657   Kay Sievers   Driver core: excl...
45
46
47
48
49
50
51
52
  /* the strings here must match the enum in include/linux/kobject.h */
  static const char *kobject_actions[] = {
  	[KOBJ_ADD] =		"add",
  	[KOBJ_REMOVE] =		"remove",
  	[KOBJ_CHANGE] =		"change",
  	[KOBJ_MOVE] =		"move",
  	[KOBJ_ONLINE] =		"online",
  	[KOBJ_OFFLINE] =	"offline",
1455cf8db   Dmitry Torokhov   driver core: emit...
53
54
  	[KOBJ_BIND] =		"bind",
  	[KOBJ_UNBIND] =		"unbind",
5c5daf657   Kay Sievers   Driver core: excl...
55
  };
f36776faf   Peter Rajnoha   kobject: support ...
56
57
58
  static int kobject_action_type(const char *buf, size_t count,
  			       enum kobject_action *type,
  			       const char **args)
5c5daf657   Kay Sievers   Driver core: excl...
59
60
  {
  	enum kobject_action action;
f36776faf   Peter Rajnoha   kobject: support ...
61
62
  	size_t count_first;
  	const char *args_start;
5c5daf657   Kay Sievers   Driver core: excl...
63
  	int ret = -EINVAL;
a9edadbf7   Mark Lord   fix uevent action...
64
65
  	if (count && (buf[count-1] == '
  ' || buf[count-1] == '\0'))
5c5daf657   Kay Sievers   Driver core: excl...
66
67
68
69
  		count--;
  
  	if (!count)
  		goto out;
f36776faf   Peter Rajnoha   kobject: support ...
70
71
72
73
74
75
  	args_start = strnchr(buf, count, ' ');
  	if (args_start) {
  		count_first = args_start - buf;
  		args_start = args_start + 1;
  	} else
  		count_first = count;
5c5daf657   Kay Sievers   Driver core: excl...
76
  	for (action = 0; action < ARRAY_SIZE(kobject_actions); action++) {
f36776faf   Peter Rajnoha   kobject: support ...
77
  		if (strncmp(kobject_actions[action], buf, count_first) != 0)
5c5daf657   Kay Sievers   Driver core: excl...
78
  			continue;
f36776faf   Peter Rajnoha   kobject: support ...
79
  		if (kobject_actions[action][count_first] != '\0')
5c5daf657   Kay Sievers   Driver core: excl...
80
  			continue;
f36776faf   Peter Rajnoha   kobject: support ...
81
82
  		if (args)
  			*args = args_start;
5c5daf657   Kay Sievers   Driver core: excl...
83
84
85
86
87
88
89
  		*type = action;
  		ret = 0;
  		break;
  	}
  out:
  	return ret;
  }
f36776faf   Peter Rajnoha   kobject: support ...
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
  static const char *action_arg_word_end(const char *buf, const char *buf_end,
  				       char delim)
  {
  	const char *next = buf;
  
  	while (next <= buf_end && *next != delim)
  		if (!isalnum(*next++))
  			return NULL;
  
  	if (next == buf)
  		return NULL;
  
  	return next;
  }
  
  static int kobject_action_args(const char *buf, size_t count,
  			       struct kobj_uevent_env **ret_env)
  {
  	struct kobj_uevent_env *env = NULL;
  	const char *next, *buf_end, *key;
  	int key_len;
  	int r = -EINVAL;
  
  	if (count && (buf[count - 1] == '
  ' || buf[count - 1] == '\0'))
  		count--;
  
  	if (!count)
  		return -EINVAL;
  
  	env = kzalloc(sizeof(*env), GFP_KERNEL);
  	if (!env)
  		return -ENOMEM;
  
  	/* first arg is UUID */
  	if (count < UUID_STRING_LEN || !uuid_is_valid(buf) ||
  	    add_uevent_var(env, "SYNTH_UUID=%.*s", UUID_STRING_LEN, buf))
  		goto out;
  
  	/*
  	 * the rest are custom environment variables in KEY=VALUE
  	 * format with ' ' delimiter between each KEY=VALUE pair
  	 */
  	next = buf + UUID_STRING_LEN;
  	buf_end = buf + count - 1;
  
  	while (next <= buf_end) {
  		if (*next != ' ')
  			goto out;
  
  		/* skip the ' ', key must follow */
  		key = ++next;
  		if (key > buf_end)
  			goto out;
  
  		buf = next;
  		next = action_arg_word_end(buf, buf_end, '=');
  		if (!next || next > buf_end || *next != '=')
  			goto out;
  		key_len = next - buf;
  
  		/* skip the '=', value must follow */
  		if (++next > buf_end)
  			goto out;
  
  		buf = next;
  		next = action_arg_word_end(buf, buf_end, ' ');
  		if (!next)
  			goto out;
  
  		if (add_uevent_var(env, "SYNTH_ARG_%.*s=%.*s",
  				   key_len, key, (int) (next - buf), buf))
  			goto out;
  	}
  
  	r = 0;
  out:
  	if (r)
  		kfree(env);
  	else
  		*ret_env = env;
  	return r;
  }
  
  /**
   * kobject_synth_uevent - send synthetic uevent with arguments
   *
   * @kobj: struct kobject for which synthetic uevent is to be generated
   * @buf: buffer containing action type and action args, newline is ignored
   * @count: length of buffer
   *
   * Returns 0 if kobject_synthetic_uevent() is completed with success or the
   * corresponding error when it fails.
   */
  int kobject_synth_uevent(struct kobject *kobj, const char *buf, size_t count)
  {
  	char *no_uuid_envp[] = { "SYNTH_UUID=0", NULL };
  	enum kobject_action action;
  	const char *action_args;
  	struct kobj_uevent_env *env;
  	const char *msg = NULL, *devpath;
  	int r;
  
  	r = kobject_action_type(buf, count, &action, &action_args);
  	if (r) {
  		msg = "unknown uevent action string
  ";
  		goto out;
  	}
  
  	if (!action_args) {
  		r = kobject_uevent_env(kobj, action, no_uuid_envp);
  		goto out;
  	}
  
  	r = kobject_action_args(action_args,
  				count - (action_args - buf), &env);
  	if (r == -EINVAL) {
  		msg = "incorrect uevent action arguments
  ";
  		goto out;
  	}
  
  	if (r)
  		goto out;
  
  	r = kobject_uevent_env(kobj, action, env->envp);
  	kfree(env);
  out:
  	if (r) {
  		devpath = kobject_get_path(kobj, GFP_KERNEL);
  		printk(KERN_WARNING "synth uevent: %s: %s",
  		       devpath ?: "unknown device",
  		       msg ?: "failed to send uevent");
  		kfree(devpath);
  	}
  	return r;
  }
c84212860   Andrew Morton   lib/kobject_ueven...
228
  #ifdef CONFIG_NET
5f71a2962   Eric W. Biederman   kobj: Send hotplu...
229
230
  static int kobj_bcast_filter(struct sock *dsk, struct sk_buff *skb, void *data)
  {
82ef3d5d5   Weilong Chen   net: fix "queues"...
231
  	struct kobject *kobj = data, *ksobj;
5f71a2962   Eric W. Biederman   kobj: Send hotplu...
232
233
234
  	const struct kobj_ns_type_operations *ops;
  
  	ops = kobj_ns_ops(kobj);
82ef3d5d5   Weilong Chen   net: fix "queues"...
235
236
237
238
239
240
241
  	if (!ops && kobj->kset) {
  		ksobj = &kobj->kset->kobj;
  		if (ksobj->parent != NULL)
  			ops = kobj_ns_ops(ksobj->parent);
  	}
  
  	if (ops && ops->netlink_ns && kobj->ktype->namespace) {
5f71a2962   Eric W. Biederman   kobj: Send hotplu...
242
243
244
245
246
247
248
249
  		const void *sock_ns, *ns;
  		ns = kobj->ktype->namespace(kobj);
  		sock_ns = ops->netlink_ns(dsk);
  		return sock_ns != ns;
  	}
  
  	return 0;
  }
c84212860   Andrew Morton   lib/kobject_ueven...
250
  #endif
5f71a2962   Eric W. Biederman   kobj: Send hotplu...
251

86d56134f   Michael Marineau   kobject: Make sup...
252
  #ifdef CONFIG_UEVENT_HELPER
417daa1e8   Eric W. Biederman   hotplug: netns aw...
253
254
255
256
257
258
259
260
261
262
263
264
265
266
  static int kobj_usermode_filter(struct kobject *kobj)
  {
  	const struct kobj_ns_type_operations *ops;
  
  	ops = kobj_ns_ops(kobj);
  	if (ops) {
  		const void *init_ns, *ns;
  		ns = kobj->ktype->namespace(kobj);
  		init_ns = ops->initial_ns();
  		return ns != init_ns;
  	}
  
  	return 0;
  }
bcccff93a   Vladimir Davydov   kobject: don't bl...
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
  static int init_uevent_argv(struct kobj_uevent_env *env, const char *subsystem)
  {
  	int len;
  
  	len = strlcpy(&env->buf[env->buflen], subsystem,
  		      sizeof(env->buf) - env->buflen);
  	if (len >= (sizeof(env->buf) - env->buflen)) {
  		WARN(1, KERN_ERR "init_uevent_argv: buffer size too small
  ");
  		return -ENOMEM;
  	}
  
  	env->argv[0] = uevent_helper;
  	env->argv[1] = &env->buf[env->buflen];
  	env->argv[2] = NULL;
  
  	env->buflen += len + 1;
  	return 0;
  }
  
  static void cleanup_uevent_env(struct subprocess_info *info)
  {
  	kfree(info->data);
  }
86d56134f   Michael Marineau   kobject: Make sup...
291
  #endif
bcccff93a   Vladimir Davydov   kobject: don't bl...
292

6878e7de6   Dmitry Torokhov   driver core: supp...
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
  static void zap_modalias_env(struct kobj_uevent_env *env)
  {
  	static const char modalias_prefix[] = "MODALIAS=";
  	int i;
  
  	for (i = 0; i < env->envp_idx;) {
  		if (strncmp(env->envp[i], modalias_prefix,
  			    sizeof(modalias_prefix) - 1)) {
  			i++;
  			continue;
  		}
  
  		if (i != env->envp_idx - 1)
  			memmove(&env->envp[i], &env->envp[i + 1],
  				sizeof(env->envp[i]) * env->envp_idx - 1);
  
  		env->envp_idx--;
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
  /**
8a82472f8   Cornelia Huck   driver core: Intr...
313
   * kobject_uevent_env - send an uevent with environmental data
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
   * @kobj: struct kobject that the action is happening to
edbbf994b   Julia Lawall   kobject: improve ...
316
   * @action: action that is happening
8a82472f8   Cornelia Huck   driver core: Intr...
317
   * @envp_ext: pointer to environmental data
542cfce6f   Aneesh Kumar K.V   kobject: kobject_...
318
   *
f6e6e7799   Xiaotian Feng   kobject_uevent: f...
319
   * Returns 0 if kobject_uevent_env() is completed with success or the
542cfce6f   Aneesh Kumar K.V   kobject: kobject_...
320
   * corresponding error when it fails.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
   */
542cfce6f   Aneesh Kumar K.V   kobject: kobject_...
322
  int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
7eff2e7a8   Kay Sievers   Driver core: chan...
323
  		       char *envp_ext[])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
  {
7eff2e7a8   Kay Sievers   Driver core: chan...
325
326
  	struct kobj_uevent_env *env;
  	const char *action_string = kobject_actions[action];
5f123fbd8   Kay Sievers   [PATCH] merge kob...
327
328
329
330
  	const char *devpath = NULL;
  	const char *subsystem;
  	struct kobject *top_kobj;
  	struct kset *kset;
9cd43611c   Emese Revfy   kobject: Constify...
331
  	const struct kset_uevent_ops *uevent_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
  	int i = 0;
542cfce6f   Aneesh Kumar K.V   kobject: kobject_...
333
  	int retval = 0;
07e98962f   Eric W. Biederman   kobject: Send hot...
334
335
336
  #ifdef CONFIG_NET
  	struct uevent_sock *ue_sk;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337

9f66fa2a4   Greg Kroah-Hartman   kobject: clean up...
338
339
  	pr_debug("kobject: '%s' (%p): %s
  ",
810304db7   Harvey Harrison   lib: replace rema...
340
  		 kobject_name(kobj), kobj, __func__);
5f123fbd8   Kay Sievers   [PATCH] merge kob...
341

5f123fbd8   Kay Sievers   [PATCH] merge kob...
342
343
  	/* search the kset we belong to */
  	top_kobj = kobj;
ccd490a3c   Kay Sievers   Driver core: kern...
344
  	while (!top_kobj->kset && top_kobj->parent)
14193fb91   John Anthony Kazos Jr   Kobject: kobject_...
345
  		top_kobj = top_kobj->parent;
ccd490a3c   Kay Sievers   Driver core: kern...
346

542cfce6f   Aneesh Kumar K.V   kobject: kobject_...
347
  	if (!top_kobj->kset) {
9f66fa2a4   Greg Kroah-Hartman   kobject: clean up...
348
349
350
  		pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
  			 "without kset!
  ", kobject_name(kobj), kobj,
810304db7   Harvey Harrison   lib: replace rema...
351
  			 __func__);
542cfce6f   Aneesh Kumar K.V   kobject: kobject_...
352
353
  		return -EINVAL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354

5f123fbd8   Kay Sievers   [PATCH] merge kob...
355
  	kset = top_kobj->kset;
312c004d3   Kay Sievers   [PATCH] driver co...
356
  	uevent_ops = kset->uevent_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357

f67f129e5   Ming Lei   Driver core: impl...
358
359
360
361
362
363
364
365
  	/* skip the event, if uevent_suppress is set*/
  	if (kobj->uevent_suppress) {
  		pr_debug("kobject: '%s' (%p): %s: uevent_suppress "
  				 "caused the event to drop!
  ",
  				 kobject_name(kobj), kobj, __func__);
  		return 0;
  	}
7eff2e7a8   Kay Sievers   Driver core: chan...
366
  	/* skip the event, if the filter returns zero. */
312c004d3   Kay Sievers   [PATCH] driver co...
367
  	if (uevent_ops && uevent_ops->filter)
542cfce6f   Aneesh Kumar K.V   kobject: kobject_...
368
  		if (!uevent_ops->filter(kset, kobj)) {
9f66fa2a4   Greg Kroah-Hartman   kobject: clean up...
369
370
371
  			pr_debug("kobject: '%s' (%p): %s: filter function "
  				 "caused the event to drop!
  ",
810304db7   Harvey Harrison   lib: replace rema...
372
  				 kobject_name(kobj), kobj, __func__);
542cfce6f   Aneesh Kumar K.V   kobject: kobject_...
373
374
  			return 0;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375

864062457   Kay Sievers   driver core: fix ...
376
377
378
379
380
381
  	/* originating subsystem */
  	if (uevent_ops && uevent_ops->name)
  		subsystem = uevent_ops->name(kset, kobj);
  	else
  		subsystem = kobject_name(&kset->kobj);
  	if (!subsystem) {
9f66fa2a4   Greg Kroah-Hartman   kobject: clean up...
382
383
384
  		pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the "
  			 "event to drop!
  ", kobject_name(kobj), kobj,
810304db7   Harvey Harrison   lib: replace rema...
385
  			 __func__);
864062457   Kay Sievers   driver core: fix ...
386
387
  		return 0;
  	}
7eff2e7a8   Kay Sievers   Driver core: chan...
388
389
390
  	/* environment buffer */
  	env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
  	if (!env)
542cfce6f   Aneesh Kumar K.V   kobject: kobject_...
391
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392

5f123fbd8   Kay Sievers   [PATCH] merge kob...
393
394
  	/* complete object path */
  	devpath = kobject_get_path(kobj, GFP_KERNEL);
542cfce6f   Aneesh Kumar K.V   kobject: kobject_...
395
396
  	if (!devpath) {
  		retval = -ENOENT;
5f123fbd8   Kay Sievers   [PATCH] merge kob...
397
  		goto exit;
542cfce6f   Aneesh Kumar K.V   kobject: kobject_...
398
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399

5f123fbd8   Kay Sievers   [PATCH] merge kob...
400
  	/* default keys */
7eff2e7a8   Kay Sievers   Driver core: chan...
401
402
403
404
405
406
407
408
409
410
411
412
413
  	retval = add_uevent_var(env, "ACTION=%s", action_string);
  	if (retval)
  		goto exit;
  	retval = add_uevent_var(env, "DEVPATH=%s", devpath);
  	if (retval)
  		goto exit;
  	retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
  	if (retval)
  		goto exit;
  
  	/* keys passed in from the caller */
  	if (envp_ext) {
  		for (i = 0; envp_ext[i]; i++) {
c65b9145f   Tejun Heo   uevent: don't pas...
414
  			retval = add_uevent_var(env, "%s", envp_ext[i]);
7eff2e7a8   Kay Sievers   Driver core: chan...
415
416
417
418
  			if (retval)
  				goto exit;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419

5f123fbd8   Kay Sievers   [PATCH] merge kob...
420
  	/* let the kset specific function add its stuff */
312c004d3   Kay Sievers   [PATCH] driver co...
421
  	if (uevent_ops && uevent_ops->uevent) {
7eff2e7a8   Kay Sievers   Driver core: chan...
422
  		retval = uevent_ops->uevent(kset, kobj, env);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  		if (retval) {
9f66fa2a4   Greg Kroah-Hartman   kobject: clean up...
424
425
426
  			pr_debug("kobject: '%s' (%p): %s: uevent() returned "
  				 "%d
  ", kobject_name(kobj), kobj,
810304db7   Harvey Harrison   lib: replace rema...
427
  				 __func__, retval);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
429
430
  			goto exit;
  		}
  	}
6878e7de6   Dmitry Torokhov   driver core: supp...
431
432
433
434
435
436
437
438
439
  	switch (action) {
  	case KOBJ_ADD:
  		/*
  		 * Mark "add" event so we can make sure we deliver "remove"
  		 * event to userspace during automatic cleanup. If
  		 * the object did send an "add" event, "remove" will
  		 * automatically generated by the core, if not already done
  		 * by the caller.
  		 */
0f4dafc05   Kay Sievers   Kobject: auto-cle...
440
  		kobj->state_add_uevent_sent = 1;
6878e7de6   Dmitry Torokhov   driver core: supp...
441
442
443
  		break;
  
  	case KOBJ_REMOVE:
0f4dafc05   Kay Sievers   Kobject: auto-cle...
444
  		kobj->state_remove_uevent_sent = 1;
6878e7de6   Dmitry Torokhov   driver core: supp...
445
446
447
448
449
450
451
452
453
  		break;
  
  	case KOBJ_UNBIND:
  		zap_modalias_env(env);
  		break;
  
  	default:
  		break;
  	}
0f4dafc05   Kay Sievers   Kobject: auto-cle...
454

7b60a18da   Andrew Vagin   uevent: send even...
455
  	mutex_lock(&uevent_sock_mutex);
7eff2e7a8   Kay Sievers   Driver core: chan...
456
  	/* we will send an event, so request a new sequence number */
7b60a18da   Andrew Vagin   uevent: send even...
457
458
459
  	retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)++uevent_seqnum);
  	if (retval) {
  		mutex_unlock(&uevent_sock_mutex);
7eff2e7a8   Kay Sievers   Driver core: chan...
460
  		goto exit;
7b60a18da   Andrew Vagin   uevent: send even...
461
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462

4d17ffda3   Kay Sievers   [PATCH] Kobject: ...
463
  #if defined(CONFIG_NET)
5f123fbd8   Kay Sievers   [PATCH] merge kob...
464
  	/* send netlink message */
07e98962f   Eric W. Biederman   kobject: Send hot...
465
466
  	list_for_each_entry(ue_sk, &uevent_sock_list, list) {
  		struct sock *uevent_sock = ue_sk->sk;
5f123fbd8   Kay Sievers   [PATCH] merge kob...
467
468
  		struct sk_buff *skb;
  		size_t len;
74099b18b   Kay Sievers   driver-core: skip...
469
470
  		if (!netlink_has_listeners(uevent_sock, 1))
  			continue;
5f123fbd8   Kay Sievers   [PATCH] merge kob...
471
472
  		/* allocate message with the maximum possible size */
  		len = strlen(action_string) + strlen(devpath) + 2;
7eff2e7a8   Kay Sievers   Driver core: chan...
473
  		skb = alloc_skb(len + env->buflen, GFP_KERNEL);
5f123fbd8   Kay Sievers   [PATCH] merge kob...
474
  		if (skb) {
7eff2e7a8   Kay Sievers   Driver core: chan...
475
  			char *scratch;
5f123fbd8   Kay Sievers   [PATCH] merge kob...
476
477
478
479
480
  			/* add header */
  			scratch = skb_put(skb, len);
  			sprintf(scratch, "%s@%s", action_string, devpath);
  
  			/* copy keys to our continuous event payload buffer */
7eff2e7a8   Kay Sievers   Driver core: chan...
481
482
  			for (i = 0; i < env->envp_idx; i++) {
  				len = strlen(env->envp[i]) + 1;
5f123fbd8   Kay Sievers   [PATCH] merge kob...
483
  				scratch = skb_put(skb, len);
7eff2e7a8   Kay Sievers   Driver core: chan...
484
  				strcpy(scratch, env->envp[i]);
5f123fbd8   Kay Sievers   [PATCH] merge kob...
485
486
487
  			}
  
  			NETLINK_CB(skb).dst_group = 1;
5f71a2962   Eric W. Biederman   kobj: Send hotplu...
488
489
490
491
  			retval = netlink_broadcast_filtered(uevent_sock, skb,
  							    0, 1, GFP_KERNEL,
  							    kobj_bcast_filter,
  							    kobj);
ff491a733   Pablo Neira Ayuso   netlink: change r...
492
  			/* ENOBUFS should be handled in userspace */
ebf4127cd   Milan Broz   kobj_uevent: Igno...
493
  			if (retval == -ENOBUFS || retval == -ESRCH)
ff491a733   Pablo Neira Ayuso   netlink: change r...
494
  				retval = 0;
e0d7bf5d5   Ming Lei   kobject: return t...
495
496
  		} else
  			retval = -ENOMEM;
5f123fbd8   Kay Sievers   [PATCH] merge kob...
497
  	}
4d17ffda3   Kay Sievers   [PATCH] Kobject: ...
498
  #endif
7b60a18da   Andrew Vagin   uevent: send even...
499
  	mutex_unlock(&uevent_sock_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500

86d56134f   Michael Marineau   kobject: Make sup...
501
  #ifdef CONFIG_UEVENT_HELPER
5f123fbd8   Kay Sievers   [PATCH] merge kob...
502
  	/* call uevent_helper, usually only enabled during early boot */
417daa1e8   Eric W. Biederman   hotplug: netns aw...
503
  	if (uevent_helper[0] && !kobj_usermode_filter(kobj)) {
bcccff93a   Vladimir Davydov   kobject: don't bl...
504
  		struct subprocess_info *info;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505

7eff2e7a8   Kay Sievers   Driver core: chan...
506
507
508
  		retval = add_uevent_var(env, "HOME=/");
  		if (retval)
  			goto exit;
e374a2bfe   Greg Kroah-Hartman   Kobject: fix codi...
509
510
  		retval = add_uevent_var(env,
  					"PATH=/sbin:/bin:/usr/sbin:/usr/bin");
7eff2e7a8   Kay Sievers   Driver core: chan...
511
512
  		if (retval)
  			goto exit;
bcccff93a   Vladimir Davydov   kobject: don't bl...
513
514
515
  		retval = init_uevent_argv(env, subsystem);
  		if (retval)
  			goto exit;
7eff2e7a8   Kay Sievers   Driver core: chan...
516

bcccff93a   Vladimir Davydov   kobject: don't bl...
517
518
519
520
521
522
523
524
  		retval = -ENOMEM;
  		info = call_usermodehelper_setup(env->argv[0], env->argv,
  						 env->envp, GFP_KERNEL,
  						 NULL, cleanup_uevent_env, env);
  		if (info) {
  			retval = call_usermodehelper_exec(info, UMH_NO_WAIT);
  			env = NULL;	/* freed by cleanup_uevent_env */
  		}
5f123fbd8   Kay Sievers   [PATCH] merge kob...
525
  	}
86d56134f   Michael Marineau   kobject: Make sup...
526
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
528
  
  exit:
5f123fbd8   Kay Sievers   [PATCH] merge kob...
529
  	kfree(devpath);
7eff2e7a8   Kay Sievers   Driver core: chan...
530
  	kfree(env);
542cfce6f   Aneesh Kumar K.V   kobject: kobject_...
531
  	return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
  }
8a82472f8   Cornelia Huck   driver core: Intr...
533
534
535
  EXPORT_SYMBOL_GPL(kobject_uevent_env);
  
  /**
f6e6e7799   Xiaotian Feng   kobject_uevent: f...
536
   * kobject_uevent - notify userspace by sending an uevent
8a82472f8   Cornelia Huck   driver core: Intr...
537
   *
8a82472f8   Cornelia Huck   driver core: Intr...
538
   * @kobj: struct kobject that the action is happening to
edbbf994b   Julia Lawall   kobject: improve ...
539
   * @action: action that is happening
542cfce6f   Aneesh Kumar K.V   kobject: kobject_...
540
541
542
   *
   * Returns 0 if kobject_uevent() is completed with success or the
   * corresponding error when it fails.
8a82472f8   Cornelia Huck   driver core: Intr...
543
   */
542cfce6f   Aneesh Kumar K.V   kobject: kobject_...
544
  int kobject_uevent(struct kobject *kobj, enum kobject_action action)
8a82472f8   Cornelia Huck   driver core: Intr...
545
  {
542cfce6f   Aneesh Kumar K.V   kobject: kobject_...
546
  	return kobject_uevent_env(kobj, action, NULL);
8a82472f8   Cornelia Huck   driver core: Intr...
547
  }
312c004d3   Kay Sievers   [PATCH] driver co...
548
  EXPORT_SYMBOL_GPL(kobject_uevent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
550
  
  /**
7eff2e7a8   Kay Sievers   Driver core: chan...
551
552
553
   * add_uevent_var - add key value string to the environment buffer
   * @env: environment buffer structure
   * @format: printf format for the key=value pair
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554
555
556
557
   *
   * Returns 0 if environment variable was added successfully or -ENOMEM
   * if no space was available.
   */
7eff2e7a8   Kay Sievers   Driver core: chan...
558
  int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
  {
  	va_list args;
7eff2e7a8   Kay Sievers   Driver core: chan...
561
  	int len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562

7eff2e7a8   Kay Sievers   Driver core: chan...
563
  	if (env->envp_idx >= ARRAY_SIZE(env->envp)) {
5cd2b459d   Arjan van de Ven   Use WARN() in lib/
564
565
  		WARN(1, KERN_ERR "add_uevent_var: too many keys
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
  		return -ENOMEM;
7eff2e7a8   Kay Sievers   Driver core: chan...
567
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
569
  
  	va_start(args, format);
7eff2e7a8   Kay Sievers   Driver core: chan...
570
571
572
  	len = vsnprintf(&env->buf[env->buflen],
  			sizeof(env->buf) - env->buflen,
  			format, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
  	va_end(args);
7eff2e7a8   Kay Sievers   Driver core: chan...
574
  	if (len >= (sizeof(env->buf) - env->buflen)) {
5cd2b459d   Arjan van de Ven   Use WARN() in lib/
575
576
  		WARN(1, KERN_ERR "add_uevent_var: buffer size too small
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
  		return -ENOMEM;
7eff2e7a8   Kay Sievers   Driver core: chan...
578
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579

7eff2e7a8   Kay Sievers   Driver core: chan...
580
581
  	env->envp[env->envp_idx++] = &env->buf[env->buflen];
  	env->buflen += len + 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
583
  	return 0;
  }
312c004d3   Kay Sievers   [PATCH] driver co...
584
  EXPORT_SYMBOL_GPL(add_uevent_var);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585

4d17ffda3   Kay Sievers   [PATCH] Kobject: ...
586
  #if defined(CONFIG_NET)
07e98962f   Eric W. Biederman   kobject: Send hot...
587
  static int uevent_net_init(struct net *net)
5f123fbd8   Kay Sievers   [PATCH] merge kob...
588
  {
07e98962f   Eric W. Biederman   kobject: Send hot...
589
  	struct uevent_sock *ue_sk;
a31f2d17b   Pablo Neira Ayuso   netlink: add netl...
590
591
  	struct netlink_kernel_cfg cfg = {
  		.groups	= 1,
9785e10ae   Pablo Neira Ayuso   netlink: kill net...
592
  		.flags	= NL_CFG_F_NONROOT_RECV,
a31f2d17b   Pablo Neira Ayuso   netlink: add netl...
593
  	};
07e98962f   Eric W. Biederman   kobject: Send hot...
594
595
596
597
  
  	ue_sk = kzalloc(sizeof(*ue_sk), GFP_KERNEL);
  	if (!ue_sk)
  		return -ENOMEM;
9f00d9776   Pablo Neira Ayuso   netlink: hide str...
598
  	ue_sk->sk = netlink_kernel_create(net, NETLINK_KOBJECT_UEVENT, &cfg);
07e98962f   Eric W. Biederman   kobject: Send hot...
599
  	if (!ue_sk->sk) {
5f123fbd8   Kay Sievers   [PATCH] merge kob...
600
601
602
  		printk(KERN_ERR
  		       "kobject_uevent: unable to create netlink socket!
  ");
743db2d90   Dan Carpenter   kobject: free mem...
603
  		kfree(ue_sk);
5f123fbd8   Kay Sievers   [PATCH] merge kob...
604
605
  		return -ENODEV;
  	}
07e98962f   Eric W. Biederman   kobject: Send hot...
606
607
608
  	mutex_lock(&uevent_sock_mutex);
  	list_add_tail(&ue_sk->list, &uevent_sock_list);
  	mutex_unlock(&uevent_sock_mutex);
5f123fbd8   Kay Sievers   [PATCH] merge kob...
609
610
  	return 0;
  }
07e98962f   Eric W. Biederman   kobject: Send hot...
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
  static void uevent_net_exit(struct net *net)
  {
  	struct uevent_sock *ue_sk;
  
  	mutex_lock(&uevent_sock_mutex);
  	list_for_each_entry(ue_sk, &uevent_sock_list, list) {
  		if (sock_net(ue_sk->sk) == net)
  			goto found;
  	}
  	mutex_unlock(&uevent_sock_mutex);
  	return;
  
  found:
  	list_del(&ue_sk->list);
  	mutex_unlock(&uevent_sock_mutex);
  
  	netlink_kernel_release(ue_sk->sk);
  	kfree(ue_sk);
  }
  
  static struct pernet_operations uevent_net_ops = {
  	.init	= uevent_net_init,
  	.exit	= uevent_net_exit,
  };
  
  static int __init kobject_uevent_init(void)
  {
07e98962f   Eric W. Biederman   kobject: Send hot...
638
639
  	return register_pernet_subsys(&uevent_net_ops);
  }
5f123fbd8   Kay Sievers   [PATCH] merge kob...
640
  postcore_initcall(kobject_uevent_init);
4d17ffda3   Kay Sievers   [PATCH] Kobject: ...
641
  #endif