diff options
-rw-r--r-- | include/linux/kmod.h | 4 | ||||
-rw-r--r-- | kernel/kmod.c | 55 |
2 files changed, 58 insertions, 1 deletions
diff --git a/include/linux/kmod.h b/include/linux/kmod.h index 0db22a1ab474..10f505c8431d 100644 --- a/include/linux/kmod.h +++ b/include/linux/kmod.h | |||
@@ -47,4 +47,8 @@ call_usermodehelper(char *path, char **argv, char **envp, int wait) | |||
47 | 47 | ||
48 | extern void usermodehelper_init(void); | 48 | extern void usermodehelper_init(void); |
49 | 49 | ||
50 | struct file; | ||
51 | extern int call_usermodehelper_pipe(char *path, char *argv[], char *envp[], | ||
52 | struct file **filp); | ||
53 | |||
50 | #endif /* __LINUX_KMOD_H__ */ | 54 | #endif /* __LINUX_KMOD_H__ */ |
diff --git a/kernel/kmod.c b/kernel/kmod.c index 842f8015d7fd..5c63c53014a9 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c | |||
@@ -122,6 +122,7 @@ struct subprocess_info { | |||
122 | struct key *ring; | 122 | struct key *ring; |
123 | int wait; | 123 | int wait; |
124 | int retval; | 124 | int retval; |
125 | struct file *stdin; | ||
125 | }; | 126 | }; |
126 | 127 | ||
127 | /* | 128 | /* |
@@ -145,12 +146,26 @@ static int ____call_usermodehelper(void *data) | |||
145 | 146 | ||
146 | key_put(old_session); | 147 | key_put(old_session); |
147 | 148 | ||
149 | /* Install input pipe when needed */ | ||
150 | if (sub_info->stdin) { | ||
151 | struct files_struct *f = current->files; | ||
152 | struct fdtable *fdt; | ||
153 | /* no races because files should be private here */ | ||
154 | sys_close(0); | ||
155 | fd_install(0, sub_info->stdin); | ||
156 | spin_lock(&f->file_lock); | ||
157 | fdt = files_fdtable(f); | ||
158 | FD_SET(0, fdt->open_fds); | ||
159 | FD_CLR(0, fdt->close_on_exec); | ||
160 | spin_unlock(&f->file_lock); | ||
161 | } | ||
162 | |||
148 | /* We can run anywhere, unlike our parent keventd(). */ | 163 | /* We can run anywhere, unlike our parent keventd(). */ |
149 | set_cpus_allowed(current, CPU_MASK_ALL); | 164 | set_cpus_allowed(current, CPU_MASK_ALL); |
150 | 165 | ||
151 | retval = -EPERM; | 166 | retval = -EPERM; |
152 | if (current->fs->root) | 167 | if (current->fs->root) |
153 | retval = execve(sub_info->path, sub_info->argv,sub_info->envp); | 168 | retval = execve(sub_info->path, sub_info->argv, sub_info->envp); |
154 | 169 | ||
155 | /* Exec failed? */ | 170 | /* Exec failed? */ |
156 | sub_info->retval = retval; | 171 | sub_info->retval = retval; |
@@ -268,6 +283,44 @@ int call_usermodehelper_keys(char *path, char **argv, char **envp, | |||
268 | } | 283 | } |
269 | EXPORT_SYMBOL(call_usermodehelper_keys); | 284 | EXPORT_SYMBOL(call_usermodehelper_keys); |
270 | 285 | ||
286 | int call_usermodehelper_pipe(char *path, char **argv, char **envp, | ||
287 | struct file **filp) | ||
288 | { | ||
289 | DECLARE_COMPLETION(done); | ||
290 | struct subprocess_info sub_info = { | ||
291 | .complete = &done, | ||
292 | .path = path, | ||
293 | .argv = argv, | ||
294 | .envp = envp, | ||
295 | .retval = 0, | ||
296 | }; | ||
297 | struct file *f; | ||
298 | DECLARE_WORK(work, __call_usermodehelper, &sub_info); | ||
299 | |||
300 | if (!khelper_wq) | ||
301 | return -EBUSY; | ||
302 | |||
303 | if (path[0] == '\0') | ||
304 | return 0; | ||
305 | |||
306 | f = create_write_pipe(); | ||
307 | if (!f) | ||
308 | return -ENOMEM; | ||
309 | *filp = f; | ||
310 | |||
311 | f = create_read_pipe(f); | ||
312 | if (!f) { | ||
313 | free_write_pipe(*filp); | ||
314 | return -ENOMEM; | ||
315 | } | ||
316 | sub_info.stdin = f; | ||
317 | |||
318 | queue_work(khelper_wq, &work); | ||
319 | wait_for_completion(&done); | ||
320 | return sub_info.retval; | ||
321 | } | ||
322 | EXPORT_SYMBOL(call_usermodehelper_pipe); | ||
323 | |||
271 | void __init usermodehelper_init(void) | 324 | void __init usermodehelper_init(void) |
272 | { | 325 | { |
273 | khelper_wq = create_singlethread_workqueue("khelper"); | 326 | khelper_wq = create_singlethread_workqueue("khelper"); |