open_transformer.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  4. */
  5. #include "libbb.h"
  6. #include "bb_archive.h"
  7. void FAST_FUNC init_transformer_aux_data(transformer_aux_data_t *aux)
  8. {
  9. memset(aux, 0, sizeof(*aux));
  10. }
  11. int FAST_FUNC check_signature16(transformer_aux_data_t *aux, int src_fd, unsigned magic16)
  12. {
  13. if (aux && aux->check_signature) {
  14. uint16_t magic2;
  15. if (full_read(src_fd, &magic2, 2) != 2 || magic2 != magic16) {
  16. bb_error_msg("invalid magic");
  17. #if 0 /* possible future extension */
  18. if (aux->check_signature > 1)
  19. xfunc_die();
  20. #endif
  21. return -1;
  22. }
  23. }
  24. return 0;
  25. }
  26. void check_errors_in_children(int signo)
  27. {
  28. int status;
  29. if (!signo) {
  30. /* block waiting for any child */
  31. if (wait(&status) < 0)
  32. //FIXME: check EINTR?
  33. return; /* probably there are no children */
  34. goto check_status;
  35. }
  36. /* Wait for any child without blocking */
  37. for (;;) {
  38. if (wait_any_nohang(&status) < 0)
  39. //FIXME: check EINTR?
  40. /* wait failed?! I'm confused... */
  41. return;
  42. check_status:
  43. /*if (WIFEXITED(status) && WEXITSTATUS(status) == 0)*/
  44. /* On Linux, the above can be checked simply as: */
  45. if (status == 0)
  46. /* this child exited with 0 */
  47. continue;
  48. /* Cannot happen:
  49. if (!WIFSIGNALED(status) && !WIFEXITED(status)) ???;
  50. */
  51. bb_got_signal = 1;
  52. }
  53. }
  54. /* transformer(), more than meets the eye */
  55. #if BB_MMU
  56. void FAST_FUNC open_transformer(int fd,
  57. int check_signature,
  58. IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd)
  59. )
  60. #else
  61. void FAST_FUNC open_transformer(int fd, const char *transform_prog)
  62. #endif
  63. {
  64. struct fd_pair fd_pipe;
  65. int pid;
  66. xpiped_pair(fd_pipe);
  67. pid = BB_MMU ? xfork() : xvfork();
  68. if (pid == 0) {
  69. /* Child */
  70. close(fd_pipe.rd); /* we don't want to read from the parent */
  71. // FIXME: error check?
  72. #if BB_MMU
  73. {
  74. IF_DESKTOP(long long) int r;
  75. transformer_aux_data_t aux;
  76. init_transformer_aux_data(&aux);
  77. aux.check_signature = check_signature;
  78. r = transformer(&aux, fd, fd_pipe.wr);
  79. if (ENABLE_FEATURE_CLEAN_UP) {
  80. close(fd_pipe.wr); /* send EOF */
  81. close(fd);
  82. }
  83. /* must be _exit! bug was actually seen here */
  84. _exit(/*error if:*/ r < 0);
  85. }
  86. #else
  87. {
  88. char *argv[4];
  89. xmove_fd(fd, 0);
  90. xmove_fd(fd_pipe.wr, 1);
  91. argv[0] = (char*)transform_prog;
  92. argv[1] = (char*)"-cf";
  93. argv[2] = (char*)"-";
  94. argv[3] = NULL;
  95. BB_EXECVP(transform_prog, argv);
  96. bb_perror_msg_and_die("can't execute '%s'", transform_prog);
  97. }
  98. #endif
  99. /* notreached */
  100. }
  101. /* parent process */
  102. close(fd_pipe.wr); /* don't want to write to the child */
  103. xmove_fd(fd_pipe.rd, fd);
  104. }
  105. #if SEAMLESS_COMPRESSION
  106. /* Used by e.g. rpm which gives us a fd without filename,
  107. * thus we can't guess the format from filename's extension.
  108. */
  109. int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_detected)
  110. {
  111. union {
  112. uint8_t b[4];
  113. uint16_t b16[2];
  114. uint32_t b32[1];
  115. } magic;
  116. int offset = -2;
  117. USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd);)
  118. USE_FOR_NOMMU(const char *xformer_prog;)
  119. /* .gz and .bz2 both have 2-byte signature, and their
  120. * unpack_XXX_stream wants this header skipped. */
  121. xread(fd, magic.b16, sizeof(magic.b16[0]));
  122. if (ENABLE_FEATURE_SEAMLESS_GZ
  123. && magic.b16[0] == GZIP_MAGIC
  124. ) {
  125. USE_FOR_MMU(xformer = unpack_gz_stream;)
  126. USE_FOR_NOMMU(xformer_prog = "gunzip";)
  127. goto found_magic;
  128. }
  129. if (ENABLE_FEATURE_SEAMLESS_BZ2
  130. && magic.b16[0] == BZIP2_MAGIC
  131. ) {
  132. USE_FOR_MMU(xformer = unpack_bz2_stream;)
  133. USE_FOR_NOMMU(xformer_prog = "bunzip2";)
  134. goto found_magic;
  135. }
  136. if (ENABLE_FEATURE_SEAMLESS_XZ
  137. && magic.b16[0] == XZ_MAGIC1
  138. ) {
  139. offset = -6;
  140. xread(fd, magic.b32, sizeof(magic.b32[0]));
  141. if (magic.b32[0] == XZ_MAGIC2) {
  142. USE_FOR_MMU(xformer = unpack_xz_stream;)
  143. USE_FOR_NOMMU(xformer_prog = "unxz";)
  144. goto found_magic;
  145. }
  146. }
  147. /* No known magic seen */
  148. if (fail_if_not_detected)
  149. bb_error_msg_and_die("no gzip"
  150. IF_FEATURE_SEAMLESS_BZ2("/bzip2")
  151. IF_FEATURE_SEAMLESS_XZ("/xz")
  152. " magic");
  153. xlseek(fd, offset, SEEK_CUR);
  154. return 1;
  155. found_magic:
  156. # if BB_MMU
  157. open_transformer_with_no_sig(fd, xformer);
  158. # else
  159. /* NOMMU version of open_transformer execs
  160. * an external unzipper that wants
  161. * file position at the start of the file */
  162. xlseek(fd, offset, SEEK_CUR);
  163. open_transformer_with_sig(fd, xformer, xformer_prog);
  164. # endif
  165. return 0;
  166. }
  167. int FAST_FUNC open_zipped(const char *fname)
  168. {
  169. int fd;
  170. fd = open(fname, O_RDONLY);
  171. if (fd < 0)
  172. return fd;
  173. if (ENABLE_FEATURE_SEAMLESS_LZMA) {
  174. /* .lzma has no header/signature, can only detect it by extension */
  175. char *sfx = strrchr(fname, '.');
  176. if (sfx && strcmp(sfx+1, "lzma") == 0) {
  177. open_transformer_with_sig(fd, unpack_lzma_stream, "unlzma");
  178. return fd;
  179. }
  180. }
  181. if ((ENABLE_FEATURE_SEAMLESS_GZ)
  182. || (ENABLE_FEATURE_SEAMLESS_BZ2)
  183. || (ENABLE_FEATURE_SEAMLESS_XZ)
  184. ) {
  185. setup_unzip_on_fd(fd, /*fail_if_not_detected:*/ 1);
  186. }
  187. return fd;
  188. }
  189. #endif /* SEAMLESS_COMPRESSION */
  190. void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p)
  191. {
  192. int fd;
  193. char *image;
  194. fd = open_zipped(fname);
  195. if (fd < 0)
  196. return NULL;
  197. image = xmalloc_read(fd, maxsz_p);
  198. if (!image)
  199. bb_perror_msg("read error from '%s'", fname);
  200. close(fd);
  201. return image;
  202. }