1/* 2 * Common modutils related functions for busybox 3 * 4 * Copyright (C) 2008 by Timo Teras <timo.teras@iki.fi> 5 * 6 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 7 */ 8#include "modutils.h" 9 10#ifdef __UCLIBC__ 11extern int init_module(void *module, unsigned long len, const char *options); 12extern int delete_module(const char *module, unsigned int flags); 13#else 14# include <sys/syscall.h> 15# define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts) 16# define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags) 17#endif 18 19void FAST_FUNC replace(char *s, char what, char with) 20{ 21 while (*s) { 22 if (what == *s) 23 *s = with; 24 ++s; 25 } 26} 27 28char* FAST_FUNC replace_underscores(char *s) 29{ 30 replace(s, '-', '_'); 31 return s; 32} 33 34int FAST_FUNC string_to_llist(char *string, llist_t **llist, const char *delim) 35{ 36 char *tok; 37 int len = 0; 38 39 while ((tok = strsep(&string, delim)) != NULL) { 40 if (tok[0] == '\0') 41 continue; 42 llist_add_to_end(llist, xstrdup(tok)); 43 len += strlen(tok); 44 } 45 return len; 46} 47 48char* FAST_FUNC filename2modname(const char *filename, char *modname) 49{ 50 int i; 51 char *from; 52 53 if (filename == NULL) 54 return NULL; 55 if (modname == NULL) 56 modname = xmalloc(MODULE_NAME_LEN); 57 from = bb_get_last_path_component_nostrip(filename); 58 for (i = 0; i < (MODULE_NAME_LEN-1) && from[i] != '\0' && from[i] != '.'; i++) 59 modname[i] = (from[i] == '-') ? '_' : from[i]; 60 modname[i] = '\0'; 61 62 return modname; 63} 64 65char* FAST_FUNC parse_cmdline_module_options(char **argv) 66{ 67 char *options; 68 int optlen; 69 70 options = xzalloc(1); 71 optlen = 0; 72 while (*++argv) { 73 options = xrealloc(options, optlen + 2 + strlen(*argv) + 2); 74 /* Older versions were enclosing space-containing *argv in "", 75 * but both modprobe and insmod from module-init-tools 3.11.1 76 * don't do this anymore. (As to extra trailing space, 77 * insmod adds it but modprobe does not. We do in both cases) 78 */ 79 optlen += sprintf(options + optlen, "%s ", *argv); 80 } 81 return options; 82} 83 84#if ENABLE_FEATURE_INSMOD_TRY_MMAP 85void* FAST_FUNC try_to_mmap_module(const char *filename, size_t *image_size_p) 86{ 87 /* We have user reports of failure to load 3MB module 88 * on a 16MB RAM machine. Apparently even a transient 89 * memory spike to 6MB during module load 90 * is too big for that system. */ 91 void *image; 92 struct stat st; 93 int fd; 94 95 fd = xopen(filename, O_RDONLY); 96 fstat(fd, &st); 97 image = NULL; 98 /* st.st_size is off_t, we can't just pass it to mmap */ 99 if (st.st_size <= *image_size_p) { 100 size_t image_size = st.st_size; 101 image = mmap(NULL, image_size, PROT_READ, MAP_PRIVATE, fd, 0); 102 if (image == MAP_FAILED) { 103 image = NULL; 104 } else if (*(uint32_t*)image != SWAP_BE32(0x7f454C46)) { 105 /* No ELF signature. Compressed module? */ 106 munmap(image, image_size); 107 image = NULL; 108 } else { 109 /* Success. Report the size */ 110 *image_size_p = image_size; 111 } 112 } 113 close(fd); 114 return image; 115} 116#endif 117 118/* Return: 119 * 0 on success, 120 * -errno on open/read error, 121 * errno on init_module() error 122 */ 123int FAST_FUNC bb_init_module(const char *filename, const char *options) 124{ 125 size_t image_size; 126 char *image; 127 int rc; 128 bool mmaped; 129 130 if (!options) 131 options = ""; 132 133//TODO: audit bb_init_module_24 to match error code convention 134#if ENABLE_FEATURE_2_4_MODULES 135 if (get_linux_version_code() < KERNEL_VERSION(2,6,0)) 136 return bb_init_module_24(filename, options); 137#endif 138 139 image_size = INT_MAX - 4095; 140 mmaped = 0; 141 image = try_to_mmap_module(filename, &image_size); 142 if (image) { 143 mmaped = 1; 144 } else { 145 errno = ENOMEM; /* may be changed by e.g. open errors below */ 146 image = xmalloc_open_zipped_read_close(filename, &image_size); 147 if (!image) 148 return -errno; 149 } 150 151 errno = 0; 152 init_module(image, image_size, options); 153 rc = errno; 154 if (mmaped) 155 munmap(image, image_size); 156 else 157 free(image); 158 return rc; 159} 160 161int FAST_FUNC bb_delete_module(const char *module, unsigned int flags) 162{ 163 errno = 0; 164 delete_module(module, flags); 165 return errno; 166} 167 168const char* FAST_FUNC moderror(int err) 169{ 170 switch (err) { 171 case -1: /* btw: it's -EPERM */ 172 return "no such module"; 173 case ENOEXEC: 174 return "invalid module format"; 175 case ENOENT: 176 return "unknown symbol in module, or unknown parameter"; 177 case ESRCH: 178 return "module has wrong symbol version"; 179 case ENOSYS: 180 return "kernel does not support requested operation"; 181 } 182 if (err < 0) /* should always be */ 183 err = -err; 184 return strerror(err); 185} 186