• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
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/string.h>
19  #include <linux/kobject.h>
20  #include <linux/export.h>
21  #include <linux/kmod.h>
22  #include <linux/slab.h>
23  #include <linux/socket.h>
24  #include <linux/skbuff.h>
25  #include <linux/netlink.h>
26  #include <linux/uuid.h>
27  #include <linux/ctype.h>
28  #include <net/sock.h>
29  #include <net/net_namespace.h>
30  
31  
32  u64 uevent_seqnum;
33  #ifdef CONFIG_UEVENT_HELPER
34  char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
35  #endif
36  #ifdef CONFIG_NET
37  struct uevent_sock {
38  	struct list_head list;
39  	struct sock *sk;
40  };
41  static LIST_HEAD(uevent_sock_list);
42  #endif
43  
44  /* This lock protects uevent_seqnum and uevent_sock_list */
45  static DEFINE_MUTEX(uevent_sock_mutex);
46  
47  /* the strings here must match the enum in include/linux/kobject.h */
48  static const char *kobject_actions[] = {
49  	[KOBJ_ADD] =		"add",
50  	[KOBJ_REMOVE] =		"remove",
51  	[KOBJ_CHANGE] =		"change",
52  	[KOBJ_MOVE] =		"move",
53  	[KOBJ_ONLINE] =		"online",
54  	[KOBJ_OFFLINE] =	"offline",
55  	[KOBJ_BIND] =		"bind",
56  	[KOBJ_UNBIND] =		"unbind",
57  };
58  
kobject_action_type(const char * buf,size_t count,enum kobject_action * type,const char ** args)59  static int kobject_action_type(const char *buf, size_t count,
60  			       enum kobject_action *type,
61  			       const char **args)
62  {
63  	enum kobject_action action;
64  	size_t count_first;
65  	const char *args_start;
66  	int ret = -EINVAL;
67  
68  	if (count && (buf[count-1] == '\n' || buf[count-1] == '\0'))
69  		count--;
70  
71  	if (!count)
72  		goto out;
73  
74  	args_start = strnchr(buf, count, ' ');
75  	if (args_start) {
76  		count_first = args_start - buf;
77  		args_start = args_start + 1;
78  	} else
79  		count_first = count;
80  
81  	for (action = 0; action < ARRAY_SIZE(kobject_actions); action++) {
82  		if (strncmp(kobject_actions[action], buf, count_first) != 0)
83  			continue;
84  		if (kobject_actions[action][count_first] != '\0')
85  			continue;
86  		if (args)
87  			*args = args_start;
88  		*type = action;
89  		ret = 0;
90  		break;
91  	}
92  out:
93  	return ret;
94  }
95  
action_arg_word_end(const char * buf,const char * buf_end,char delim)96  static const char *action_arg_word_end(const char *buf, const char *buf_end,
97  				       char delim)
98  {
99  	const char *next = buf;
100  
101  	while (next <= buf_end && *next != delim)
102  		if (!isalnum(*next++))
103  			return NULL;
104  
105  	if (next == buf)
106  		return NULL;
107  
108  	return next;
109  }
110  
kobject_action_args(const char * buf,size_t count,struct kobj_uevent_env ** ret_env)111  static int kobject_action_args(const char *buf, size_t count,
112  			       struct kobj_uevent_env **ret_env)
113  {
114  	struct kobj_uevent_env *env = NULL;
115  	const char *next, *buf_end, *key;
116  	int key_len;
117  	int r = -EINVAL;
118  
119  	if (count && (buf[count - 1] == '\n' || buf[count - 1] == '\0'))
120  		count--;
121  
122  	if (!count)
123  		return -EINVAL;
124  
125  	env = kzalloc(sizeof(*env), GFP_KERNEL);
126  	if (!env)
127  		return -ENOMEM;
128  
129  	/* first arg is UUID */
130  	if (count < UUID_STRING_LEN || !uuid_is_valid(buf) ||
131  	    add_uevent_var(env, "SYNTH_UUID=%.*s", UUID_STRING_LEN, buf))
132  		goto out;
133  
134  	/*
135  	 * the rest are custom environment variables in KEY=VALUE
136  	 * format with ' ' delimiter between each KEY=VALUE pair
137  	 */
138  	next = buf + UUID_STRING_LEN;
139  	buf_end = buf + count - 1;
140  
141  	while (next <= buf_end) {
142  		if (*next != ' ')
143  			goto out;
144  
145  		/* skip the ' ', key must follow */
146  		key = ++next;
147  		if (key > buf_end)
148  			goto out;
149  
150  		buf = next;
151  		next = action_arg_word_end(buf, buf_end, '=');
152  		if (!next || next > buf_end || *next != '=')
153  			goto out;
154  		key_len = next - buf;
155  
156  		/* skip the '=', value must follow */
157  		if (++next > buf_end)
158  			goto out;
159  
160  		buf = next;
161  		next = action_arg_word_end(buf, buf_end, ' ');
162  		if (!next)
163  			goto out;
164  
165  		if (add_uevent_var(env, "SYNTH_ARG_%.*s=%.*s",
166  				   key_len, key, (int) (next - buf), buf))
167  			goto out;
168  	}
169  
170  	r = 0;
171  out:
172  	if (r)
173  		kfree(env);
174  	else
175  		*ret_env = env;
176  	return r;
177  }
178  
179  /**
180   * kobject_synth_uevent - send synthetic uevent with arguments
181   *
182   * @kobj: struct kobject for which synthetic uevent is to be generated
183   * @buf: buffer containing action type and action args, newline is ignored
184   * @count: length of buffer
185   *
186   * Returns 0 if kobject_synthetic_uevent() is completed with success or the
187   * corresponding error when it fails.
188   */
kobject_synth_uevent(struct kobject * kobj,const char * buf,size_t count)189  int kobject_synth_uevent(struct kobject *kobj, const char *buf, size_t count)
190  {
191  	char *no_uuid_envp[] = { "SYNTH_UUID=0", NULL };
192  	enum kobject_action action;
193  	const char *action_args;
194  	struct kobj_uevent_env *env;
195  	const char *msg = NULL, *devpath;
196  	int r;
197  
198  	r = kobject_action_type(buf, count, &action, &action_args);
199  	if (r) {
200  		msg = "unknown uevent action string\n";
201  		goto out;
202  	}
203  
204  	if (!action_args) {
205  		r = kobject_uevent_env(kobj, action, no_uuid_envp);
206  		goto out;
207  	}
208  
209  	r = kobject_action_args(action_args,
210  				count - (action_args - buf), &env);
211  	if (r == -EINVAL) {
212  		msg = "incorrect uevent action arguments\n";
213  		goto out;
214  	}
215  
216  	if (r)
217  		goto out;
218  
219  	r = kobject_uevent_env(kobj, action, env->envp);
220  	kfree(env);
221  out:
222  	if (r) {
223  		devpath = kobject_get_path(kobj, GFP_KERNEL);
224  		printk(KERN_WARNING "synth uevent: %s: %s",
225  		       devpath ?: "unknown device",
226  		       msg ?: "failed to send uevent");
227  		kfree(devpath);
228  	}
229  	return r;
230  }
231  
232  #ifdef CONFIG_NET
kobj_bcast_filter(struct sock * dsk,struct sk_buff * skb,void * data)233  static int kobj_bcast_filter(struct sock *dsk, struct sk_buff *skb, void *data)
234  {
235  	struct kobject *kobj = data, *ksobj;
236  	const struct kobj_ns_type_operations *ops;
237  
238  	ops = kobj_ns_ops(kobj);
239  	if (!ops && kobj->kset) {
240  		ksobj = &kobj->kset->kobj;
241  		if (ksobj->parent != NULL)
242  			ops = kobj_ns_ops(ksobj->parent);
243  	}
244  
245  	if (ops && ops->netlink_ns && kobj->ktype->namespace) {
246  		const void *sock_ns, *ns;
247  		ns = kobj->ktype->namespace(kobj);
248  		sock_ns = ops->netlink_ns(dsk);
249  		return sock_ns != ns;
250  	}
251  
252  	return 0;
253  }
254  #endif
255  
256  #ifdef CONFIG_UEVENT_HELPER
kobj_usermode_filter(struct kobject * kobj)257  static int kobj_usermode_filter(struct kobject *kobj)
258  {
259  	const struct kobj_ns_type_operations *ops;
260  
261  	ops = kobj_ns_ops(kobj);
262  	if (ops) {
263  		const void *init_ns, *ns;
264  		ns = kobj->ktype->namespace(kobj);
265  		init_ns = ops->initial_ns();
266  		return ns != init_ns;
267  	}
268  
269  	return 0;
270  }
271  
init_uevent_argv(struct kobj_uevent_env * env,const char * subsystem)272  static int init_uevent_argv(struct kobj_uevent_env *env, const char *subsystem)
273  {
274  	int len;
275  
276  	len = strlcpy(&env->buf[env->buflen], subsystem,
277  		      sizeof(env->buf) - env->buflen);
278  	if (len >= (sizeof(env->buf) - env->buflen)) {
279  		WARN(1, KERN_ERR "init_uevent_argv: buffer size too small\n");
280  		return -ENOMEM;
281  	}
282  
283  	env->argv[0] = uevent_helper;
284  	env->argv[1] = &env->buf[env->buflen];
285  	env->argv[2] = NULL;
286  
287  	env->buflen += len + 1;
288  	return 0;
289  }
290  
cleanup_uevent_env(struct subprocess_info * info)291  static void cleanup_uevent_env(struct subprocess_info *info)
292  {
293  	kfree(info->data);
294  }
295  #endif
296  
zap_modalias_env(struct kobj_uevent_env * env)297  static void zap_modalias_env(struct kobj_uevent_env *env)
298  {
299  	static const char modalias_prefix[] = "MODALIAS=";
300  	int i;
301  
302  	for (i = 0; i < env->envp_idx;) {
303  		if (strncmp(env->envp[i], modalias_prefix,
304  			    sizeof(modalias_prefix) - 1)) {
305  			i++;
306  			continue;
307  		}
308  
309  		if (i != env->envp_idx - 1)
310  			memmove(&env->envp[i], &env->envp[i + 1],
311  				sizeof(env->envp[i]) * env->envp_idx - 1);
312  
313  		env->envp_idx--;
314  	}
315  }
316  
317  /**
318   * kobject_uevent_env - send an uevent with environmental data
319   *
320   * @kobj: struct kobject that the action is happening to
321   * @action: action that is happening
322   * @envp_ext: pointer to environmental data
323   *
324   * Returns 0 if kobject_uevent_env() is completed with success or the
325   * corresponding error when it fails.
326   */
kobject_uevent_env(struct kobject * kobj,enum kobject_action action,char * envp_ext[])327  int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
328  		       char *envp_ext[])
329  {
330  	struct kobj_uevent_env *env;
331  	const char *action_string = kobject_actions[action];
332  	const char *devpath = NULL;
333  	const char *subsystem;
334  	struct kobject *top_kobj;
335  	struct kset *kset;
336  	const struct kset_uevent_ops *uevent_ops;
337  	int i = 0;
338  	int retval = 0;
339  #ifdef CONFIG_NET
340  	struct uevent_sock *ue_sk;
341  	u32 dst_nl_group = 0;
342  #endif
343  
344  	/*
345  	 * Mark "remove" event done regardless of result, for some subsystems
346  	 * do not want to re-trigger "remove" event via automatic cleanup.
347  	 */
348  	if (action == KOBJ_REMOVE)
349  		kobj->state_remove_uevent_sent = 1;
350  
351  	pr_debug("kobject: '%s' (%p): %s\n",
352  		 kobject_name(kobj), kobj, __func__);
353  
354  	/* search the kset we belong to */
355  	top_kobj = kobj;
356  	while (!top_kobj->kset && top_kobj->parent)
357  		top_kobj = top_kobj->parent;
358  
359  	if (!top_kobj->kset) {
360  		pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
361  			 "without kset!\n", kobject_name(kobj), kobj,
362  			 __func__);
363  		return -EINVAL;
364  	}
365  
366  	kset = top_kobj->kset;
367  	uevent_ops = kset->uevent_ops;
368  
369  	/* skip the event, if uevent_suppress is set*/
370  	if (kobj->uevent_suppress) {
371  		pr_debug("kobject: '%s' (%p): %s: uevent_suppress "
372  				 "caused the event to drop!\n",
373  				 kobject_name(kobj), kobj, __func__);
374  		return 0;
375  	}
376  	/* skip the event, if the filter returns zero. */
377  	if (uevent_ops && uevent_ops->filter)
378  		if (!uevent_ops->filter(kset, kobj)) {
379  			pr_debug("kobject: '%s' (%p): %s: filter function "
380  				 "caused the event to drop!\n",
381  				 kobject_name(kobj), kobj, __func__);
382  			return 0;
383  		}
384  
385  	/* originating subsystem */
386  	if (uevent_ops && uevent_ops->name)
387  		subsystem = uevent_ops->name(kset, kobj);
388  	else
389  		subsystem = kobject_name(&kset->kobj);
390  	if (!subsystem) {
391  		pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the "
392  			 "event to drop!\n", kobject_name(kobj), kobj,
393  			 __func__);
394  		return 0;
395  	}
396  
397  	/* environment buffer */
398  	env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
399  	if (!env)
400  		return -ENOMEM;
401  
402  	/* complete object path */
403  	devpath = kobject_get_path(kobj, GFP_KERNEL);
404  	if (!devpath) {
405  		retval = -ENOENT;
406  		goto exit;
407  	}
408  
409  	/* default keys */
410  	retval = add_uevent_var(env, "ACTION=%s", action_string);
411  	if (retval)
412  		goto exit;
413  	retval = add_uevent_var(env, "DEVPATH=%s", devpath);
414  	if (retval)
415  		goto exit;
416  	retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
417  	if (retval)
418  		goto exit;
419  
420  	/* keys passed in from the caller */
421  	if (envp_ext) {
422  		for (i = 0; envp_ext[i]; i++) {
423  			retval = add_uevent_var(env, "%s", envp_ext[i]);
424  			if (retval)
425  				goto exit;
426  		}
427  	}
428  
429  	/* let the kset specific function add its stuff */
430  	if (uevent_ops && uevent_ops->uevent) {
431  		retval = uevent_ops->uevent(kset, kobj, env);
432  		if (retval) {
433  			pr_debug("kobject: '%s' (%p): %s: uevent() returned "
434  				 "%d\n", kobject_name(kobj), kobj,
435  				 __func__, retval);
436  			goto exit;
437  		}
438  	}
439  
440  	switch (action) {
441  	case KOBJ_ADD:
442  		/*
443  		 * Mark "add" event so we can make sure we deliver "remove"
444  		 * event to userspace during automatic cleanup. If
445  		 * the object did send an "add" event, "remove" will
446  		 * automatically generated by the core, if not already done
447  		 * by the caller.
448  		 */
449  		kobj->state_add_uevent_sent = 1;
450  		break;
451  
452  	case KOBJ_UNBIND:
453  		zap_modalias_env(env);
454  		break;
455  
456  	default:
457  		break;
458  	}
459  
460  	mutex_lock(&uevent_sock_mutex);
461  	/* we will send an event, so request a new sequence number */
462  	retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)++uevent_seqnum);
463  	if (retval) {
464  		mutex_unlock(&uevent_sock_mutex);
465  		goto exit;
466  	}
467  
468  #if defined(CONFIG_NET)
469  	dst_nl_group =
470  		(strcmp(subsystem, "power_supply") == 0) ? (1u << 16) : 0;
471  
472  	/* send netlink message */
473  	list_for_each_entry(ue_sk, &uevent_sock_list, list) {
474  		struct sock *uevent_sock = ue_sk->sk;
475  		struct sk_buff *skb;
476  		size_t len;
477  
478  		if (!netlink_has_listeners(uevent_sock, 1))
479  			continue;
480  
481  		/* allocate message with the maximum possible size */
482  		len = strlen(action_string) + strlen(devpath) + 2;
483  		skb = alloc_skb(len + env->buflen, GFP_KERNEL);
484  		if (skb) {
485  			char *scratch;
486  
487  			/* add header */
488  			scratch = skb_put(skb, len);
489  			sprintf(scratch, "%s@%s", action_string, devpath);
490  
491  			/* copy keys to our continuous event payload buffer */
492  			for (i = 0; i < env->envp_idx; i++) {
493  				len = strlen(env->envp[i]) + 1;
494  				scratch = skb_put(skb, len);
495  				strcpy(scratch, env->envp[i]);
496  			}
497  
498  			NETLINK_CB(skb).dst_group = 1;
499  			retval = netlink_broadcast_filtered(uevent_sock, skb,
500  				0, 1, GFP_KERNEL,
501  				kobj_bcast_filter,
502  				kobj);
503  			/* ENOBUFS should be handled in userspace */
504  			if (retval == -ENOBUFS || retval == -ESRCH)
505  				retval = 0;
506  		} else
507  			retval = -ENOMEM;
508  	}
509  
510  	if (dst_nl_group) {
511  		/* send netlink message */
512  		list_for_each_entry(ue_sk, &uevent_sock_list, list) {
513  			struct sock *uevent_sock = ue_sk->sk;
514  			struct sk_buff *skb;
515  			size_t len;
516  
517  			if (!netlink_has_listeners(uevent_sock, dst_nl_group))
518  				continue;
519  
520  			/* allocate message with the maximum possible size */
521  			len = strlen(action_string) + strlen(devpath) + 2;
522  			skb = alloc_skb(len + env->buflen, GFP_KERNEL);
523  			if (skb) {
524  				char *scratch;
525  
526  				/* add header */
527  				scratch = skb_put(skb, len);
528  				sprintf(scratch, "%s@%s", action_string,
529  					devpath);
530  
531  				/* copy keys to our continuous event payload
532  				 * buffer
533  				 */
534  				for (i = 0; i < env->envp_idx; i++) {
535  					len = strlen(env->envp[i]) + 1;
536  					scratch = skb_put(skb, len);
537  					strcpy(scratch, env->envp[i]);
538  				}
539  
540  				NETLINK_CB(skb).dst_group = dst_nl_group;
541  				retval = netlink_broadcast_filtered(
542  					uevent_sock, skb,
543  					0, dst_nl_group, GFP_KERNEL,
544  					kobj_bcast_filter,
545  					kobj);
546  				/* ENOBUFS should be handled in userspace */
547  				if (retval == -ENOBUFS || retval == -ESRCH)
548  					retval = 0;
549  			} else
550  				retval = -ENOMEM;
551  		}
552  	}
553  #endif
554  	mutex_unlock(&uevent_sock_mutex);
555  
556  #ifdef CONFIG_UEVENT_HELPER
557  	/* call uevent_helper, usually only enabled during early boot */
558  	if (uevent_helper[0] && !kobj_usermode_filter(kobj)) {
559  		struct subprocess_info *info;
560  
561  		retval = add_uevent_var(env, "HOME=/");
562  		if (retval)
563  			goto exit;
564  		retval = add_uevent_var(env,
565  					"PATH=/sbin:/bin:/usr/sbin:/usr/bin");
566  		if (retval)
567  			goto exit;
568  		retval = init_uevent_argv(env, subsystem);
569  		if (retval)
570  			goto exit;
571  
572  		retval = -ENOMEM;
573  		info = call_usermodehelper_setup(env->argv[0], env->argv,
574  						 env->envp, GFP_KERNEL,
575  						 NULL, cleanup_uevent_env, env);
576  		if (info) {
577  			retval = call_usermodehelper_exec(info, UMH_NO_WAIT);
578  			env = NULL;	/* freed by cleanup_uevent_env */
579  		}
580  	}
581  #endif
582  
583  exit:
584  	kfree(devpath);
585  	kfree(env);
586  	return retval;
587  }
588  EXPORT_SYMBOL_GPL(kobject_uevent_env);
589  
590  /**
591   * kobject_uevent - notify userspace by sending an uevent
592   *
593   * @kobj: struct kobject that the action is happening to
594   * @action: action that is happening
595   *
596   * Returns 0 if kobject_uevent() is completed with success or the
597   * corresponding error when it fails.
598   */
kobject_uevent(struct kobject * kobj,enum kobject_action action)599  int kobject_uevent(struct kobject *kobj, enum kobject_action action)
600  {
601  	return kobject_uevent_env(kobj, action, NULL);
602  }
603  EXPORT_SYMBOL_GPL(kobject_uevent);
604  
605  /**
606   * add_uevent_var - add key value string to the environment buffer
607   * @env: environment buffer structure
608   * @format: printf format for the key=value pair
609   *
610   * Returns 0 if environment variable was added successfully or -ENOMEM
611   * if no space was available.
612   */
add_uevent_var(struct kobj_uevent_env * env,const char * format,...)613  int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
614  {
615  	va_list args;
616  	int len;
617  
618  	if (env->envp_idx >= ARRAY_SIZE(env->envp)) {
619  		WARN(1, KERN_ERR "add_uevent_var: too many keys\n");
620  		return -ENOMEM;
621  	}
622  
623  	va_start(args, format);
624  	len = vsnprintf(&env->buf[env->buflen],
625  			sizeof(env->buf) - env->buflen,
626  			format, args);
627  	va_end(args);
628  
629  	if (len >= (sizeof(env->buf) - env->buflen)) {
630  		WARN(1, KERN_ERR "add_uevent_var: buffer size too small\n");
631  		return -ENOMEM;
632  	}
633  
634  	env->envp[env->envp_idx++] = &env->buf[env->buflen];
635  	env->buflen += len + 1;
636  	return 0;
637  }
638  EXPORT_SYMBOL_GPL(add_uevent_var);
639  
640  #if defined(CONFIG_NET)
uevent_net_init(struct net * net)641  static int uevent_net_init(struct net *net)
642  {
643  	struct uevent_sock *ue_sk;
644  	struct netlink_kernel_cfg cfg = {
645  		.groups	= 1,
646  		.flags	= NL_CFG_F_NONROOT_RECV,
647  	};
648  
649  	ue_sk = kzalloc(sizeof(*ue_sk), GFP_KERNEL);
650  	if (!ue_sk)
651  		return -ENOMEM;
652  
653  	ue_sk->sk = netlink_kernel_create(net, NETLINK_KOBJECT_UEVENT, &cfg);
654  	if (!ue_sk->sk) {
655  		printk(KERN_ERR
656  		       "kobject_uevent: unable to create netlink socket!\n");
657  		kfree(ue_sk);
658  		return -ENODEV;
659  	}
660  	mutex_lock(&uevent_sock_mutex);
661  	list_add_tail(&ue_sk->list, &uevent_sock_list);
662  	mutex_unlock(&uevent_sock_mutex);
663  	return 0;
664  }
665  
uevent_net_exit(struct net * net)666  static void uevent_net_exit(struct net *net)
667  {
668  	struct uevent_sock *ue_sk;
669  
670  	mutex_lock(&uevent_sock_mutex);
671  	list_for_each_entry(ue_sk, &uevent_sock_list, list) {
672  		if (sock_net(ue_sk->sk) == net)
673  			goto found;
674  	}
675  	mutex_unlock(&uevent_sock_mutex);
676  	return;
677  
678  found:
679  	list_del(&ue_sk->list);
680  	mutex_unlock(&uevent_sock_mutex);
681  
682  	netlink_kernel_release(ue_sk->sk);
683  	kfree(ue_sk);
684  }
685  
686  static struct pernet_operations uevent_net_ops = {
687  	.init	= uevent_net_init,
688  	.exit	= uevent_net_exit,
689  };
690  
kobject_uevent_init(void)691  static int __init kobject_uevent_init(void)
692  {
693  	return register_pernet_subsys(&uevent_net_ops);
694  }
695  
696  
697  postcore_initcall(kobject_uevent_init);
698  #endif
699