]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - lib/kobject_uevent.c
Driver core: accept all valid action-strings in uevent-trigger
[linux-2.6-omap-h63xx.git] / lib / kobject_uevent.c
index 7f20e7b857cb559b7624d89ca4c52bbf86bc1b65..6a80c784a8fb91f43c6d5f3f833df320be3b2cbb 100644 (file)
@@ -33,35 +33,28 @@ static DEFINE_SPINLOCK(sequence_lock);
 static struct sock *uevent_sock;
 #endif
 
-static char *action_to_string(enum kobject_action action)
-{
-       switch (action) {
-       case KOBJ_ADD:
-               return "add";
-       case KOBJ_REMOVE:
-               return "remove";
-       case KOBJ_CHANGE:
-               return "change";
-       case KOBJ_MOUNT:
-               return "mount";
-       case KOBJ_UMOUNT:
-               return "umount";
-       case KOBJ_OFFLINE:
-               return "offline";
-       case KOBJ_ONLINE:
-               return "online";
-       default:
-               return NULL;
-       }
-}
+/* the strings here must match the enum in include/linux/kobject.h */
+const char *kobject_actions[] = {
+       "add",
+       "remove",
+       "change",
+       "move",
+       "online",
+       "offline",
+};
 
 /**
- * kobject_uevent - notify userspace by ending an uevent
+ * kobject_uevent_env - send an uevent with environmental data
  *
- * @action: action that is happening (usually KOBJ_ADD and KOBJ_REMOVE)
+ * @action: action that is happening (usually KOBJ_MOVE)
  * @kobj: struct kobject that the action is happening to
+ * @envp_ext: pointer to environmental data
+ *
+ * Returns 0 if kobject_uevent() is completed with success or the
+ * corresponding error when it fails.
  */
-void kobject_uevent(struct kobject *kobj, enum kobject_action action)
+int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
+                       char *envp_ext[])
 {
        char **envp;
        char *buffer;
@@ -75,52 +68,65 @@ void kobject_uevent(struct kobject *kobj, enum kobject_action action)
        u64 seq;
        char *seq_buff;
        int i = 0;
-       int retval;
+       int retval = 0;
+       int j;
 
        pr_debug("%s\n", __FUNCTION__);
 
-       action_string = action_to_string(action);
-       if (!action_string)
-               return;
+       action_string = kobject_actions[action];
+       if (!action_string) {
+               pr_debug("kobject attempted to send uevent without action_string!\n");
+               return -EINVAL;
+       }
 
        /* search the kset we belong to */
        top_kobj = kobj;
-       if (!top_kobj->kset && top_kobj->parent) {
-               do {
-                       top_kobj = top_kobj->parent;
-               } while (!top_kobj->kset && top_kobj->parent);
+       while (!top_kobj->kset && top_kobj->parent) {
+               top_kobj = top_kobj->parent;
+       }
+       if (!top_kobj->kset) {
+               pr_debug("kobject attempted to send uevent without kset!\n");
+               return -EINVAL;
        }
-       if (!top_kobj->kset)
-               return;
 
        kset = top_kobj->kset;
        uevent_ops = kset->uevent_ops;
 
        /*  skip the event, if the filter returns zero. */
        if (uevent_ops && uevent_ops->filter)
-               if (!uevent_ops->filter(kset, kobj))
-                       return;
+               if (!uevent_ops->filter(kset, kobj)) {
+                       pr_debug("kobject filter function caused the event to drop!\n");
+                       return 0;
+               }
+
+       /* originating subsystem */
+       if (uevent_ops && uevent_ops->name)
+               subsystem = uevent_ops->name(kset, kobj);
+       else
+               subsystem = kobject_name(&kset->kobj);
+       if (!subsystem) {
+               pr_debug("unset subsytem caused the event to drop!\n");
+               return 0;
+       }
 
        /* environment index */
        envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
        if (!envp)
-               return;
+               return -ENOMEM;
 
        /* environment values */
        buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
-       if (!buffer)
+       if (!buffer) {
+               retval = -ENOMEM;
                goto exit;
+       }
 
        /* complete object path */
        devpath = kobject_get_path(kobj, GFP_KERNEL);
-       if (!devpath)
+       if (!devpath) {
+               retval = -ENOENT;
                goto exit;
-
-       /* originating subsystem */
-       if (uevent_ops && uevent_ops->name)
-               subsystem = uevent_ops->name(kset, kobj);
-       else
-               subsystem = kobject_name(&kset->kobj);
+       }
 
        /* event environemnt for helper process only */
        envp[i++] = "HOME=/";
@@ -134,7 +140,8 @@ void kobject_uevent(struct kobject *kobj, enum kobject_action action)
        scratch += sprintf (scratch, "DEVPATH=%s", devpath) + 1;
        envp [i++] = scratch;
        scratch += sprintf(scratch, "SUBSYSTEM=%s", subsystem) + 1;
-
+       for (j = 0; envp_ext && envp_ext[j]; j++)
+               envp[i++] = envp_ext[j];
        /* just reserve the space, overwrite it after kset call has returned */
        envp[i++] = seq_buff = scratch;
        scratch += strlen("SEQNUM=18446744073709551616") + 1;
@@ -191,15 +198,32 @@ void kobject_uevent(struct kobject *kobj, enum kobject_action action)
                argv [0] = uevent_helper;
                argv [1] = (char *)subsystem;
                argv [2] = NULL;
-               call_usermodehelper (argv[0], argv, envp, 0);
+               call_usermodehelper (argv[0], argv, envp, UMH_WAIT_EXEC);
        }
 
 exit:
        kfree(devpath);
        kfree(buffer);
        kfree(envp);
-       return;
+       return retval;
 }
+
+EXPORT_SYMBOL_GPL(kobject_uevent_env);
+
+/**
+ * kobject_uevent - notify userspace by ending an uevent
+ *
+ * @action: action that is happening (usually KOBJ_ADD and KOBJ_REMOVE)
+ * @kobj: struct kobject that the action is happening to
+ *
+ * Returns 0 if kobject_uevent() is completed with success or the
+ * corresponding error when it fails.
+ */
+int kobject_uevent(struct kobject *kobj, enum kobject_action action)
+{
+       return kobject_uevent_env(kobj, action, NULL);
+}
+
 EXPORT_SYMBOL_GPL(kobject_uevent);
 
 /**
@@ -257,7 +281,7 @@ EXPORT_SYMBOL_GPL(add_uevent_var);
 static int __init kobject_uevent_init(void)
 {
        uevent_sock = netlink_kernel_create(NETLINK_KOBJECT_UEVENT, 1, NULL,
-                                           THIS_MODULE);
+                                           NULL, THIS_MODULE);
 
        if (!uevent_sock) {
                printk(KERN_ERR