Index: 2.4.x-xfs/include/linux/kmod.h
===================================================================
--- 2.4.x-xfs.orig/include/linux/kmod.h 2004-11-22 13:47:17.000000000 +1100
+++ 2.4.x-xfs/include/linux/kmod.h 2006-08-15 17:13:48.751783409 +1000
@@ -30,6 +30,7 @@
extern int exec_usermodehelper(char *program_path, char *argv[], char *envp[]);
extern int call_usermodehelper(char *path, char *argv[], char *envp[]);
+extern int __call_usermodehelper(char *path, char *argv[], char *envp[], int wait);
#ifdef CONFIG_HOTPLUG
extern char hotplug_path [];
Index: 2.4.x-xfs/kernel/kmod.c
===================================================================
--- 2.4.x-xfs.orig/kernel/kmod.c 2006-08-15 16:50:47.494091873 +1000
+++ 2.4.x-xfs/kernel/kmod.c 2006-08-15 17:13:48.751783409 +1000
@@ -14,6 +14,9 @@
Unblock all signals when we exec a usermode process.
Shuu Yamaguchi <shuu@wondernetworkresources.com> December 2000
+
+ Add wait flag to call_usermodehelper. Based on a patch from Rusty Russell.
+ Marcel Holtmann <marcel@holtmann.org> Jan 2003
*/
#define __KERNEL_SYSCALLS__
@@ -175,7 +178,7 @@
* If module auto-loading support is disabled then this function
* becomes a no-operation.
*/
-int request_module(const char * module_name)
+int request_module(const char *module_name)
{
pid_t pid;
int waitpid_result;
@@ -273,7 +276,8 @@
char *path;
char **argv;
char **envp;
- pid_t retval;
+ int wait;
+ int retval;
};
/*
@@ -289,26 +293,58 @@
retval = exec_usermodehelper(sub_info->path, sub_info->argv, sub_info->envp);
/* Exec failed? */
- sub_info->retval = (pid_t)retval;
+ sub_info->retval = retval;
do_exit(0);
}
-/*
- * This is run by keventd.
+/*
+ * Keventd can't block, but this (a child) can.
*/
-static void __call_usermodehelper(void *data)
+static int wait_for_helper(void *data)
{
struct subprocess_info *sub_info = data;
pid_t pid;
- /*
- * CLONE_VFORK: wait until the usermode helper has execve'd successfully
- * We need the data structures to stay around until that is done.
- */
- pid = kernel_thread(____call_usermodehelper, sub_info, CLONE_VFORK | SIGCHLD);
+ pid = kernel_thread(____call_usermodehelper, sub_info,
+ CLONE_VFORK | SIGCHLD);
if (pid < 0)
sub_info->retval = pid;
+ else
+ sys_wait4(pid, (unsigned int *)&sub_info->retval, 0, NULL);
+
complete(sub_info->complete);
+ return 0;
+}
+
+/*
+ * This is run by keventd.
+ */
+static void __call_usermodehelper_data(void *data)
+{
+ struct subprocess_info *sub_info = data;
+ pid_t pid;
+
+ /* CLONE_VFORK: wait until the usermode helper has execve'd
+ * successfully We need the data structures to stay around
+ * until that is done. */
+ if (sub_info->wait)
+ pid = kernel_thread(wait_for_helper, sub_info,
+ CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
+ else
+ pid = kernel_thread(____call_usermodehelper, sub_info,
+ CLONE_VFORK | SIGCHLD);
+
+ if (pid < 0) {
+ sub_info->retval = pid;
+ complete(sub_info->complete);
+ } else if (!sub_info->wait)
+ complete(sub_info->complete);
+}
+
+
+int call_usermodehelper(char *path, char *argv[], char *envp[])
+{
+ return __call_usermodehelper(path, argv, envp, 0);
}
/**
@@ -316,15 +352,17 @@
* @path: pathname for the application
* @argv: null-terminated argument list
* @envp: null-terminated environment list
+ * @wait: wait for the application to finish and return status.
*
- * Runs a user-space application. The application is started asynchronously. It
- * runs as a child of keventd. It runs with full root capabilities. keventd silently
- * reaps the child when it exits.
+ * Runs a user-space application. The application is started
+ * asynchronously if wait is not set, and runs as a child of keventd.
+ * (ie. it runs with full root capabilities).
*
- * Must be called from process context. Returns zero on success, else a negative
- * error code.
+ * Must be called from process context. Returns a negative error code
+ * if program was not execed successfully, or (exitcode << 8 + signal)
+ * of the application (0 if wait is not set).
*/
-int call_usermodehelper(char *path, char **argv, char **envp)
+int __call_usermodehelper(char *path, char *argv[], char *envp[], int wait)
{
DECLARE_COMPLETION(work);
struct subprocess_info sub_info = {
@@ -332,10 +370,11 @@
path: path,
argv: argv,
envp: envp,
+ wait: wait,
retval: 0,
};
struct tq_struct tqs = {
- routine: __call_usermodehelper,
+ routine: __call_usermodehelper_data,
data: &sub_info,
};
@@ -344,7 +383,7 @@
if (current_is_keventd()) {
/* We can't wait on keventd! */
- __call_usermodehelper(&sub_info);
+ __call_usermodehelper_data(&sub_info);
} else {
schedule_task(&tqs);
wait_for_completion(&work);
@@ -371,8 +410,8 @@
EXPORT_SYMBOL(exec_usermodehelper);
EXPORT_SYMBOL(call_usermodehelper);
+EXPORT_SYMBOL(__call_usermodehelper);
#ifdef CONFIG_KMOD
EXPORT_SYMBOL(request_module);
#endif
-