modutils.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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)
  57. {
  58. char *options;
  59. int optlen;
  60. options = xzalloc(1);
  61. optlen = 0;
  62. while (*++argv) {
  63. options = xrealloc(options, optlen + 2 + strlen(*argv) + 2);
  64. /* Spaces handled by "" pairs, but no way of escaping quotes */
  65. //TODO: module-init-tools version 3.11.1 quotes only value:
  66. //it generates var="val with spaces", not "var=val with spaces"
  67. //(and it won't quote var *name* even if it has spaces)
  68. optlen += sprintf(options + optlen, (strchr(*argv, ' ') ? "\"%s\" " : "%s "), *argv);
  69. }
  70. return options;
  71. }
  72. #if ENABLE_FEATURE_INSMOD_TRY_MMAP
  73. void* FAST_FUNC try_to_mmap_module(const char *filename, size_t *image_size_p)
  74. {
  75. /* We have user reports of failure to load 3MB module
  76. * on a 16MB RAM machine. Apparently even a transient
  77. * memory spike to 6MB during module load
  78. * is too big for that system. */
  79. void *image;
  80. struct stat st;
  81. int fd;
  82. fd = xopen(filename, O_RDONLY);
  83. fstat(fd, &st);
  84. image = NULL;
  85. /* st.st_size is off_t, we can't just pass it to mmap */
  86. if (st.st_size <= *image_size_p) {
  87. size_t image_size = st.st_size;
  88. image = mmap(NULL, image_size, PROT_READ, MAP_PRIVATE, fd, 0);
  89. if (image == MAP_FAILED) {
  90. image = NULL;
  91. } else if (*(uint32_t*)image != SWAP_BE32(0x7f454C46)) {
  92. /* No ELF signature. Compressed module? */
  93. munmap(image, image_size);
  94. image = NULL;
  95. } else {
  96. /* Success. Report the size */
  97. *image_size_p = image_size;
  98. }
  99. }
  100. close(fd);
  101. return image;
  102. }
  103. #endif
  104. /* Return:
  105. * 0 on success,
  106. * -errno on open/read error,
  107. * errno on init_module() error
  108. */
  109. int FAST_FUNC bb_init_module(const char *filename, const char *options)
  110. {
  111. size_t image_size;
  112. char *image;
  113. int rc;
  114. bool mmaped;
  115. if (!options)
  116. options = "";
  117. //TODO: audit bb_init_module_24 to match error code convention
  118. #if ENABLE_FEATURE_2_4_MODULES
  119. if (get_linux_version_code() < KERNEL_VERSION(2,6,0))
  120. return bb_init_module_24(filename, options);
  121. #endif
  122. image_size = INT_MAX - 4095;
  123. mmaped = 0;
  124. image = try_to_mmap_module(filename, &image_size);
  125. if (image) {
  126. mmaped = 1;
  127. } else {
  128. errno = ENOMEM; /* may be changed by e.g. open errors below */
  129. image = xmalloc_open_zipped_read_close(filename, &image_size);
  130. if (!image)
  131. return -errno;
  132. }
  133. errno = 0;
  134. init_module(image, image_size, options);
  135. rc = errno;
  136. if (mmaped)
  137. munmap(image, image_size);
  138. else
  139. free(image);
  140. return rc;
  141. }
  142. int FAST_FUNC bb_delete_module(const char *module, unsigned int flags)
  143. {
  144. errno = 0;
  145. delete_module(module, flags);
  146. return errno;
  147. }
  148. const char* FAST_FUNC moderror(int err)
  149. {
  150. switch (err) {
  151. case -1: /* btw: it's -EPERM */
  152. return "no such module";
  153. case ENOEXEC:
  154. return "invalid module format";
  155. case ENOENT:
  156. return "unknown symbol in module, or unknown parameter";
  157. case ESRCH:
  158. return "module has wrong symbol version";
  159. case ENOSYS:
  160. return "kernel does not support requested operation";
  161. }
  162. if (err < 0) /* should always be */
  163. err = -err;
  164. return strerror(err);
  165. }