OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [lib/] [kobject_uevent.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * kernel userspace event delivery
3
 *
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.
7
 *
8
 * Licensed under the GNU GPL v2.
9
 *
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>
15
 */
16
 
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>
24
 
25
 
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
32
 
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",
41
};
42
 
43
/**
44
 * kobject_action_type - translate action string to numeric type
45
 *
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
49
 *
50
 * Returns 0 if the action string was recognized.
51
 */
52
int kobject_action_type(const char *buf, size_t count,
53
                        enum kobject_action *type)
54
{
55
        enum kobject_action action;
56
        int ret = -EINVAL;
57
 
58
        if (count && buf[count-1] == '\n')
59
                count--;
60
 
61
        if (!count)
62
                goto out;
63
 
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;
72
        }
73
out:
74
        return ret;
75
}
76
 
77
/**
78
 * kobject_uevent_env - send an uevent with environmental data
79
 *
80
 * @action: action that is happening
81
 * @kobj: struct kobject that the action is happening to
82
 * @envp_ext: pointer to environmental data
83
 *
84
 * Returns 0 if kobject_uevent() is completed with success or the
85
 * corresponding error when it fails.
86
 */
87
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
88
                       char *envp_ext[])
89
{
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;
100
 
101
        pr_debug("%s\n", __FUNCTION__);
102
 
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;
107
 
108
        if (!top_kobj->kset) {
109
                pr_debug("kobject attempted to send uevent without kset!\n");
110
                return -EINVAL;
111
        }
112
 
113
        kset = top_kobj->kset;
114
        uevent_ops = kset->uevent_ops;
115
 
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;
121
                }
122
 
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 subsystem caused the event to drop!\n");
130
                return 0;
131
        }
132
 
133
        /* environment buffer */
134
        env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
135
        if (!env)
136
                return -ENOMEM;
137
 
138
        /* complete object path */
139
        devpath = kobject_get_path(kobj, GFP_KERNEL);
140
        if (!devpath) {
141
                retval = -ENOENT;
142
                goto exit;
143
        }
144
 
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;
155
 
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;
162
                }
163
        }
164
 
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;
172
                }
173
        }
174
 
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;
182
 
183
#if defined(CONFIG_NET)
184
        /* send netlink message */
185
        if (uevent_sock) {
186
                struct sk_buff *skb;
187
                size_t len;
188
 
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;
194
 
195
                        /* add header */
196
                        scratch = skb_put(skb, len);
197
                        sprintf(scratch, "%s@%s", action_string, devpath);
198
 
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]);
204
                        }
205
 
206
                        NETLINK_CB(skb).dst_group = 1;
207
                        netlink_broadcast(uevent_sock, skb, 0, 1, GFP_KERNEL);
208
                }
209
        }
210
#endif
211
 
212
        /* call uevent_helper, usually only enabled during early boot */
213
        if (uevent_helper[0]) {
214
                char *argv [3];
215
 
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;
225
 
226
                call_usermodehelper (argv[0], argv, env->envp, UMH_WAIT_EXEC);
227
        }
228
 
229
exit:
230
        kfree(devpath);
231
        kfree(env);
232
        return retval;
233
}
234
 
235
EXPORT_SYMBOL_GPL(kobject_uevent_env);
236
 
237
/**
238
 * kobject_uevent - notify userspace by ending an uevent
239
 *
240
 * @action: action that is happening
241
 * @kobj: struct kobject that the action is happening to
242
 *
243
 * Returns 0 if kobject_uevent() is completed with success or the
244
 * corresponding error when it fails.
245
 */
246
int kobject_uevent(struct kobject *kobj, enum kobject_action action)
247
{
248
        return kobject_uevent_env(kobj, action, NULL);
249
}
250
 
251
EXPORT_SYMBOL_GPL(kobject_uevent);
252
 
253
/**
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
257
 *
258
 * Returns 0 if environment variable was added successfully or -ENOMEM
259
 * if no space was available.
260
 */
261
int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
262
{
263
        va_list args;
264
        int len;
265
 
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;
270
        }
271
 
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);
277
 
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;
282
        }
283
 
284
        env->envp[env->envp_idx++] = &env->buf[env->buflen];
285
        env->buflen += len + 1;
286
        return 0;
287
}
288
EXPORT_SYMBOL_GPL(add_uevent_var);
289
 
290
#if defined(CONFIG_NET)
291
static int __init kobject_uevent_init(void)
292
{
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;
299
        }
300
 
301
        return 0;
302
}
303
 
304
postcore_initcall(kobject_uevent_init);
305
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.