The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/lib/kobject_uevent.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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/user_namespace.h>
   24 #include <linux/socket.h>
   25 #include <linux/skbuff.h>
   26 #include <linux/netlink.h>
   27 #include <net/sock.h>
   28 #include <net/net_namespace.h>
   29 
   30 
   31 u64 uevent_seqnum;
   32 char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
   33 #ifdef CONFIG_NET
   34 struct uevent_sock {
   35         struct list_head list;
   36         struct sock *sk;
   37 };
   38 static LIST_HEAD(uevent_sock_list);
   39 #endif
   40 
   41 /* This lock protects uevent_seqnum and uevent_sock_list */
   42 static DEFINE_MUTEX(uevent_sock_mutex);
   43 
   44 /* the strings here must match the enum in include/linux/kobject.h */
   45 static const char *kobject_actions[] = {
   46         [KOBJ_ADD] =            "add",
   47         [KOBJ_REMOVE] =         "remove",
   48         [KOBJ_CHANGE] =         "change",
   49         [KOBJ_MOVE] =           "move",
   50         [KOBJ_ONLINE] =         "online",
   51         [KOBJ_OFFLINE] =        "offline",
   52 };
   53 
   54 /**
   55  * kobject_action_type - translate action string to numeric type
   56  *
   57  * @buf: buffer containing the action string, newline is ignored
   58  * @len: length of buffer
   59  * @type: pointer to the location to store the action type
   60  *
   61  * Returns 0 if the action string was recognized.
   62  */
   63 int kobject_action_type(const char *buf, size_t count,
   64                         enum kobject_action *type)
   65 {
   66         enum kobject_action action;
   67         int ret = -EINVAL;
   68 
   69         if (count && (buf[count-1] == '\n' || buf[count-1] == '\0'))
   70                 count--;
   71 
   72         if (!count)
   73                 goto out;
   74 
   75         for (action = 0; action < ARRAY_SIZE(kobject_actions); action++) {
   76                 if (strncmp(kobject_actions[action], buf, count) != 0)
   77                         continue;
   78                 if (kobject_actions[action][count] != '\0')
   79                         continue;
   80                 *type = action;
   81                 ret = 0;
   82                 break;
   83         }
   84 out:
   85         return ret;
   86 }
   87 
   88 #ifdef CONFIG_NET
   89 static int kobj_bcast_filter(struct sock *dsk, struct sk_buff *skb, void *data)
   90 {
   91         struct kobject *kobj = data;
   92         const struct kobj_ns_type_operations *ops;
   93 
   94         ops = kobj_ns_ops(kobj);
   95         if (ops) {
   96                 const void *sock_ns, *ns;
   97                 ns = kobj->ktype->namespace(kobj);
   98                 sock_ns = ops->netlink_ns(dsk);
   99                 return sock_ns != ns;
  100         }
  101 
  102         return 0;
  103 }
  104 #endif
  105 
  106 static int kobj_usermode_filter(struct kobject *kobj)
  107 {
  108         const struct kobj_ns_type_operations *ops;
  109 
  110         ops = kobj_ns_ops(kobj);
  111         if (ops) {
  112                 const void *init_ns, *ns;
  113                 ns = kobj->ktype->namespace(kobj);
  114                 init_ns = ops->initial_ns();
  115                 return ns != init_ns;
  116         }
  117 
  118         return 0;
  119 }
  120 
  121 /**
  122  * kobject_uevent_env - send an uevent with environmental data
  123  *
  124  * @action: action that is happening
  125  * @kobj: struct kobject that the action is happening to
  126  * @envp_ext: pointer to environmental data
  127  *
  128  * Returns 0 if kobject_uevent_env() is completed with success or the
  129  * corresponding error when it fails.
  130  */
  131 int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
  132                        char *envp_ext[])
  133 {
  134         struct kobj_uevent_env *env;
  135         const char *action_string = kobject_actions[action];
  136         const char *devpath = NULL;
  137         const char *subsystem;
  138         struct kobject *top_kobj;
  139         struct kset *kset;
  140         const struct kset_uevent_ops *uevent_ops;
  141         int i = 0;
  142         int retval = 0;
  143 #ifdef CONFIG_NET
  144         struct uevent_sock *ue_sk;
  145 #endif
  146 
  147         pr_debug("kobject: '%s' (%p): %s\n",
  148                  kobject_name(kobj), kobj, __func__);
  149 
  150         /* search the kset we belong to */
  151         top_kobj = kobj;
  152         while (!top_kobj->kset && top_kobj->parent)
  153                 top_kobj = top_kobj->parent;
  154 
  155         if (!top_kobj->kset) {
  156                 pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
  157                          "without kset!\n", kobject_name(kobj), kobj,
  158                          __func__);
  159                 return -EINVAL;
  160         }
  161 
  162         kset = top_kobj->kset;
  163         uevent_ops = kset->uevent_ops;
  164 
  165         /* skip the event, if uevent_suppress is set*/
  166         if (kobj->uevent_suppress) {
  167                 pr_debug("kobject: '%s' (%p): %s: uevent_suppress "
  168                                  "caused the event to drop!\n",
  169                                  kobject_name(kobj), kobj, __func__);
  170                 return 0;
  171         }
  172         /* skip the event, if the filter returns zero. */
  173         if (uevent_ops && uevent_ops->filter)
  174                 if (!uevent_ops->filter(kset, kobj)) {
  175                         pr_debug("kobject: '%s' (%p): %s: filter function "
  176                                  "caused the event to drop!\n",
  177                                  kobject_name(kobj), kobj, __func__);
  178                         return 0;
  179                 }
  180 
  181         /* originating subsystem */
  182         if (uevent_ops && uevent_ops->name)
  183                 subsystem = uevent_ops->name(kset, kobj);
  184         else
  185                 subsystem = kobject_name(&kset->kobj);
  186         if (!subsystem) {
  187                 pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the "
  188                          "event to drop!\n", kobject_name(kobj), kobj,
  189                          __func__);
  190                 return 0;
  191         }
  192 
  193         /* environment buffer */
  194         env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
  195         if (!env)
  196                 return -ENOMEM;
  197 
  198         /* complete object path */
  199         devpath = kobject_get_path(kobj, GFP_KERNEL);
  200         if (!devpath) {
  201                 retval = -ENOENT;
  202                 goto exit;
  203         }
  204 
  205         /* default keys */
  206         retval = add_uevent_var(env, "ACTION=%s", action_string);
  207         if (retval)
  208                 goto exit;
  209         retval = add_uevent_var(env, "DEVPATH=%s", devpath);
  210         if (retval)
  211                 goto exit;
  212         retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
  213         if (retval)
  214                 goto exit;
  215 
  216         /* keys passed in from the caller */
  217         if (envp_ext) {
  218                 for (i = 0; envp_ext[i]; i++) {
  219                         retval = add_uevent_var(env, "%s", envp_ext[i]);
  220                         if (retval)
  221                                 goto exit;
  222                 }
  223         }
  224 
  225         /* let the kset specific function add its stuff */
  226         if (uevent_ops && uevent_ops->uevent) {
  227                 retval = uevent_ops->uevent(kset, kobj, env);
  228                 if (retval) {
  229                         pr_debug("kobject: '%s' (%p): %s: uevent() returned "
  230                                  "%d\n", kobject_name(kobj), kobj,
  231                                  __func__, retval);
  232                         goto exit;
  233                 }
  234         }
  235 
  236         /*
  237          * Mark "add" and "remove" events in the object to ensure proper
  238          * events to userspace during automatic cleanup. If the object did
  239          * send an "add" event, "remove" will automatically generated by
  240          * the core, if not already done by the caller.
  241          */
  242         if (action == KOBJ_ADD)
  243                 kobj->state_add_uevent_sent = 1;
  244         else if (action == KOBJ_REMOVE)
  245                 kobj->state_remove_uevent_sent = 1;
  246 
  247         mutex_lock(&uevent_sock_mutex);
  248         /* we will send an event, so request a new sequence number */
  249         retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)++uevent_seqnum);
  250         if (retval) {
  251                 mutex_unlock(&uevent_sock_mutex);
  252                 goto exit;
  253         }
  254 
  255 #if defined(CONFIG_NET)
  256         /* send netlink message */
  257         list_for_each_entry(ue_sk, &uevent_sock_list, list) {
  258                 struct sock *uevent_sock = ue_sk->sk;
  259                 struct sk_buff *skb;
  260                 size_t len;
  261 
  262                 if (!netlink_has_listeners(uevent_sock, 1))
  263                         continue;
  264 
  265                 /* allocate message with the maximum possible size */
  266                 len = strlen(action_string) + strlen(devpath) + 2;
  267                 skb = alloc_skb(len + env->buflen, GFP_KERNEL);
  268                 if (skb) {
  269                         char *scratch;
  270 
  271                         /* add header */
  272                         scratch = skb_put(skb, len);
  273                         sprintf(scratch, "%s@%s", action_string, devpath);
  274 
  275                         /* copy keys to our continuous event payload buffer */
  276                         for (i = 0; i < env->envp_idx; i++) {
  277                                 len = strlen(env->envp[i]) + 1;
  278                                 scratch = skb_put(skb, len);
  279                                 strcpy(scratch, env->envp[i]);
  280                         }
  281 
  282                         NETLINK_CB(skb).dst_group = 1;
  283                         retval = netlink_broadcast_filtered(uevent_sock, skb,
  284                                                             0, 1, GFP_KERNEL,
  285                                                             kobj_bcast_filter,
  286                                                             kobj);
  287                         /* ENOBUFS should be handled in userspace */
  288                         if (retval == -ENOBUFS || retval == -ESRCH)
  289                                 retval = 0;
  290                 } else
  291                         retval = -ENOMEM;
  292         }
  293 #endif
  294         mutex_unlock(&uevent_sock_mutex);
  295 
  296         /* call uevent_helper, usually only enabled during early boot */
  297         if (uevent_helper[0] && !kobj_usermode_filter(kobj)) {
  298                 char *argv [3];
  299 
  300                 argv [0] = uevent_helper;
  301                 argv [1] = (char *)subsystem;
  302                 argv [2] = NULL;
  303                 retval = add_uevent_var(env, "HOME=/");
  304                 if (retval)
  305                         goto exit;
  306                 retval = add_uevent_var(env,
  307                                         "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
  308                 if (retval)
  309                         goto exit;
  310 
  311                 retval = call_usermodehelper(argv[0], argv,
  312                                              env->envp, UMH_WAIT_EXEC);
  313         }
  314 
  315 exit:
  316         kfree(devpath);
  317         kfree(env);
  318         return retval;
  319 }
  320 EXPORT_SYMBOL_GPL(kobject_uevent_env);
  321 
  322 /**
  323  * kobject_uevent - notify userspace by sending an uevent
  324  *
  325  * @action: action that is happening
  326  * @kobj: struct kobject that the action is happening to
  327  *
  328  * Returns 0 if kobject_uevent() is completed with success or the
  329  * corresponding error when it fails.
  330  */
  331 int kobject_uevent(struct kobject *kobj, enum kobject_action action)
  332 {
  333         return kobject_uevent_env(kobj, action, NULL);
  334 }
  335 EXPORT_SYMBOL_GPL(kobject_uevent);
  336 
  337 /**
  338  * add_uevent_var - add key value string to the environment buffer
  339  * @env: environment buffer structure
  340  * @format: printf format for the key=value pair
  341  *
  342  * Returns 0 if environment variable was added successfully or -ENOMEM
  343  * if no space was available.
  344  */
  345 int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
  346 {
  347         va_list args;
  348         int len;
  349 
  350         if (env->envp_idx >= ARRAY_SIZE(env->envp)) {
  351                 WARN(1, KERN_ERR "add_uevent_var: too many keys\n");
  352                 return -ENOMEM;
  353         }
  354 
  355         va_start(args, format);
  356         len = vsnprintf(&env->buf[env->buflen],
  357                         sizeof(env->buf) - env->buflen,
  358                         format, args);
  359         va_end(args);
  360 
  361         if (len >= (sizeof(env->buf) - env->buflen)) {
  362                 WARN(1, KERN_ERR "add_uevent_var: buffer size too small\n");
  363                 return -ENOMEM;
  364         }
  365 
  366         env->envp[env->envp_idx++] = &env->buf[env->buflen];
  367         env->buflen += len + 1;
  368         return 0;
  369 }
  370 EXPORT_SYMBOL_GPL(add_uevent_var);
  371 
  372 #if defined(CONFIG_NET)
  373 static int uevent_net_init(struct net *net)
  374 {
  375         struct uevent_sock *ue_sk;
  376         struct netlink_kernel_cfg cfg = {
  377                 .groups = 1,
  378                 .flags  = NL_CFG_F_NONROOT_RECV,
  379         };
  380 
  381         ue_sk = kzalloc(sizeof(*ue_sk), GFP_KERNEL);
  382         if (!ue_sk)
  383                 return -ENOMEM;
  384 
  385         ue_sk->sk = netlink_kernel_create(net, NETLINK_KOBJECT_UEVENT, &cfg);
  386         if (!ue_sk->sk) {
  387                 printk(KERN_ERR
  388                        "kobject_uevent: unable to create netlink socket!\n");
  389                 kfree(ue_sk);
  390                 return -ENODEV;
  391         }
  392         mutex_lock(&uevent_sock_mutex);
  393         list_add_tail(&ue_sk->list, &uevent_sock_list);
  394         mutex_unlock(&uevent_sock_mutex);
  395         return 0;
  396 }
  397 
  398 static void uevent_net_exit(struct net *net)
  399 {
  400         struct uevent_sock *ue_sk;
  401 
  402         mutex_lock(&uevent_sock_mutex);
  403         list_for_each_entry(ue_sk, &uevent_sock_list, list) {
  404                 if (sock_net(ue_sk->sk) == net)
  405                         goto found;
  406         }
  407         mutex_unlock(&uevent_sock_mutex);
  408         return;
  409 
  410 found:
  411         list_del(&ue_sk->list);
  412         mutex_unlock(&uevent_sock_mutex);
  413 
  414         netlink_kernel_release(ue_sk->sk);
  415         kfree(ue_sk);
  416 }
  417 
  418 static struct pernet_operations uevent_net_ops = {
  419         .init   = uevent_net_init,
  420         .exit   = uevent_net_exit,
  421 };
  422 
  423 static int __init kobject_uevent_init(void)
  424 {
  425         return register_pernet_subsys(&uevent_net_ops);
  426 }
  427 
  428 
  429 postcore_initcall(kobject_uevent_init);
  430 #endif

Cache object: 4ebb3f1cfd9eb7b84a2576eaa99c0c0f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.