9 |
|
|
10 |
#include "libbb.h" |
#include "libbb.h" |
11 |
|
|
12 |
ssize_t safe_read(int fd, void *buf, size_t count) |
#define ZIPPED (ENABLE_FEATURE_SEAMLESS_LZMA \ |
13 |
|
|| ENABLE_FEATURE_SEAMLESS_BZ2 \ |
14 |
|
|| ENABLE_FEATURE_SEAMLESS_GZ \ |
15 |
|
/* || ENABLE_FEATURE_SEAMLESS_Z */ \ |
16 |
|
) |
17 |
|
|
18 |
|
#if ZIPPED |
19 |
|
#include "unarchive.h" |
20 |
|
#endif |
21 |
|
|
22 |
|
ssize_t FAST_FUNC safe_read(int fd, void *buf, size_t count) |
23 |
{ |
{ |
24 |
ssize_t n; |
ssize_t n; |
25 |
|
|
30 |
return n; |
return n; |
31 |
} |
} |
32 |
|
|
33 |
|
/* Suppose that you are a shell. You start child processes. |
34 |
|
* They work and eventually exit. You want to get user input. |
35 |
|
* You read stdin. But what happens if last child switched |
36 |
|
* its stdin into O_NONBLOCK mode? |
37 |
|
* |
38 |
|
* *** SURPRISE! It will affect the parent too! *** |
39 |
|
* *** BIG SURPRISE! It stays even after child exits! *** |
40 |
|
* |
41 |
|
* This is a design bug in UNIX API. |
42 |
|
* fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) | O_NONBLOCK); |
43 |
|
* will set nonblocking mode not only on _your_ stdin, but |
44 |
|
* also on stdin of your parent, etc. |
45 |
|
* |
46 |
|
* In general, |
47 |
|
* fd2 = dup(fd1); |
48 |
|
* fcntl(fd2, F_SETFL, fcntl(fd2, F_GETFL, 0) | O_NONBLOCK); |
49 |
|
* sets both fd1 and fd2 to O_NONBLOCK. This includes cases |
50 |
|
* where duping is done implicitly by fork() etc. |
51 |
|
* |
52 |
|
* We need |
53 |
|
* fcntl(fd2, F_SETFD, fcntl(fd2, F_GETFD, 0) | O_NONBLOCK); |
54 |
|
* (note SETFD, not SETFL!) but such thing doesn't exist. |
55 |
|
* |
56 |
|
* Alternatively, we need nonblocking_read(fd, ...) which doesn't |
57 |
|
* require O_NONBLOCK dance at all. Actually, it exists: |
58 |
|
* n = recv(fd, buf, len, MSG_DONTWAIT); |
59 |
|
* "MSG_DONTWAIT: |
60 |
|
* Enables non-blocking operation; if the operation |
61 |
|
* would block, EAGAIN is returned." |
62 |
|
* but recv() works only for sockets! |
63 |
|
* |
64 |
|
* So far I don't see any good solution, I can only propose |
65 |
|
* that affected readers should be careful and use this routine, |
66 |
|
* which detects EAGAIN and uses poll() to wait on the fd. |
67 |
|
* Thankfully, poll() doesn't care about O_NONBLOCK flag. |
68 |
|
*/ |
69 |
|
ssize_t FAST_FUNC nonblock_safe_read(int fd, void *buf, size_t count) |
70 |
|
{ |
71 |
|
struct pollfd pfd[1]; |
72 |
|
ssize_t n; |
73 |
|
|
74 |
|
while (1) { |
75 |
|
n = safe_read(fd, buf, count); |
76 |
|
if (n >= 0 || errno != EAGAIN) |
77 |
|
return n; |
78 |
|
/* fd is in O_NONBLOCK mode. Wait using poll and repeat */ |
79 |
|
pfd[0].fd = fd; |
80 |
|
pfd[0].events = POLLIN; |
81 |
|
safe_poll(pfd, 1, -1); |
82 |
|
} |
83 |
|
} |
84 |
|
|
85 |
/* |
/* |
86 |
* Read all of the supplied buffer from a file. |
* Read all of the supplied buffer from a file. |
87 |
* This does multiple reads as necessary. |
* This does multiple reads as necessary. |
88 |
* Returns the amount read, or -1 on an error. |
* Returns the amount read, or -1 on an error. |
89 |
* A short read is returned on an end of file. |
* A short read is returned on an end of file. |
90 |
*/ |
*/ |
91 |
ssize_t full_read(int fd, void *buf, size_t len) |
ssize_t FAST_FUNC full_read(int fd, void *buf, size_t len) |
92 |
{ |
{ |
93 |
ssize_t cc; |
ssize_t cc; |
94 |
ssize_t total; |
ssize_t total; |
98 |
while (len) { |
while (len) { |
99 |
cc = safe_read(fd, buf, len); |
cc = safe_read(fd, buf, len); |
100 |
|
|
101 |
if (cc < 0) |
if (cc < 0) { |
102 |
return cc; /* read() returns -1 on failure. */ |
if (total) { |
103 |
|
/* we already have some! */ |
104 |
|
/* user can do another read to know the error code */ |
105 |
|
return total; |
106 |
|
} |
107 |
|
return cc; /* read() returns -1 on failure. */ |
108 |
|
} |
109 |
if (cc == 0) |
if (cc == 0) |
110 |
break; |
break; |
|
|
|
111 |
buf = ((char *)buf) + cc; |
buf = ((char *)buf) + cc; |
112 |
total += cc; |
total += cc; |
113 |
len -= cc; |
len -= cc; |
116 |
return total; |
return total; |
117 |
} |
} |
118 |
|
|
119 |
// Die with an error message if we can't read the entire buffer. |
/* Die with an error message if we can't read the entire buffer. */ |
120 |
void xread(int fd, void *buf, size_t count) |
void FAST_FUNC xread(int fd, void *buf, size_t count) |
121 |
{ |
{ |
122 |
if (count) { |
if (count) { |
123 |
ssize_t size = full_read(fd, buf, count); |
ssize_t size = full_read(fd, buf, count); |
124 |
if (size != count) |
if ((size_t)size != count) |
125 |
bb_error_msg_and_die("short read"); |
bb_error_msg_and_die("short read"); |
126 |
} |
} |
127 |
} |
} |
128 |
|
|
129 |
// Die with an error message if we can't read one character. |
/* Die with an error message if we can't read one character. */ |
130 |
unsigned char xread_char(int fd) |
unsigned char FAST_FUNC xread_char(int fd) |
131 |
{ |
{ |
132 |
char tmp; |
char tmp; |
|
|
|
133 |
xread(fd, &tmp, 1); |
xread(fd, &tmp, 1); |
|
|
|
134 |
return tmp; |
return tmp; |
135 |
} |
} |
136 |
|
|
137 |
// Read one line a-la fgets. Works only on seekable streams |
// Reads one line a-la fgets (but doesn't save terminating '\n'). |
138 |
char *reads(int fd, char *buffer, size_t size) |
// Reads byte-by-byte. Useful when it is important to not read ahead. |
139 |
|
// Bytes are appended to pfx (which must be malloced, or NULL). |
140 |
|
char* FAST_FUNC xmalloc_reads(int fd, char *buf, size_t *maxsz_p) |
141 |
{ |
{ |
142 |
char *p; |
char *p; |
143 |
|
size_t sz = buf ? strlen(buf) : 0; |
144 |
|
size_t maxsz = maxsz_p ? *maxsz_p : MAXINT(size_t); |
145 |
|
|
146 |
if (size < 2) |
goto jump_in; |
147 |
return NULL; |
while (sz < maxsz) { |
148 |
size = full_read(fd, buffer, size-1); |
if ((size_t)(p - buf) == sz) { |
149 |
if ((ssize_t)size <= 0) |
jump_in: |
150 |
return NULL; |
buf = xrealloc(buf, sz + 128); |
151 |
|
p = buf + sz; |
152 |
buffer[size] = '\0'; |
sz += 128; |
153 |
p = strchr(buffer, '\n'); |
} |
154 |
if (p) { |
/* nonblock_safe_read() because we are used by e.g. shells */ |
155 |
off_t offset; |
if (nonblock_safe_read(fd, p, 1) != 1) { /* EOF/error */ |
156 |
*p++ = '\0'; |
if (p == buf) { /* we read nothing */ |
157 |
// avoid incorrect (unsigned) widening |
free(buf); |
158 |
offset = (off_t)(p-buffer) - (off_t)size; |
return NULL; |
159 |
// set fd position right after '\n' |
} |
160 |
if (offset && lseek(fd, offset, SEEK_CUR) == (off_t)-1) |
break; |
161 |
return NULL; |
} |
162 |
|
if (*p == '\n') |
163 |
|
break; |
164 |
|
p++; |
165 |
} |
} |
166 |
return buffer; |
*p = '\0'; |
167 |
|
if (maxsz_p) |
168 |
|
*maxsz_p = p - buf; |
169 |
|
p++; |
170 |
|
return xrealloc(buf, p - buf); |
171 |
} |
} |
172 |
|
|
173 |
ssize_t read_close(int fd, void *buf, size_t size) |
ssize_t FAST_FUNC read_close(int fd, void *buf, size_t size) |
174 |
{ |
{ |
175 |
int e; |
/*int e;*/ |
176 |
size = full_read(fd, buf, size); |
size = full_read(fd, buf, size); |
177 |
e = errno; |
/*e = errno;*/ |
178 |
close(fd); |
close(fd); |
179 |
errno = e; |
/*errno = e;*/ |
180 |
return size; |
return size; |
181 |
} |
} |
182 |
|
|
183 |
ssize_t open_read_close(const char *filename, void *buf, size_t size) |
ssize_t FAST_FUNC open_read_close(const char *filename, void *buf, size_t size) |
184 |
{ |
{ |
185 |
int fd = open(filename, O_RDONLY); |
int fd = open(filename, O_RDONLY); |
186 |
if (fd < 0) |
if (fd < 0) |
188 |
return read_close(fd, buf, size); |
return read_close(fd, buf, size); |
189 |
} |
} |
190 |
|
|
191 |
void *xmalloc_open_read_close(const char *filename, size_t *sizep) |
|
192 |
|
// Read (potentially big) files in one go. File size is estimated |
193 |
|
// by stat. Extra '\0' byte is appended. |
194 |
|
void* FAST_FUNC xmalloc_read(int fd, size_t *maxsz_p) |
195 |
|
{ |
196 |
|
char *buf; |
197 |
|
size_t size, rd_size, total; |
198 |
|
size_t to_read; |
199 |
|
struct stat st; |
200 |
|
|
201 |
|
to_read = maxsz_p ? *maxsz_p : MAXINT(ssize_t); /* max to read */ |
202 |
|
|
203 |
|
/* Estimate file size */ |
204 |
|
st.st_size = 0; /* in case fstat fails, assume 0 */ |
205 |
|
fstat(fd, &st); |
206 |
|
/* /proc/N/stat files report st_size 0 */ |
207 |
|
/* In order to make such files readable, we add small const */ |
208 |
|
size = (st.st_size | 0x3ff) + 1; |
209 |
|
|
210 |
|
total = 0; |
211 |
|
buf = NULL; |
212 |
|
while (1) { |
213 |
|
if (to_read < size) |
214 |
|
size = to_read; |
215 |
|
buf = xrealloc(buf, total + size + 1); |
216 |
|
rd_size = full_read(fd, buf + total, size); |
217 |
|
if ((ssize_t)rd_size == (ssize_t)(-1)) { /* error */ |
218 |
|
free(buf); |
219 |
|
return NULL; |
220 |
|
} |
221 |
|
total += rd_size; |
222 |
|
if (rd_size < size) /* EOF */ |
223 |
|
break; |
224 |
|
if (to_read <= rd_size) |
225 |
|
break; |
226 |
|
to_read -= rd_size; |
227 |
|
/* grow by 1/8, but in [1k..64k] bounds */ |
228 |
|
size = ((total / 8) | 0x3ff) + 1; |
229 |
|
if (size > 64*1024) |
230 |
|
size = 64*1024; |
231 |
|
} |
232 |
|
xrealloc(buf, total + 1); |
233 |
|
buf[total] = '\0'; |
234 |
|
|
235 |
|
if (maxsz_p) |
236 |
|
*maxsz_p = total; |
237 |
|
return buf; |
238 |
|
} |
239 |
|
|
240 |
|
#ifdef USING_LSEEK_TO_GET_SIZE |
241 |
|
/* Alternatively, file size can be obtained by lseek to the end. |
242 |
|
* The code is slightly bigger. Retained in case fstat approach |
243 |
|
* will not work for some weird cases (/proc, block devices, etc). |
244 |
|
* (NB: lseek also can fail to work for some weird files) */ |
245 |
|
|
246 |
|
// Read (potentially big) files in one go. File size is estimated by |
247 |
|
// lseek to end. |
248 |
|
void* FAST_FUNC xmalloc_open_read_close(const char *filename, size_t *maxsz_p) |
249 |
{ |
{ |
250 |
char *buf; |
char *buf; |
251 |
size_t size = sizep ? *sizep : INT_MAX; |
size_t size; |
252 |
int fd = xopen(filename, O_RDONLY); |
int fd; |
253 |
|
off_t len; |
254 |
|
|
255 |
|
fd = open(filename, O_RDONLY); |
256 |
|
if (fd < 0) |
257 |
|
return NULL; |
258 |
|
|
259 |
/* /proc/N/stat files report len 0 here */ |
/* /proc/N/stat files report len 0 here */ |
260 |
/* In order to make such files readable, we add small const */ |
/* In order to make such files readable, we add small const */ |
261 |
off_t len = xlseek(fd, 0, SEEK_END) + 256; |
size = 0x3ff; /* read only 1k on unseekable files */ |
262 |
xlseek(fd, 0, SEEK_SET); |
len = lseek(fd, 0, SEEK_END) | 0x3ff; /* + up to 1k */ |
263 |
|
if (len != (off_t)-1) { |
264 |
|
xlseek(fd, 0, SEEK_SET); |
265 |
|
size = maxsz_p ? *maxsz_p : INT_MAX; |
266 |
|
if (len < size) |
267 |
|
size = len; |
268 |
|
} |
269 |
|
|
|
if (len > size) |
|
|
bb_error_msg_and_die("file '%s' is too big", filename); |
|
|
size = len; |
|
270 |
buf = xmalloc(size + 1); |
buf = xmalloc(size + 1); |
271 |
size = read_close(fd, buf, size); |
size = read_close(fd, buf, size); |
272 |
if ((ssize_t)size < 0) |
if ((ssize_t)size < 0) { |
273 |
bb_perror_msg_and_die("'%s'", filename); |
free(buf); |
274 |
|
return NULL; |
275 |
|
} |
276 |
xrealloc(buf, size + 1); |
xrealloc(buf, size + 1); |
277 |
buf[size] = '\0'; |
buf[size] = '\0'; |
278 |
if (sizep) *sizep = size; |
|
279 |
|
if (maxsz_p) |
280 |
|
*maxsz_p = size; |
281 |
|
return buf; |
282 |
|
} |
283 |
|
#endif |
284 |
|
|
285 |
|
// Read (potentially big) files in one go. File size is estimated |
286 |
|
// by stat. |
287 |
|
void* FAST_FUNC xmalloc_open_read_close(const char *filename, size_t *maxsz_p) |
288 |
|
{ |
289 |
|
char *buf; |
290 |
|
int fd; |
291 |
|
|
292 |
|
fd = open(filename, O_RDONLY); |
293 |
|
if (fd < 0) |
294 |
|
return NULL; |
295 |
|
|
296 |
|
buf = xmalloc_read(fd, maxsz_p); |
297 |
|
close(fd); |
298 |
|
return buf; |
299 |
|
} |
300 |
|
|
301 |
|
void* FAST_FUNC xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) |
302 |
|
{ |
303 |
|
void *buf = xmalloc_open_read_close(filename, maxsz_p); |
304 |
|
if (!buf) |
305 |
|
bb_perror_msg_and_die("can't read '%s'", filename); |
306 |
return buf; |
return buf; |
307 |
} |
} |
308 |
|
|
309 |
|
int FAST_FUNC open_zipped(const char *fname) |
310 |
|
{ |
311 |
|
#if !ZIPPED |
312 |
|
return open(fname, O_RDONLY); |
313 |
|
#else |
314 |
|
unsigned char magic[2]; |
315 |
|
char *sfx; |
316 |
|
int fd; |
317 |
|
#if BB_MMU |
318 |
|
USE_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd); |
319 |
|
enum { xformer_prog = 0 }; |
320 |
|
#else |
321 |
|
enum { xformer = 0 }; |
322 |
|
const char *xformer_prog; |
323 |
|
#endif |
324 |
|
|
325 |
|
fd = open(fname, O_RDONLY); |
326 |
|
if (fd < 0) |
327 |
|
return fd; |
328 |
|
|
329 |
|
sfx = strrchr(fname, '.'); |
330 |
|
if (sfx) { |
331 |
|
if (ENABLE_FEATURE_SEAMLESS_LZMA && strcmp(sfx, ".lzma") == 0) |
332 |
|
/* .lzma has no header/signature, just trust it */ |
333 |
|
open_transformer(fd, unpack_lzma_stream, "unlzma"); |
334 |
|
else |
335 |
|
if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, ".gz") == 0) |
336 |
|
|| (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, ".bz2") == 0) |
337 |
|
) { |
338 |
|
/* .gz and .bz2 both have 2-byte signature, and their |
339 |
|
* unpack_XXX_stream want this header skipped. */ |
340 |
|
xread(fd, &magic, 2); |
341 |
|
#if ENABLE_FEATURE_SEAMLESS_GZ |
342 |
|
#if BB_MMU |
343 |
|
xformer = unpack_gz_stream; |
344 |
|
#else |
345 |
|
xformer_prog = "gunzip"; |
346 |
|
#endif |
347 |
|
#endif |
348 |
|
if (!ENABLE_FEATURE_SEAMLESS_GZ |
349 |
|
|| magic[0] != 0x1f || magic[1] != 0x8b |
350 |
|
) { |
351 |
|
if (!ENABLE_FEATURE_SEAMLESS_BZ2 |
352 |
|
|| magic[0] != 'B' || magic[1] != 'Z' |
353 |
|
) { |
354 |
|
bb_error_msg_and_die("no gzip" |
355 |
|
USE_FEATURE_SEAMLESS_BZ2("/bzip2") |
356 |
|
" magic"); |
357 |
|
} |
358 |
|
#if BB_MMU |
359 |
|
xformer = unpack_bz2_stream; |
360 |
|
#else |
361 |
|
xformer_prog = "bunzip2"; |
362 |
|
#endif |
363 |
|
} else { |
364 |
|
#if !BB_MMU |
365 |
|
/* NOMMU version of open_transformer execs |
366 |
|
* an external unzipper that wants |
367 |
|
* file position at the start of the file */ |
368 |
|
xlseek(fd, 0, SEEK_SET); |
369 |
|
#endif |
370 |
|
} |
371 |
|
open_transformer(fd, xformer, xformer_prog); |
372 |
|
} |
373 |
|
} |
374 |
|
|
375 |
|
return fd; |
376 |
|
#endif |
377 |
|
} |
378 |
|
|
379 |
|
void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) |
380 |
|
{ |
381 |
|
int fd; |
382 |
|
char *image; |
383 |
|
|
384 |
|
fd = open_zipped(fname); |
385 |
|
if (fd < 0) |
386 |
|
return NULL; |
387 |
|
|
388 |
|
image = xmalloc_read(fd, maxsz_p); |
389 |
|
if (!image) |
390 |
|
bb_perror_msg("read error from '%s'", fname); |
391 |
|
close(fd); |
392 |
|
|
393 |
|
return image; |
394 |
|
} |