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