modutils.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  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. char local_modname[MODULE_NAME_LEN];
  45. int i;
  46. const char *from;
  47. if (filename == NULL)
  48. return NULL;
  49. if (modname == NULL)
  50. modname = local_modname;
  51. // Disabled since otherwise "modprobe dir/name" would work
  52. // as if it is "modprobe name". It is unclear why
  53. // 'basenamization' was here in the first place.
  54. //from = bb_get_last_path_component_nostrip(filename);
  55. from = filename;
  56. for (i = 0; i < (MODULE_NAME_LEN-1) && from[i] != '\0' && from[i] != '.'; i++)
  57. modname[i] = (from[i] == '-') ? '_' : from[i];
  58. modname[i] = '\0';
  59. if (modname == local_modname)
  60. return xstrdup(modname);
  61. return modname;
  62. }
  63. char* FAST_FUNC parse_cmdline_module_options(char **argv, int quote_spaces)
  64. {
  65. char *options;
  66. int optlen;
  67. options = xzalloc(1);
  68. optlen = 0;
  69. while (*++argv) {
  70. const char *fmt;
  71. const char *var;
  72. const char *val;
  73. var = *argv;
  74. options = xrealloc(options, optlen + 2 + strlen(var) + 2);
  75. fmt = "%.*s%s ";
  76. val = strchrnul(var, '=');
  77. if (quote_spaces) {
  78. /*
  79. * modprobe (module-init-tools version 3.11.1) compat:
  80. * quote only value:
  81. * var="val with spaces", not "var=val with spaces"
  82. * (note: var *name* is not checked for spaces!)
  83. */
  84. if (*val) { /* has var=val format. skip '=' */
  85. val++;
  86. if (strchr(val, ' '))
  87. fmt = "%.*s\"%s\" ";
  88. }
  89. }
  90. optlen += sprintf(options + optlen, fmt, (int)(val - var), var, val);
  91. }
  92. /* Remove trailing space. Disabled */
  93. /* if (optlen != 0) options[optlen-1] = '\0'; */
  94. return options;
  95. }
  96. #if ENABLE_FEATURE_INSMOD_TRY_MMAP
  97. void* FAST_FUNC try_to_mmap_module(const char *filename, size_t *image_size_p)
  98. {
  99. /* We have user reports of failure to load 3MB module
  100. * on a 16MB RAM machine. Apparently even a transient
  101. * memory spike to 6MB during module load
  102. * is too big for that system. */
  103. void *image;
  104. struct stat st;
  105. int fd;
  106. fd = xopen(filename, O_RDONLY);
  107. fstat(fd, &st);
  108. image = NULL;
  109. /* st.st_size is off_t, we can't just pass it to mmap */
  110. if (st.st_size <= *image_size_p) {
  111. size_t image_size = st.st_size;
  112. image = mmap(NULL, image_size, PROT_READ, MAP_PRIVATE, fd, 0);
  113. if (image == MAP_FAILED) {
  114. image = NULL;
  115. } else if (*(uint32_t*)image != SWAP_BE32(0x7f454C46)) {
  116. /* No ELF signature. Compressed module? */
  117. munmap(image, image_size);
  118. image = NULL;
  119. } else {
  120. /* Success. Report the size */
  121. *image_size_p = image_size;
  122. }
  123. }
  124. close(fd);
  125. return image;
  126. }
  127. #endif
  128. /* Return:
  129. * 0 on success,
  130. * -errno on open/read error,
  131. * errno on init_module() error
  132. */
  133. int FAST_FUNC bb_init_module(const char *filename, const char *options)
  134. {
  135. size_t image_size;
  136. char *image;
  137. int rc;
  138. bool mmaped;
  139. if (!options)
  140. options = "";
  141. //TODO: audit bb_init_module_24 to match error code convention
  142. #if ENABLE_FEATURE_2_4_MODULES
  143. if (get_linux_version_code() < KERNEL_VERSION(2,6,0))
  144. return bb_init_module_24(filename, options);
  145. #endif
  146. image_size = INT_MAX - 4095;
  147. mmaped = 0;
  148. image = try_to_mmap_module(filename, &image_size);
  149. if (image) {
  150. mmaped = 1;
  151. } else {
  152. errno = ENOMEM; /* may be changed by e.g. open errors below */
  153. image = xmalloc_open_zipped_read_close(filename, &image_size);
  154. if (!image)
  155. return -errno;
  156. }
  157. errno = 0;
  158. init_module(image, image_size, options);
  159. rc = errno;
  160. if (mmaped)
  161. munmap(image, image_size);
  162. else
  163. free(image);
  164. return rc;
  165. }
  166. int FAST_FUNC bb_delete_module(const char *module, unsigned int flags)
  167. {
  168. errno = 0;
  169. delete_module(module, flags);
  170. return errno;
  171. }
  172. const char* FAST_FUNC moderror(int err)
  173. {
  174. switch (err) {
  175. case -1: /* btw: it's -EPERM */
  176. return "no such module";
  177. case ENOEXEC:
  178. return "invalid module format";
  179. case ENOENT:
  180. return "unknown symbol in module, or unknown parameter";
  181. case ESRCH:
  182. return "module has wrong symbol version";
  183. case ENOSYS:
  184. return "kernel does not support requested operation";
  185. }
  186. if (err < 0) /* should always be */
  187. err = -err;
  188. return strerror(err);
  189. }