modutils.c 4.6 KB

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