add-vmcore: cleanup the coding style according to Andrew's comments
[linux-2.6/linux-2.6-openrd.git] / lib / kobject_uevent.c
blob2e4eae5b0824400de9f6eeafb5483c3fde8f5b0c
1 /*
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.
10 * Authors:
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.h>
23 #include <net/sock.h>
26 u64 uevent_seqnum;
27 char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
28 static DEFINE_SPINLOCK(sequence_lock);
29 #if defined(CONFIG_NET)
30 static struct sock *uevent_sock;
31 #endif
33 /* the strings here must match the enum in include/linux/kobject.h */
34 static const char *kobject_actions[] = {
35 [KOBJ_ADD] = "add",
36 [KOBJ_REMOVE] = "remove",
37 [KOBJ_CHANGE] = "change",
38 [KOBJ_MOVE] = "move",
39 [KOBJ_ONLINE] = "online",
40 [KOBJ_OFFLINE] = "offline",
43 /**
44 * kobject_action_type - translate action string to numeric type
46 * @buf: buffer containing the action string, newline is ignored
47 * @len: length of buffer
48 * @type: pointer to the location to store the action type
50 * Returns 0 if the action string was recognized.
52 int kobject_action_type(const char *buf, size_t count,
53 enum kobject_action *type)
55 enum kobject_action action;
56 int ret = -EINVAL;
58 if (count && buf[count-1] == '\n')
59 count--;
61 if (!count)
62 goto out;
64 for (action = 0; action < ARRAY_SIZE(kobject_actions); action++) {
65 if (strncmp(kobject_actions[action], buf, count) != 0)
66 continue;
67 if (kobject_actions[action][count] != '\0')
68 continue;
69 *type = action;
70 ret = 0;
71 break;
73 out:
74 return ret;
77 /**
78 * kobject_uevent_env - send an uevent with environmental data
80 * @action: action that is happening
81 * @kobj: struct kobject that the action is happening to
82 * @envp_ext: pointer to environmental data
84 * Returns 0 if kobject_uevent() is completed with success or the
85 * corresponding error when it fails.
87 int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
88 char *envp_ext[])
90 struct kobj_uevent_env *env;
91 const char *action_string = kobject_actions[action];
92 const char *devpath = NULL;
93 const char *subsystem;
94 struct kobject *top_kobj;
95 struct kset *kset;
96 struct kset_uevent_ops *uevent_ops;
97 u64 seq;
98 int i = 0;
99 int retval = 0;
101 pr_debug("%s\n", __FUNCTION__);
103 /* search the kset we belong to */
104 top_kobj = kobj;
105 while (!top_kobj->kset && top_kobj->parent)
106 top_kobj = top_kobj->parent;
108 if (!top_kobj->kset) {
109 pr_debug("kobject attempted to send uevent without kset!\n");
110 return -EINVAL;
113 kset = top_kobj->kset;
114 uevent_ops = kset->uevent_ops;
116 /* skip the event, if the filter returns zero. */
117 if (uevent_ops && uevent_ops->filter)
118 if (!uevent_ops->filter(kset, kobj)) {
119 pr_debug("kobject filter function caused the event to drop!\n");
120 return 0;
123 /* originating subsystem */
124 if (uevent_ops && uevent_ops->name)
125 subsystem = uevent_ops->name(kset, kobj);
126 else
127 subsystem = kobject_name(&kset->kobj);
128 if (!subsystem) {
129 pr_debug("unset subsytem caused the event to drop!\n");
130 return 0;
133 /* environment buffer */
134 env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
135 if (!env)
136 return -ENOMEM;
138 /* complete object path */
139 devpath = kobject_get_path(kobj, GFP_KERNEL);
140 if (!devpath) {
141 retval = -ENOENT;
142 goto exit;
145 /* default keys */
146 retval = add_uevent_var(env, "ACTION=%s", action_string);
147 if (retval)
148 goto exit;
149 retval = add_uevent_var(env, "DEVPATH=%s", devpath);
150 if (retval)
151 goto exit;
152 retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
153 if (retval)
154 goto exit;
156 /* keys passed in from the caller */
157 if (envp_ext) {
158 for (i = 0; envp_ext[i]; i++) {
159 retval = add_uevent_var(env, envp_ext[i]);
160 if (retval)
161 goto exit;
165 /* let the kset specific function add its stuff */
166 if (uevent_ops && uevent_ops->uevent) {
167 retval = uevent_ops->uevent(kset, kobj, env);
168 if (retval) {
169 pr_debug ("%s - uevent() returned %d\n",
170 __FUNCTION__, retval);
171 goto exit;
175 /* we will send an event, so request a new sequence number */
176 spin_lock(&sequence_lock);
177 seq = ++uevent_seqnum;
178 spin_unlock(&sequence_lock);
179 retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq);
180 if (retval)
181 goto exit;
183 #if defined(CONFIG_NET)
184 /* send netlink message */
185 if (uevent_sock) {
186 struct sk_buff *skb;
187 size_t len;
189 /* allocate message with the maximum possible size */
190 len = strlen(action_string) + strlen(devpath) + 2;
191 skb = alloc_skb(len + env->buflen, GFP_KERNEL);
192 if (skb) {
193 char *scratch;
195 /* add header */
196 scratch = skb_put(skb, len);
197 sprintf(scratch, "%s@%s", action_string, devpath);
199 /* copy keys to our continuous event payload buffer */
200 for (i = 0; i < env->envp_idx; i++) {
201 len = strlen(env->envp[i]) + 1;
202 scratch = skb_put(skb, len);
203 strcpy(scratch, env->envp[i]);
206 NETLINK_CB(skb).dst_group = 1;
207 netlink_broadcast(uevent_sock, skb, 0, 1, GFP_KERNEL);
210 #endif
212 /* call uevent_helper, usually only enabled during early boot */
213 if (uevent_helper[0]) {
214 char *argv [3];
216 argv [0] = uevent_helper;
217 argv [1] = (char *)subsystem;
218 argv [2] = NULL;
219 retval = add_uevent_var(env, "HOME=/");
220 if (retval)
221 goto exit;
222 retval = add_uevent_var(env, "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
223 if (retval)
224 goto exit;
226 call_usermodehelper (argv[0], argv, env->envp, UMH_WAIT_EXEC);
229 exit:
230 kfree(devpath);
231 kfree(env);
232 return retval;
235 EXPORT_SYMBOL_GPL(kobject_uevent_env);
238 * kobject_uevent - notify userspace by ending an uevent
240 * @action: action that is happening
241 * @kobj: struct kobject that the action is happening to
243 * Returns 0 if kobject_uevent() is completed with success or the
244 * corresponding error when it fails.
246 int kobject_uevent(struct kobject *kobj, enum kobject_action action)
248 return kobject_uevent_env(kobj, action, NULL);
251 EXPORT_SYMBOL_GPL(kobject_uevent);
254 * add_uevent_var - add key value string to the environment buffer
255 * @env: environment buffer structure
256 * @format: printf format for the key=value pair
258 * Returns 0 if environment variable was added successfully or -ENOMEM
259 * if no space was available.
261 int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
263 va_list args;
264 int len;
266 if (env->envp_idx >= ARRAY_SIZE(env->envp)) {
267 printk(KERN_ERR "add_uevent_var: too many keys\n");
268 WARN_ON(1);
269 return -ENOMEM;
272 va_start(args, format);
273 len = vsnprintf(&env->buf[env->buflen],
274 sizeof(env->buf) - env->buflen,
275 format, args);
276 va_end(args);
278 if (len >= (sizeof(env->buf) - env->buflen)) {
279 printk(KERN_ERR "add_uevent_var: buffer size too small\n");
280 WARN_ON(1);
281 return -ENOMEM;
284 env->envp[env->envp_idx++] = &env->buf[env->buflen];
285 env->buflen += len + 1;
286 return 0;
288 EXPORT_SYMBOL_GPL(add_uevent_var);
290 #if defined(CONFIG_NET)
291 static int __init kobject_uevent_init(void)
293 uevent_sock = netlink_kernel_create(&init_net, NETLINK_KOBJECT_UEVENT,
294 1, NULL, NULL, THIS_MODULE);
295 if (!uevent_sock) {
296 printk(KERN_ERR
297 "kobject_uevent: unable to create netlink socket!\n");
298 return -ENODEV;
301 return 0;
304 postcore_initcall(kobject_uevent_init);
305 #endif