X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=lib%2Fkobject_uevent.c;h=df02814699d747bc484b89cb22100467f82e0a91;hb=544002ef832730b18327000c898a140bfc93efd4;hp=7f20e7b857cb559b7624d89ca4c52bbf86bc1b65;hpb=a05ef8bfdc03c5061f44d91826caa855b0aae481;p=mv-sheeva.git diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 7f20e7b857c..df02814699d 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -25,6 +25,16 @@ #define BUFFER_SIZE 2048 /* buffer for the variables */ #define NUM_ENVP 32 /* number of env pointers */ +/* the strings here must match the enum in include/linux/kobject.h */ +const char *kobject_actions[] = { + "add", + "remove", + "change", + "move", + "online", + "offline", +}; + #if defined(CONFIG_HOTPLUG) u64 uevent_seqnum; char uevent_helper[UEVENT_HELPER_PATH_LEN] = "/sbin/hotplug"; @@ -33,35 +43,18 @@ 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; - } -} - /** - * 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