2 * kernel userspace event delivery
4 * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
5 * Copyright (C) 2004 Novell, Inc. All rights reserved.
6 * Copyright (C) 2004 IBM, Inc. All rights reserved.
8 * Licensed under the GNU GPL v2.
11 * Robert Love <rml@novell.com>
12 * Kay Sievers <kay.sievers@vrfy.org>
13 * Arjan van de Ven <arjanv@redhat.com>
14 * Greg Kroah-Hartman <greg@kroah.com>
17 #include <linux/spinlock.h>
18 #include <linux/socket.h>
19 #include <linux/skbuff.h>
20 #include <linux/netlink.h>
21 #include <linux/string.h>
22 #include <linux/kobject_uevent.h>
23 #include <linux/kobject.h>
27 * These must match up with the values for enum kobject_action
28 * as found in include/linux/kobject_uevent.h
30 static char *actions[] = {
38 static char *action_to_string(enum kobject_action action)
40 if (action >= KOBJ_MAX_ACTION)
43 return actions[action];
46 #ifdef CONFIG_KOBJECT_UEVENT
47 static struct sock *uevent_sock;
50 * send_uevent - notify userspace by sending event trough netlink socket
52 * @signal: signal name
53 * @obj: object path (kobject)
54 * @buf: buffer used to pass auxiliary data like the hotplug environment
58 static int send_uevent(const char *signal, const char *obj, const void *buf,
59 int buflen, int gfp_mask)
68 len = strlen(signal) + 1;
69 len += strlen(obj) + 1;
72 skb = alloc_skb(len, gfp_mask);
76 pos = skb_put(skb, len);
78 pos += sprintf(pos, "%s@%s", signal, obj) + 1;
79 memcpy(pos, buf, buflen);
81 return netlink_broadcast(uevent_sock, skb, 0, 1, gfp_mask);
84 static int do_kobject_uevent(struct kobject *kobj, enum kobject_action action,
85 struct attribute *attr, int gfp_mask)
93 path = kobject_get_path(kobj, gfp_mask);
97 signal = action_to_string(action);
103 len += strlen(attr->name) + 2;
104 attrpath = kmalloc(len, gfp_mask);
107 sprintf(attrpath, "%s/%s", path, attr->name);
108 rc = send_uevent(signal, attrpath, NULL, 0, gfp_mask);
111 rc = send_uevent(signal, path, NULL, 0, gfp_mask);
120 * kobject_uevent - notify userspace by sending event through netlink socket
122 * @signal: signal name
123 * @kobj: struct kobject that the event is happening to
124 * @attr: optional struct attribute the event belongs to
126 int kobject_uevent(struct kobject *kobj, enum kobject_action action,
127 struct attribute *attr)
129 return do_kobject_uevent(kobj, action, attr, GFP_KERNEL);
131 EXPORT_SYMBOL_GPL(kobject_uevent);
133 int kobject_uevent_atomic(struct kobject *kobj, enum kobject_action action,
134 struct attribute *attr)
136 return do_kobject_uevent(kobj, action, attr, GFP_ATOMIC);
139 EXPORT_SYMBOL_GPL(kobject_uevent_atomic);
141 static int __init kobject_uevent_init(void)
143 uevent_sock = netlink_kernel_create(NETLINK_KOBJECT_UEVENT, NULL);
147 "kobject_uevent: unable to create netlink socket!\n");
154 core_initcall(kobject_uevent_init);
157 static inline int send_uevent(const char *signal, const char *obj,
158 const void *buf, int buflen, int gfp_mask)
163 #endif /* CONFIG_KOBJECT_UEVENT */
166 #ifdef CONFIG_HOTPLUG
168 static spinlock_t sequence_lock = SPIN_LOCK_UNLOCKED;
170 #define BUFFER_SIZE 1024 /* should be enough memory for the env */
171 #define NUM_ENVP 32 /* number of env pointers */
173 * kobject_hotplug - notify userspace by executing /sbin/hotplug
175 * @action: action that is happening (usually "ADD" or "REMOVE")
176 * @kobj: struct kobject that the action is happening to
178 void kobject_hotplug(struct kobject *kobj, enum kobject_action action)
186 char *kobj_path = NULL;
190 struct kobject *top_kobj = kobj;
193 if (!top_kobj->kset && top_kobj->parent) {
195 top_kobj = top_kobj->parent;
196 } while (!top_kobj->kset && top_kobj->parent);
199 if (top_kobj->kset && top_kobj->kset->hotplug_ops)
200 kset = top_kobj->kset;
204 /* If the kset has a filter operation, call it.
205 Skip the event, if the filter returns zero. */
206 if (kset->hotplug_ops->filter) {
207 if (!kset->hotplug_ops->filter(kset, kobj))
211 pr_debug ("%s\n", __FUNCTION__);
213 action_string = action_to_string(action);
217 envp = kmalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
220 memset (envp, 0x00, NUM_ENVP * sizeof (char *));
222 buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
226 if (kset->hotplug_ops->name)
227 name = kset->hotplug_ops->name(kset, kobj);
229 name = kset->kobj.name;
231 argv [0] = hotplug_path;
235 /* minimal command environment */
236 envp [i++] = "HOME=/";
237 envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
241 envp [i++] = scratch;
242 scratch += sprintf(scratch, "ACTION=%s", action_string) + 1;
244 kobj_path = kobject_get_path(kobj, GFP_KERNEL);
248 envp [i++] = scratch;
249 scratch += sprintf (scratch, "DEVPATH=%s", kobj_path) + 1;
251 spin_lock(&sequence_lock);
252 seq = ++hotplug_seqnum;
253 spin_unlock(&sequence_lock);
255 envp [i++] = scratch;
256 scratch += sprintf(scratch, "SEQNUM=%lld", (long long)seq) + 1;
258 envp [i++] = scratch;
259 scratch += sprintf(scratch, "SUBSYSTEM=%s", name) + 1;
261 if (kset->hotplug_ops->hotplug) {
262 /* have the kset specific function add its stuff */
263 retval = kset->hotplug_ops->hotplug (kset, kobj,
264 &envp[i], NUM_ENVP - i, scratch,
265 BUFFER_SIZE - (scratch - buffer));
267 pr_debug ("%s - hotplug() returned %d\n",
268 __FUNCTION__, retval);
273 pr_debug ("%s: %s %s %s %s %s %s %s\n", __FUNCTION__, argv[0], argv[1],
274 envp[0], envp[1], envp[2], envp[3], envp[4]);
276 send_uevent(action_string, kobj_path, buffer, scratch - buffer, GFP_KERNEL);
278 if (!hotplug_path[0])
281 retval = call_usermodehelper (argv[0], argv, envp, 0);
283 pr_debug ("%s - call_usermodehelper returned %d\n",
284 __FUNCTION__, retval);
292 EXPORT_SYMBOL(kobject_hotplug);
293 #endif /* CONFIG_HOTPLUG */