[PATCH] Create call_usermodehelper_pipe()
Andi Kleen [Sun, 1 Oct 2006 06:29:27 +0000 (23:29 -0700)]
A new member in the ever growing family of call_usermode* functions is
born.  The new call_usermodehelper_pipe() function allows to pipe data to
the stdin of the called user mode progam and behaves otherwise like the
normal call_usermodehelp() (except that it always waits for the child to
finish)

Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

include/linux/kmod.h
kernel/kmod.c

index 0db22a1..10f505c 100644 (file)
@@ -47,4 +47,8 @@ call_usermodehelper(char *path, char **argv, char **envp, int wait)
 
 extern void usermodehelper_init(void);
 
+struct file;
+extern int call_usermodehelper_pipe(char *path, char *argv[], char *envp[],
+                                   struct file **filp);
+
 #endif /* __LINUX_KMOD_H__ */
index 842f801..5c63c53 100644 (file)
@@ -122,6 +122,7 @@ struct subprocess_info {
        struct key *ring;
        int wait;
        int retval;
+       struct file *stdin;
 };
 
 /*
@@ -145,12 +146,26 @@ static int ____call_usermodehelper(void *data)
 
        key_put(old_session);
 
+       /* Install input pipe when needed */
+       if (sub_info->stdin) {
+               struct files_struct *f = current->files;
+               struct fdtable *fdt;
+               /* no races because files should be private here */
+               sys_close(0);
+               fd_install(0, sub_info->stdin);
+               spin_lock(&f->file_lock);
+               fdt = files_fdtable(f);
+               FD_SET(0, fdt->open_fds);
+               FD_CLR(0, fdt->close_on_exec);
+               spin_unlock(&f->file_lock);
+       }
+
        /* We can run anywhere, unlike our parent keventd(). */
        set_cpus_allowed(current, CPU_MASK_ALL);
 
        retval = -EPERM;
        if (current->fs->root)
-               retval = execve(sub_info->path, sub_info->argv,sub_info->envp);
+               retval = execve(sub_info->path, sub_info->argv, sub_info->envp);
 
        /* Exec failed? */
        sub_info->retval = retval;
@@ -268,6 +283,44 @@ int call_usermodehelper_keys(char *path, char **argv, char **envp,
 }
 EXPORT_SYMBOL(call_usermodehelper_keys);
 
+int call_usermodehelper_pipe(char *path, char **argv, char **envp,
+                            struct file **filp)
+{
+       DECLARE_COMPLETION(done);
+       struct subprocess_info sub_info = {
+               .complete       = &done,
+               .path           = path,
+               .argv           = argv,
+               .envp           = envp,
+               .retval         = 0,
+       };
+       struct file *f;
+       DECLARE_WORK(work, __call_usermodehelper, &sub_info);
+
+       if (!khelper_wq)
+               return -EBUSY;
+
+       if (path[0] == '\0')
+               return 0;
+
+       f = create_write_pipe();
+       if (!f)
+               return -ENOMEM;
+       *filp = f;
+
+       f = create_read_pipe(f);
+       if (!f) {
+               free_write_pipe(*filp);
+               return -ENOMEM;
+       }
+       sub_info.stdin = f;
+
+       queue_work(khelper_wq, &work);
+       wait_for_completion(&done);
+       return sub_info.retval;
+}
+EXPORT_SYMBOL(call_usermodehelper_pipe);
+
 void __init usermodehelper_init(void)
 {
        khelper_wq = create_singlethread_workqueue("khelper");