Blame view
lib/kobject_uevent.c
14.8 KB
1da177e4c 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 [NETNS]: Do no in... |
18 19 |
#include <linux/string.h> #include <linux/kobject.h> |
8bc3bcc93 lib: reduce the u... |
20 21 |
#include <linux/export.h> #include <linux/kmod.h> |
5a0e3ad6a include cleanup: ... |
22 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
23 24 25 |
#include <linux/socket.h> #include <linux/skbuff.h> #include <linux/netlink.h> |
f36776faf kobject: support ... |
26 27 |
#include <linux/uuid.h> #include <linux/ctype.h> |
1da177e4c Linux-2.6.12-rc2 |
28 |
#include <net/sock.h> |
07e98962f kobject: Send hot... |
29 |
#include <net/net_namespace.h> |
1da177e4c Linux-2.6.12-rc2 |
30 |
|
1da177e4c Linux-2.6.12-rc2 |
31 |
|
cd030c4cb kobject: fix link... |
32 |
u64 uevent_seqnum; |
86d56134f kobject: Make sup... |
33 |
#ifdef CONFIG_UEVENT_HELPER |
6a8d8abb6 Driver core: add ... |
34 |
char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH; |
86d56134f kobject: Make sup... |
35 |
#endif |
07e98962f 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 kobject: fix link... |
42 |
#endif |
7b60a18da uevent: send even... |
43 44 |
/* This lock protects uevent_seqnum and uevent_sock_list */ static DEFINE_MUTEX(uevent_sock_mutex); |
5c5daf657 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 driver core: emit... |
53 54 |
[KOBJ_BIND] = "bind", [KOBJ_UNBIND] = "unbind", |
5c5daf657 Driver core: excl... |
55 |
}; |
f36776faf kobject: support ... |
56 57 58 |
static int kobject_action_type(const char *buf, size_t count, enum kobject_action *type, const char **args) |
5c5daf657 Driver core: excl... |
59 60 |
{ enum kobject_action action; |
f36776faf kobject: support ... |
61 62 |
size_t count_first; const char *args_start; |
5c5daf657 Driver core: excl... |
63 |
int ret = -EINVAL; |
a9edadbf7 fix uevent action... |
64 65 |
if (count && (buf[count-1] == ' ' || buf[count-1] == '\0')) |
5c5daf657 Driver core: excl... |
66 67 68 69 |
count--; if (!count) goto out; |
f36776faf 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 Driver core: excl... |
76 |
for (action = 0; action < ARRAY_SIZE(kobject_actions); action++) { |
f36776faf kobject: support ... |
77 |
if (strncmp(kobject_actions[action], buf, count_first) != 0) |
5c5daf657 Driver core: excl... |
78 |
continue; |
f36776faf kobject: support ... |
79 |
if (kobject_actions[action][count_first] != '\0') |
5c5daf657 Driver core: excl... |
80 |
continue; |
f36776faf kobject: support ... |
81 82 |
if (args) *args = args_start; |
5c5daf657 Driver core: excl... |
83 84 85 86 87 88 89 |
*type = action; ret = 0; break; } out: return ret; } |
f36776faf 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 lib/kobject_ueven... |
228 |
#ifdef CONFIG_NET |
5f71a2962 kobj: Send hotplu... |
229 230 |
static int kobj_bcast_filter(struct sock *dsk, struct sk_buff *skb, void *data) { |
82ef3d5d5 net: fix "queues"... |
231 |
struct kobject *kobj = data, *ksobj; |
5f71a2962 kobj: Send hotplu... |
232 233 234 |
const struct kobj_ns_type_operations *ops; ops = kobj_ns_ops(kobj); |
82ef3d5d5 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 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 lib/kobject_ueven... |
250 |
#endif |
5f71a2962 kobj: Send hotplu... |
251 |
|
86d56134f kobject: Make sup... |
252 |
#ifdef CONFIG_UEVENT_HELPER |
417daa1e8 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 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 kobject: Make sup... |
291 |
#endif |
bcccff93a kobject: don't bl... |
292 |
|
6878e7de6 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 Linux-2.6.12-rc2 |
312 |
/** |
8a82472f8 driver core: Intr... |
313 |
* kobject_uevent_env - send an uevent with environmental data |
1da177e4c Linux-2.6.12-rc2 |
314 |
* |
1da177e4c Linux-2.6.12-rc2 |
315 |
* @kobj: struct kobject that the action is happening to |
edbbf994b kobject: improve ... |
316 |
* @action: action that is happening |
8a82472f8 driver core: Intr... |
317 |
* @envp_ext: pointer to environmental data |
542cfce6f kobject: kobject_... |
318 |
* |
f6e6e7799 kobject_uevent: f... |
319 |
* Returns 0 if kobject_uevent_env() is completed with success or the |
542cfce6f kobject: kobject_... |
320 |
* corresponding error when it fails. |
1da177e4c Linux-2.6.12-rc2 |
321 |
*/ |
542cfce6f kobject: kobject_... |
322 |
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, |
7eff2e7a8 Driver core: chan... |
323 |
char *envp_ext[]) |
1da177e4c Linux-2.6.12-rc2 |
324 |
{ |
7eff2e7a8 Driver core: chan... |
325 326 |
struct kobj_uevent_env *env; const char *action_string = kobject_actions[action]; |
5f123fbd8 [PATCH] merge kob... |
327 328 329 330 |
const char *devpath = NULL; const char *subsystem; struct kobject *top_kobj; struct kset *kset; |
9cd43611c kobject: Constify... |
331 |
const struct kset_uevent_ops *uevent_ops; |
1da177e4c Linux-2.6.12-rc2 |
332 |
int i = 0; |
542cfce6f kobject: kobject_... |
333 |
int retval = 0; |
07e98962f kobject: Send hot... |
334 335 336 |
#ifdef CONFIG_NET struct uevent_sock *ue_sk; #endif |
1da177e4c Linux-2.6.12-rc2 |
337 |
|
9f66fa2a4 kobject: clean up... |
338 339 |
pr_debug("kobject: '%s' (%p): %s ", |
810304db7 lib: replace rema... |
340 |
kobject_name(kobj), kobj, __func__); |
5f123fbd8 [PATCH] merge kob... |
341 |
|
5f123fbd8 [PATCH] merge kob... |
342 343 |
/* search the kset we belong to */ top_kobj = kobj; |
ccd490a3c Driver core: kern... |
344 |
while (!top_kobj->kset && top_kobj->parent) |
14193fb91 Kobject: kobject_... |
345 |
top_kobj = top_kobj->parent; |
ccd490a3c Driver core: kern... |
346 |
|
542cfce6f kobject: kobject_... |
347 |
if (!top_kobj->kset) { |
9f66fa2a4 kobject: clean up... |
348 349 350 |
pr_debug("kobject: '%s' (%p): %s: attempted to send uevent " "without kset! ", kobject_name(kobj), kobj, |
810304db7 lib: replace rema... |
351 |
__func__); |
542cfce6f kobject: kobject_... |
352 353 |
return -EINVAL; } |
1da177e4c Linux-2.6.12-rc2 |
354 |
|
5f123fbd8 [PATCH] merge kob... |
355 |
kset = top_kobj->kset; |
312c004d3 [PATCH] driver co... |
356 |
uevent_ops = kset->uevent_ops; |
1da177e4c Linux-2.6.12-rc2 |
357 |
|
f67f129e5 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 Driver core: chan... |
366 |
/* skip the event, if the filter returns zero. */ |
312c004d3 [PATCH] driver co... |
367 |
if (uevent_ops && uevent_ops->filter) |
542cfce6f kobject: kobject_... |
368 |
if (!uevent_ops->filter(kset, kobj)) { |
9f66fa2a4 kobject: clean up... |
369 370 371 |
pr_debug("kobject: '%s' (%p): %s: filter function " "caused the event to drop! ", |
810304db7 lib: replace rema... |
372 |
kobject_name(kobj), kobj, __func__); |
542cfce6f kobject: kobject_... |
373 374 |
return 0; } |
1da177e4c Linux-2.6.12-rc2 |
375 |
|
864062457 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 kobject: clean up... |
382 383 384 |
pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the " "event to drop! ", kobject_name(kobj), kobj, |
810304db7 lib: replace rema... |
385 |
__func__); |
864062457 driver core: fix ... |
386 387 |
return 0; } |
7eff2e7a8 Driver core: chan... |
388 389 390 |
/* environment buffer */ env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); if (!env) |
542cfce6f kobject: kobject_... |
391 |
return -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
392 |
|
5f123fbd8 [PATCH] merge kob... |
393 394 |
/* complete object path */ devpath = kobject_get_path(kobj, GFP_KERNEL); |
542cfce6f kobject: kobject_... |
395 396 |
if (!devpath) { retval = -ENOENT; |
5f123fbd8 [PATCH] merge kob... |
397 |
goto exit; |
542cfce6f kobject: kobject_... |
398 |
} |
1da177e4c Linux-2.6.12-rc2 |
399 |
|
5f123fbd8 [PATCH] merge kob... |
400 |
/* default keys */ |
7eff2e7a8 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 uevent: don't pas... |
414 |
retval = add_uevent_var(env, "%s", envp_ext[i]); |
7eff2e7a8 Driver core: chan... |
415 416 417 418 |
if (retval) goto exit; } } |
1da177e4c Linux-2.6.12-rc2 |
419 |
|
5f123fbd8 [PATCH] merge kob... |
420 |
/* let the kset specific function add its stuff */ |
312c004d3 [PATCH] driver co... |
421 |
if (uevent_ops && uevent_ops->uevent) { |
7eff2e7a8 Driver core: chan... |
422 |
retval = uevent_ops->uevent(kset, kobj, env); |
1da177e4c Linux-2.6.12-rc2 |
423 |
if (retval) { |
9f66fa2a4 kobject: clean up... |
424 425 426 |
pr_debug("kobject: '%s' (%p): %s: uevent() returned " "%d ", kobject_name(kobj), kobj, |
810304db7 lib: replace rema... |
427 |
__func__, retval); |
1da177e4c Linux-2.6.12-rc2 |
428 429 430 |
goto exit; } } |
6878e7de6 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 Kobject: auto-cle... |
440 |
kobj->state_add_uevent_sent = 1; |
6878e7de6 driver core: supp... |
441 442 443 |
break; case KOBJ_REMOVE: |
0f4dafc05 Kobject: auto-cle... |
444 |
kobj->state_remove_uevent_sent = 1; |
6878e7de6 driver core: supp... |
445 446 447 448 449 450 451 452 453 |
break; case KOBJ_UNBIND: zap_modalias_env(env); break; default: break; } |
0f4dafc05 Kobject: auto-cle... |
454 |
|
7b60a18da uevent: send even... |
455 |
mutex_lock(&uevent_sock_mutex); |
7eff2e7a8 Driver core: chan... |
456 |
/* we will send an event, so request a new sequence number */ |
7b60a18da 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 Driver core: chan... |
460 |
goto exit; |
7b60a18da uevent: send even... |
461 |
} |
1da177e4c Linux-2.6.12-rc2 |
462 |
|
4d17ffda3 [PATCH] Kobject: ... |
463 |
#if defined(CONFIG_NET) |
5f123fbd8 [PATCH] merge kob... |
464 |
/* send netlink message */ |
07e98962f kobject: Send hot... |
465 466 |
list_for_each_entry(ue_sk, &uevent_sock_list, list) { struct sock *uevent_sock = ue_sk->sk; |
5f123fbd8 [PATCH] merge kob... |
467 468 |
struct sk_buff *skb; size_t len; |
74099b18b driver-core: skip... |
469 470 |
if (!netlink_has_listeners(uevent_sock, 1)) continue; |
5f123fbd8 [PATCH] merge kob... |
471 472 |
/* allocate message with the maximum possible size */ len = strlen(action_string) + strlen(devpath) + 2; |
7eff2e7a8 Driver core: chan... |
473 |
skb = alloc_skb(len + env->buflen, GFP_KERNEL); |
5f123fbd8 [PATCH] merge kob... |
474 |
if (skb) { |
7eff2e7a8 Driver core: chan... |
475 |
char *scratch; |
5f123fbd8 [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 Driver core: chan... |
481 482 |
for (i = 0; i < env->envp_idx; i++) { len = strlen(env->envp[i]) + 1; |
5f123fbd8 [PATCH] merge kob... |
483 |
scratch = skb_put(skb, len); |
7eff2e7a8 Driver core: chan... |
484 |
strcpy(scratch, env->envp[i]); |
5f123fbd8 [PATCH] merge kob... |
485 486 487 |
} NETLINK_CB(skb).dst_group = 1; |
5f71a2962 kobj: Send hotplu... |
488 489 490 491 |
retval = netlink_broadcast_filtered(uevent_sock, skb, 0, 1, GFP_KERNEL, kobj_bcast_filter, kobj); |
ff491a733 netlink: change r... |
492 |
/* ENOBUFS should be handled in userspace */ |
ebf4127cd kobj_uevent: Igno... |
493 |
if (retval == -ENOBUFS || retval == -ESRCH) |
ff491a733 netlink: change r... |
494 |
retval = 0; |
e0d7bf5d5 kobject: return t... |
495 496 |
} else retval = -ENOMEM; |
5f123fbd8 [PATCH] merge kob... |
497 |
} |
4d17ffda3 [PATCH] Kobject: ... |
498 |
#endif |
7b60a18da uevent: send even... |
499 |
mutex_unlock(&uevent_sock_mutex); |
1da177e4c Linux-2.6.12-rc2 |
500 |
|
86d56134f kobject: Make sup... |
501 |
#ifdef CONFIG_UEVENT_HELPER |
5f123fbd8 [PATCH] merge kob... |
502 |
/* call uevent_helper, usually only enabled during early boot */ |
417daa1e8 hotplug: netns aw... |
503 |
if (uevent_helper[0] && !kobj_usermode_filter(kobj)) { |
bcccff93a kobject: don't bl... |
504 |
struct subprocess_info *info; |
1da177e4c Linux-2.6.12-rc2 |
505 |
|
7eff2e7a8 Driver core: chan... |
506 507 508 |
retval = add_uevent_var(env, "HOME=/"); if (retval) goto exit; |
e374a2bfe Kobject: fix codi... |
509 510 |
retval = add_uevent_var(env, "PATH=/sbin:/bin:/usr/sbin:/usr/bin"); |
7eff2e7a8 Driver core: chan... |
511 512 |
if (retval) goto exit; |
bcccff93a kobject: don't bl... |
513 514 515 |
retval = init_uevent_argv(env, subsystem); if (retval) goto exit; |
7eff2e7a8 Driver core: chan... |
516 |
|
bcccff93a 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 [PATCH] merge kob... |
525 |
} |
86d56134f kobject: Make sup... |
526 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
527 528 |
exit: |
5f123fbd8 [PATCH] merge kob... |
529 |
kfree(devpath); |
7eff2e7a8 Driver core: chan... |
530 |
kfree(env); |
542cfce6f kobject: kobject_... |
531 |
return retval; |
1da177e4c Linux-2.6.12-rc2 |
532 |
} |
8a82472f8 driver core: Intr... |
533 534 535 |
EXPORT_SYMBOL_GPL(kobject_uevent_env); /** |
f6e6e7799 kobject_uevent: f... |
536 |
* kobject_uevent - notify userspace by sending an uevent |
8a82472f8 driver core: Intr... |
537 |
* |
8a82472f8 driver core: Intr... |
538 |
* @kobj: struct kobject that the action is happening to |
edbbf994b kobject: improve ... |
539 |
* @action: action that is happening |
542cfce6f kobject: kobject_... |
540 541 542 |
* * Returns 0 if kobject_uevent() is completed with success or the * corresponding error when it fails. |
8a82472f8 driver core: Intr... |
543 |
*/ |
542cfce6f kobject: kobject_... |
544 |
int kobject_uevent(struct kobject *kobj, enum kobject_action action) |
8a82472f8 driver core: Intr... |
545 |
{ |
542cfce6f kobject: kobject_... |
546 |
return kobject_uevent_env(kobj, action, NULL); |
8a82472f8 driver core: Intr... |
547 |
} |
312c004d3 [PATCH] driver co... |
548 |
EXPORT_SYMBOL_GPL(kobject_uevent); |
1da177e4c Linux-2.6.12-rc2 |
549 550 |
/** |
7eff2e7a8 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 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 Driver core: chan... |
558 |
int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) |
1da177e4c Linux-2.6.12-rc2 |
559 560 |
{ va_list args; |
7eff2e7a8 Driver core: chan... |
561 |
int len; |
1da177e4c Linux-2.6.12-rc2 |
562 |
|
7eff2e7a8 Driver core: chan... |
563 |
if (env->envp_idx >= ARRAY_SIZE(env->envp)) { |
5cd2b459d Use WARN() in lib/ |
564 565 |
WARN(1, KERN_ERR "add_uevent_var: too many keys "); |
1da177e4c Linux-2.6.12-rc2 |
566 |
return -ENOMEM; |
7eff2e7a8 Driver core: chan... |
567 |
} |
1da177e4c Linux-2.6.12-rc2 |
568 569 |
va_start(args, format); |
7eff2e7a8 Driver core: chan... |
570 571 572 |
len = vsnprintf(&env->buf[env->buflen], sizeof(env->buf) - env->buflen, format, args); |
1da177e4c Linux-2.6.12-rc2 |
573 |
va_end(args); |
7eff2e7a8 Driver core: chan... |
574 |
if (len >= (sizeof(env->buf) - env->buflen)) { |
5cd2b459d Use WARN() in lib/ |
575 576 |
WARN(1, KERN_ERR "add_uevent_var: buffer size too small "); |
1da177e4c Linux-2.6.12-rc2 |
577 |
return -ENOMEM; |
7eff2e7a8 Driver core: chan... |
578 |
} |
1da177e4c Linux-2.6.12-rc2 |
579 |
|
7eff2e7a8 Driver core: chan... |
580 581 |
env->envp[env->envp_idx++] = &env->buf[env->buflen]; env->buflen += len + 1; |
1da177e4c Linux-2.6.12-rc2 |
582 583 |
return 0; } |
312c004d3 [PATCH] driver co... |
584 |
EXPORT_SYMBOL_GPL(add_uevent_var); |
1da177e4c Linux-2.6.12-rc2 |
585 |
|
4d17ffda3 [PATCH] Kobject: ... |
586 |
#if defined(CONFIG_NET) |
07e98962f kobject: Send hot... |
587 |
static int uevent_net_init(struct net *net) |
5f123fbd8 [PATCH] merge kob... |
588 |
{ |
07e98962f kobject: Send hot... |
589 |
struct uevent_sock *ue_sk; |
a31f2d17b netlink: add netl... |
590 591 |
struct netlink_kernel_cfg cfg = { .groups = 1, |
9785e10ae netlink: kill net... |
592 |
.flags = NL_CFG_F_NONROOT_RECV, |
a31f2d17b netlink: add netl... |
593 |
}; |
07e98962f kobject: Send hot... |
594 595 596 597 |
ue_sk = kzalloc(sizeof(*ue_sk), GFP_KERNEL); if (!ue_sk) return -ENOMEM; |
9f00d9776 netlink: hide str... |
598 |
ue_sk->sk = netlink_kernel_create(net, NETLINK_KOBJECT_UEVENT, &cfg); |
07e98962f kobject: Send hot... |
599 |
if (!ue_sk->sk) { |
5f123fbd8 [PATCH] merge kob... |
600 601 602 |
printk(KERN_ERR "kobject_uevent: unable to create netlink socket! "); |
743db2d90 kobject: free mem... |
603 |
kfree(ue_sk); |
5f123fbd8 [PATCH] merge kob... |
604 605 |
return -ENODEV; } |
07e98962f 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 [PATCH] merge kob... |
609 610 |
return 0; } |
07e98962f 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 kobject: Send hot... |
638 639 |
return register_pernet_subsys(&uevent_net_ops); } |
5f123fbd8 [PATCH] merge kob... |
640 |
postcore_initcall(kobject_uevent_init); |
4d17ffda3 [PATCH] Kobject: ... |
641 |
#endif |