Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
| lk_usermodehelper [2019/02/13 21:26] – [Standard calls] rpjday | lk_usermodehelper [2019/02/14 15:18] (current) – [init/do_mounts_initrd.c] rpjday | ||
|---|---|---|---|
| Line 42: | Line 42: | ||
| ==== Standard calls ==== | ==== Standard calls ==== | ||
| + | Common combination: | ||
| < | < | ||
| Line 52: | Line 53: | ||
| extern int | extern int | ||
| call_usermodehelper_exec(struct subprocess_info *info, int wait); | call_usermodehelper_exec(struct subprocess_info *info, int wait); | ||
| + | </ | ||
| + | or combination of the above: | ||
| + | |||
| + | < | ||
| extern int | extern int | ||
| call_usermodehelper(const char *path, char **argv, char **envp, int wait); | call_usermodehelper(const char *path, char **argv, char **envp, int wait); | ||
| Line 62: | Line 67: | ||
| < | < | ||
| - | /** | ||
| - | * call_usermodehelper_setup - prepare to call a usermode helper | ||
| - | * @path: path to usermode executable | ||
| - | * @argv: arg vector for process | ||
| - | * @envp: environment for process | ||
| - | * @gfp_mask: gfp mask for memory allocation | ||
| - | * @cleanup: a cleanup function | ||
| - | * @init: an init function | ||
| - | * @data: arbitrary context sensitive data | ||
| - | * | ||
| - | * Returns either %NULL on allocation failure, or a subprocess_info | ||
| - | * structure. | ||
| - | * exec the process and free the structure. | ||
| - | * | ||
| - | * The init function is used to customize the helper process prior to | ||
| - | * exec. A non-zero return code causes the process to error out, exit, | ||
| - | * and return the failure to the calling process | ||
| - | * | ||
| - | * The cleanup function is just before ethe subprocess_info is about to | ||
| - | * be freed. | ||
| - | * Function must be runnable in either a process context or the | ||
| - | * context in which call_usermodehelper_exec is called. | ||
| - | */ | ||
| struct subprocess_info *call_usermodehelper_setup(const char *path, char **argv, | struct subprocess_info *call_usermodehelper_setup(const char *path, char **argv, | ||
| char **envp, gfp_t gfp_mask, | char **envp, gfp_t gfp_mask, | ||
| Line 171: | Line 153: | ||
| helper_unlock(); | helper_unlock(); | ||
| return retval; | return retval; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== call_usermodehelper() ==== | ||
| + | |||
| + | Combination of the above two: | ||
| + | |||
| + | < | ||
| + | int call_usermodehelper(const char *path, char **argv, char **envp, int wait) | ||
| + | { | ||
| + | struct subprocess_info *info; | ||
| + | gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL; | ||
| + | |||
| + | info = call_usermodehelper_setup(path, | ||
| + | NULL, NULL, NULL); | ||
| + | if (info == NULL) | ||
| + | return -ENOMEM; | ||
| + | |||
| + | return call_usermodehelper_exec(info, | ||
| } | } | ||
| </ | </ | ||
| Line 222: | Line 223: | ||
| sub_info-> | sub_info-> | ||
| #endif | #endif | ||
| + | </ | ||
| + | |||
| + | ===== Examples ===== | ||
| + | |||
| + | ==== kernel/ | ||
| + | |||
| + | < | ||
| + | static int call_modprobe(char *module_name, | ||
| + | { | ||
| + | struct subprocess_info *info; | ||
| + | static char *envp[] = { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | NULL | ||
| + | }; | ||
| + | |||
| + | char **argv = kmalloc(sizeof(char *[5]), GFP_KERNEL); | ||
| + | if (!argv) | ||
| + | goto out; | ||
| + | |||
| + | module_name = kstrdup(module_name, | ||
| + | if (!module_name) | ||
| + | goto free_argv; | ||
| + | |||
| + | argv[0] = modprobe_path; | ||
| + | argv[1] = " | ||
| + | argv[2] = " | ||
| + | argv[3] = module_name; | ||
| + | argv[4] = NULL; | ||
| + | |||
| + | info = call_usermodehelper_setup(modprobe_path, | ||
| + | NULL, free_modprobe_argv, | ||
| + | if (!info) | ||
| + | goto free_module_name; | ||
| + | |||
| + | return call_usermodehelper_exec(info, | ||
| + | |||
| + | free_module_name: | ||
| + | kfree(module_name); | ||
| + | free_argv: | ||
| + | kfree(argv); | ||
| + | out: | ||
| + | return -ENOMEM; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== drivers/ | ||
| + | |||
| + | < | ||
| + | static char v86d_path[PATH_MAX] = "/ | ||
| + | |||
| + | ... | ||
| + | |||
| + | static int uvesafb_helper_start(void) | ||
| + | { | ||
| + | char *envp[] = { | ||
| + | " | ||
| + | " | ||
| + | NULL, | ||
| + | }; | ||
| + | |||
| + | char *argv[] = { | ||
| + | v86d_path, | ||
| + | NULL, | ||
| + | }; | ||
| + | |||
| + | return call_usermodehelper(v86d_path, | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== drivers/ | ||
| + | |||
| + | < | ||
| + | static int wf_critical_overtemp(void) | ||
| + | { | ||
| + | static char const critical_overtemp_path[] = "/ | ||
| + | char *argv[] = { (char *)critical_overtemp_path, | ||
| + | static char *envp[] = { " | ||
| + | " | ||
| + | " | ||
| + | NULL }; | ||
| + | |||
| + | return call_usermodehelper(critical_overtemp_path, | ||
| + | argv, envp, UMH_WAIT_EXEC); | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== init/ | ||
| + | |||
| + | < | ||
| + | static void __init handle_initrd(void) | ||
| + | { | ||
| + | struct subprocess_info *info; | ||
| + | static char *argv[] = { " | ||
| + | extern char *envp_init[]; | ||
| + | int error; | ||
| + | |||
| + | real_root_dev = new_encode_dev(ROOT_DEV); | ||
| + | create_dev("/ | ||
| + | /* mount initrd on rootfs' | ||
| + | mount_block_root("/ | ||
| + | ksys_mkdir("/ | ||
| + | ksys_chdir("/ | ||
| + | |||
| + | /* | ||
| + | * In case that a resume from disk is carried out by linuxrc or one of | ||
| + | * its children, we need to tell the freezer not to wait for us. | ||
| + | */ | ||
| + | current-> | ||
| + | |||
| + | info = call_usermodehelper_setup("/ | ||
| + | | ||
| + | if (!info) | ||
| + | return; | ||
| + | call_usermodehelper_exec(info, | ||
| + | | ||
| + | ... | ||
| + | </ | ||
| + | |||
| + | ==== kernel/ | ||
| + | |||
| + | < | ||
| + | char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/ | ||
| + | static const char reboot_cmd[] = "/ | ||
| + | |||
| + | static int run_cmd(const char *cmd) | ||
| + | { | ||
| + | char **argv; | ||
| + | static char *envp[] = { | ||
| + | " | ||
| + | " | ||
| + | NULL | ||
| + | }; | ||
| + | int ret; | ||
| + | argv = argv_split(GFP_KERNEL, | ||
| + | if (argv) { | ||
| + | ret = call_usermodehelper(argv[0], | ||
| + | argv_free(argv); | ||
| + | } else { | ||
| + | ret = -ENOMEM; | ||
| + | } | ||
| + | |||
| + | return ret; | ||
| + | } | ||
| </ | </ | ||