aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kobject_uevent.c
diff options
context:
space:
mode:
authorKay Sievers <kay.sievers@suse.de>2005-11-11 08:43:07 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-01-04 19:18:07 -0500
commit5f123fbd80f4f788554636f02bf73e40f914e0d6 (patch)
treedbb7db4c62fa8130a393ce772cf819fcffe2606b /lib/kobject_uevent.c
parent033b96fd30db52a710d97b06f87d16fc59fee0f1 (diff)
[PATCH] merge kobject_uevent and kobject_hotplug
The distinction between hotplug and uevent does not make sense these days, netlink events are the default. udev depends entirely on netlink uevents. Only during early boot and in initramfs, /sbin/hotplug is needed. So merge the two functions and provide only one interface without all the options. The netlink layer got a nice generic interface with named slots recently, which is probably a better facility to plug events for subsystem specific events. Also the new poll() interface to /proc/mounts is a nicer way to notify about changes than sending events through the core. The uevents should only be used for driver core related requests to userspace now. Signed-off-by: Kay Sievers <kay.sievers@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'lib/kobject_uevent.c')
-rw-r--r--lib/kobject_uevent.c279
1 files changed, 95 insertions, 184 deletions
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index 845bf67d94ca..dd061da3aba9 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -29,6 +29,7 @@
29char hotplug_path[HOTPLUG_PATH_LEN] = "/sbin/hotplug"; 29char hotplug_path[HOTPLUG_PATH_LEN] = "/sbin/hotplug";
30u64 hotplug_seqnum; 30u64 hotplug_seqnum;
31static DEFINE_SPINLOCK(sequence_lock); 31static DEFINE_SPINLOCK(sequence_lock);
32static struct sock *uevent_sock;
32 33
33static char *action_to_string(enum kobject_action action) 34static char *action_to_string(enum kobject_action action)
34{ 35{
@@ -48,123 +49,6 @@ static char *action_to_string(enum kobject_action action)
48 } 49 }
49} 50}
50 51
51static struct sock *uevent_sock;
52
53/**
54 * send_uevent - notify userspace by sending event through netlink socket
55 *
56 * @signal: signal name
57 * @obj: object path (kobject)
58 * @envp: possible hotplug environment to pass with the message
59 * @gfp_mask:
60 */
61static int send_uevent(const char *signal, const char *obj,
62 char **envp, gfp_t gfp_mask)
63{
64 struct sk_buff *skb;
65 char *pos;
66 int len;
67
68 if (!uevent_sock)
69 return -EIO;
70
71 len = strlen(signal) + 1;
72 len += strlen(obj) + 1;
73
74 /* allocate buffer with the maximum possible message size */
75 skb = alloc_skb(len + BUFFER_SIZE, gfp_mask);
76 if (!skb)
77 return -ENOMEM;
78
79 pos = skb_put(skb, len);
80 sprintf(pos, "%s@%s", signal, obj);
81
82 /* copy the environment key by key to our continuous buffer */
83 if (envp) {
84 int i;
85
86 for (i = 2; envp[i]; i++) {
87 len = strlen(envp[i]) + 1;
88 pos = skb_put(skb, len);
89 strcpy(pos, envp[i]);
90 }
91 }
92
93 NETLINK_CB(skb).dst_group = 1;
94 return netlink_broadcast(uevent_sock, skb, 0, 1, gfp_mask);
95}
96
97static int do_kobject_uevent(struct kobject *kobj, enum kobject_action action,
98 struct attribute *attr, gfp_t gfp_mask)
99{
100 char *path;
101 char *attrpath;
102 char *signal;
103 int len;
104 int rc = -ENOMEM;
105
106 path = kobject_get_path(kobj, gfp_mask);
107 if (!path)
108 return -ENOMEM;
109
110 signal = action_to_string(action);
111 if (!signal)
112 return -EINVAL;
113
114 if (attr) {
115 len = strlen(path);
116 len += strlen(attr->name) + 2;
117 attrpath = kmalloc(len, gfp_mask);
118 if (!attrpath)
119 goto exit;
120 sprintf(attrpath, "%s/%s", path, attr->name);
121 rc = send_uevent(signal, attrpath, NULL, gfp_mask);
122 kfree(attrpath);
123 } else
124 rc = send_uevent(signal, path, NULL, gfp_mask);
125
126exit:
127 kfree(path);
128 return rc;
129}
130
131/**
132 * kobject_uevent - notify userspace by sending event through netlink socket
133 *
134 * @signal: signal name
135 * @kobj: struct kobject that the event is happening to
136 * @attr: optional struct attribute the event belongs to
137 */
138int kobject_uevent(struct kobject *kobj, enum kobject_action action,
139 struct attribute *attr)
140{
141 return do_kobject_uevent(kobj, action, attr, GFP_KERNEL);
142}
143EXPORT_SYMBOL_GPL(kobject_uevent);
144
145int kobject_uevent_atomic(struct kobject *kobj, enum kobject_action action,
146 struct attribute *attr)
147{
148 return do_kobject_uevent(kobj, action, attr, GFP_ATOMIC);
149}
150EXPORT_SYMBOL_GPL(kobject_uevent_atomic);
151
152static int __init kobject_uevent_init(void)
153{
154 uevent_sock = netlink_kernel_create(NETLINK_KOBJECT_UEVENT, 1, NULL,
155 THIS_MODULE);
156
157 if (!uevent_sock) {
158 printk(KERN_ERR
159 "kobject_uevent: unable to create netlink socket!\n");
160 return -ENODEV;
161 }
162
163 return 0;
164}
165
166postcore_initcall(kobject_uevent_init);
167
168/** 52/**
169 * kobject_hotplug - notify userspace by executing /sbin/hotplug 53 * kobject_hotplug - notify userspace by executing /sbin/hotplug
170 * 54 *
@@ -173,95 +57,84 @@ postcore_initcall(kobject_uevent_init);
173 */ 57 */
174void kobject_hotplug(struct kobject *kobj, enum kobject_action action) 58void kobject_hotplug(struct kobject *kobj, enum kobject_action action)
175{ 59{
176 char *argv [3]; 60 char **envp;
177 char **envp = NULL; 61 char *buffer;
178 char *buffer = NULL;
179 char *seq_buff;
180 char *scratch; 62 char *scratch;
63 const char *action_string;
64 const char *devpath = NULL;
65 const char *subsystem;
66 struct kobject *top_kobj;
67 struct kset *kset;
68 struct kset_hotplug_ops *hotplug_ops;
69 u64 seq;
70 char *seq_buff;
181 int i = 0; 71 int i = 0;
182 int retval; 72 int retval;
183 char *kobj_path = NULL;
184 const char *name = NULL;
185 char *action_string;
186 u64 seq;
187 struct kobject *top_kobj = kobj;
188 struct kset *kset;
189 static struct kset_hotplug_ops null_hotplug_ops;
190 struct kset_hotplug_ops *hotplug_ops = &null_hotplug_ops;
191 73
192 /* If this kobj does not belong to a kset, 74 pr_debug("%s\n", __FUNCTION__);
193 try to find a parent that does. */ 75
76 action_string = action_to_string(action);
77 if (!action_string)
78 return;
79
80 /* search the kset we belong to */
81 top_kobj = kobj;
194 if (!top_kobj->kset && top_kobj->parent) { 82 if (!top_kobj->kset && top_kobj->parent) {
195 do { 83 do {
196 top_kobj = top_kobj->parent; 84 top_kobj = top_kobj->parent;
197 } while (!top_kobj->kset && top_kobj->parent); 85 } while (!top_kobj->kset && top_kobj->parent);
198 } 86 }
199 87 if (!top_kobj->kset)
200 if (top_kobj->kset)
201 kset = top_kobj->kset;
202 else
203 return; 88 return;
204 89
205 if (kset->hotplug_ops) 90 kset = top_kobj->kset;
206 hotplug_ops = kset->hotplug_ops; 91 hotplug_ops = kset->hotplug_ops;
207 92
208 /* If the kset has a filter operation, call it. 93 /* skip the event, if the filter returns zero. */
209 Skip the event, if the filter returns zero. */ 94 if (hotplug_ops && hotplug_ops->filter)
210 if (hotplug_ops->filter) {
211 if (!hotplug_ops->filter(kset, kobj)) 95 if (!hotplug_ops->filter(kset, kobj))
212 return; 96 return;
213 }
214
215 pr_debug ("%s\n", __FUNCTION__);
216
217 action_string = action_to_string(action);
218 if (!action_string)
219 return;
220 97
221 envp = kmalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL); 98 /* environment index */
99 envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
222 if (!envp) 100 if (!envp)
223 return; 101 return;
224 memset (envp, 0x00, NUM_ENVP * sizeof (char *));
225 102
103 /* environment values */
226 buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); 104 buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
227 if (!buffer) 105 if (!buffer)
228 goto exit; 106 goto exit;
229 107
230 if (hotplug_ops->name) 108 /* complete object path */
231 name = hotplug_ops->name(kset, kobj); 109 devpath = kobject_get_path(kobj, GFP_KERNEL);
232 if (name == NULL) 110 if (!devpath)
233 name = kobject_name(&kset->kobj); 111 goto exit;
234 112
235 argv [0] = hotplug_path; 113 /* originating subsystem */
236 argv [1] = (char *)name; /* won't be changed but 'const' has to go */ 114 if (hotplug_ops && hotplug_ops->name)
237 argv [2] = NULL; 115 subsystem = hotplug_ops->name(kset, kobj);
116 else
117 subsystem = kobject_name(&kset->kobj);
238 118
239 /* minimal command environment */ 119 /* event environemnt for helper process only */
240 envp [i++] = "HOME=/"; 120 envp[i++] = "HOME=/";
241 envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; 121 envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
242 122
123 /* default keys */
243 scratch = buffer; 124 scratch = buffer;
244
245 envp [i++] = scratch; 125 envp [i++] = scratch;
246 scratch += sprintf(scratch, "ACTION=%s", action_string) + 1; 126 scratch += sprintf(scratch, "ACTION=%s", action_string) + 1;
247
248 kobj_path = kobject_get_path(kobj, GFP_KERNEL);
249 if (!kobj_path)
250 goto exit;
251
252 envp [i++] = scratch; 127 envp [i++] = scratch;
253 scratch += sprintf (scratch, "DEVPATH=%s", kobj_path) + 1; 128 scratch += sprintf (scratch, "DEVPATH=%s", devpath) + 1;
254
255 envp [i++] = scratch; 129 envp [i++] = scratch;
256 scratch += sprintf(scratch, "SUBSYSTEM=%s", name) + 1; 130 scratch += sprintf(scratch, "SUBSYSTEM=%s", subsystem) + 1;
257 131
258 /* reserve space for the sequence, 132 /* just reserve the space, overwrite it after kset call has returned */
259 * put the real one in after the hotplug call */
260 envp[i++] = seq_buff = scratch; 133 envp[i++] = seq_buff = scratch;
261 scratch += strlen("SEQNUM=18446744073709551616") + 1; 134 scratch += strlen("SEQNUM=18446744073709551616") + 1;
262 135
263 if (hotplug_ops->hotplug) { 136 /* let the kset specific function add its stuff */
264 /* have the kset specific function add its stuff */ 137 if (hotplug_ops && hotplug_ops->hotplug) {
265 retval = hotplug_ops->hotplug (kset, kobj, 138 retval = hotplug_ops->hotplug (kset, kobj,
266 &envp[i], NUM_ENVP - i, scratch, 139 &envp[i], NUM_ENVP - i, scratch,
267 BUFFER_SIZE - (scratch - buffer)); 140 BUFFER_SIZE - (scratch - buffer));
@@ -272,27 +145,49 @@ void kobject_hotplug(struct kobject *kobj, enum kobject_action action)
272 } 145 }
273 } 146 }
274 147
148 /* we will send an event, request a new sequence number */
275 spin_lock(&sequence_lock); 149 spin_lock(&sequence_lock);
276 seq = ++hotplug_seqnum; 150 seq = ++hotplug_seqnum;
277 spin_unlock(&sequence_lock); 151 spin_unlock(&sequence_lock);
278 sprintf(seq_buff, "SEQNUM=%llu", (unsigned long long)seq); 152 sprintf(seq_buff, "SEQNUM=%llu", (unsigned long long)seq);
279 153
280 pr_debug ("%s: %s %s seq=%llu %s %s %s %s %s\n", 154 /* send netlink message */
281 __FUNCTION__, argv[0], argv[1], (unsigned long long)seq, 155 if (uevent_sock) {
282 envp[0], envp[1], envp[2], envp[3], envp[4]); 156 struct sk_buff *skb;
283 157 size_t len;
284 send_uevent(action_string, kobj_path, envp, GFP_KERNEL); 158
159 /* allocate message with the maximum possible size */
160 len = strlen(action_string) + strlen(devpath) + 2;
161 skb = alloc_skb(len + BUFFER_SIZE, GFP_KERNEL);
162 if (skb) {
163 /* add header */
164 scratch = skb_put(skb, len);
165 sprintf(scratch, "%s@%s", action_string, devpath);
166
167 /* copy keys to our continuous event payload buffer */
168 for (i = 2; envp[i]; i++) {
169 len = strlen(envp[i]) + 1;
170 scratch = skb_put(skb, len);
171 strcpy(scratch, envp[i]);
172 }
173
174 NETLINK_CB(skb).dst_group = 1;
175 netlink_broadcast(uevent_sock, skb, 0, 1, GFP_KERNEL);
176 }
177 }
285 178
286 if (!hotplug_path[0]) 179 /* call uevent_helper, usually only enabled during early boot */
287 goto exit; 180 if (hotplug_path[0]) {
181 char *argv [3];
288 182
289 retval = call_usermodehelper (argv[0], argv, envp, 0); 183 argv [0] = hotplug_path;
290 if (retval) 184 argv [1] = (char *)subsystem;
291 pr_debug ("%s - call_usermodehelper returned %d\n", 185 argv [2] = NULL;
292 __FUNCTION__, retval); 186 call_usermodehelper (argv[0], argv, envp, 0);
187 }
293 188
294exit: 189exit:
295 kfree(kobj_path); 190 kfree(devpath);
296 kfree(buffer); 191 kfree(buffer);
297 kfree(envp); 192 kfree(envp);
298 return; 193 return;
@@ -350,4 +245,20 @@ int add_hotplug_env_var(char **envp, int num_envp, int *cur_index,
350} 245}
351EXPORT_SYMBOL(add_hotplug_env_var); 246EXPORT_SYMBOL(add_hotplug_env_var);
352 247
248static int __init kobject_uevent_init(void)
249{
250 uevent_sock = netlink_kernel_create(NETLINK_KOBJECT_UEVENT, 1, NULL,
251 THIS_MODULE);
252
253 if (!uevent_sock) {
254 printk(KERN_ERR
255 "kobject_uevent: unable to create netlink socket!\n");
256 return -ENODEV;
257 }
258
259 return 0;
260}
261
262postcore_initcall(kobject_uevent_init);
263
353#endif /* CONFIG_HOTPLUG */ 264#endif /* CONFIG_HOTPLUG */