blob: 7af8952078fbe1b6c081840d284e860b13d03968 [file] [log] [blame]
Denis Vlasenkoea620772006-10-14 02:23:43 +00001/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
Denis Vlasenkob6052722008-07-10 17:43:01 +000011#if ENABLE_FEATURE_MODPROBE_SMALL_ZIPPED
12#include "unarchive.h"
13#endif
Denis Vlasenkoea620772006-10-14 02:23:43 +000014
Denis Vlasenkodefc1ea2008-06-27 02:52:20 +000015ssize_t FAST_FUNC safe_read(int fd, void *buf, size_t count)
Denis Vlasenkoea620772006-10-14 02:23:43 +000016{
17 ssize_t n;
18
19 do {
20 n = read(fd, buf, count);
21 } while (n < 0 && errno == EINTR);
22
23 return n;
24}
25
Denis Vlasenkoe376d452008-02-20 22:23:24 +000026/* Suppose that you are a shell. You start child processes.
27 * They work and eventually exit. You want to get user input.
28 * You read stdin. But what happens if last child switched
29 * its stdin into O_NONBLOCK mode?
30 *
31 * *** SURPRISE! It will affect the parent too! ***
32 * *** BIG SURPRISE! It stays even after child exits! ***
33 *
34 * This is a design bug in UNIX API.
35 * fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) | O_NONBLOCK);
36 * will set nonblocking mode not only on _your_ stdin, but
37 * also on stdin of your parent, etc.
38 *
39 * In general,
40 * fd2 = dup(fd1);
41 * fcntl(fd2, F_SETFL, fcntl(fd2, F_GETFL, 0) | O_NONBLOCK);
42 * sets both fd1 and fd2 to O_NONBLOCK. This includes cases
43 * where duping is done implicitly by fork() etc.
44 *
45 * We need
46 * fcntl(fd2, F_SETFD, fcntl(fd2, F_GETFD, 0) | O_NONBLOCK);
47 * (note SETFD, not SETFL!) but such thing doesn't exist.
48 *
49 * Alternatively, we need nonblocking_read(fd, ...) which doesn't
50 * require O_NONBLOCK dance at all. Actually, it exists:
51 * n = recv(fd, buf, len, MSG_DONTWAIT);
52 * "MSG_DONTWAIT:
53 * Enables non-blocking operation; if the operation
54 * would block, EAGAIN is returned."
55 * but recv() works only for sockets!
56 *
57 * So far I don't see any good solution, I can only propose
58 * that affected readers should be careful and use this routine,
59 * which detects EAGAIN and uses poll() to wait on the fd.
Denis Vlasenko081efd12008-02-20 22:57:24 +000060 * Thankfully, poll() doesn't care about O_NONBLOCK flag.
Denis Vlasenkoe376d452008-02-20 22:23:24 +000061 */
Denis Vlasenkodefc1ea2008-06-27 02:52:20 +000062ssize_t FAST_FUNC nonblock_safe_read(int fd, void *buf, size_t count)
Denis Vlasenkoe376d452008-02-20 22:23:24 +000063{
64 struct pollfd pfd[1];
65 ssize_t n;
66
67 while (1) {
68 n = safe_read(fd, buf, count);
69 if (n >= 0 || errno != EAGAIN)
70 return n;
71 /* fd is in O_NONBLOCK mode. Wait using poll and repeat */
72 pfd[0].fd = fd;
73 pfd[0].events = POLLIN;
74 safe_poll(pfd, 1, -1);
75 }
76}
77
Denis Vlasenkoea620772006-10-14 02:23:43 +000078/*
79 * Read all of the supplied buffer from a file.
80 * This does multiple reads as necessary.
81 * Returns the amount read, or -1 on an error.
82 * A short read is returned on an end of file.
83 */
Denis Vlasenkodefc1ea2008-06-27 02:52:20 +000084ssize_t FAST_FUNC full_read(int fd, void *buf, size_t len)
Denis Vlasenkoea620772006-10-14 02:23:43 +000085{
86 ssize_t cc;
87 ssize_t total;
88
89 total = 0;
90
91 while (len) {
92 cc = safe_read(fd, buf, len);
93
Denis Vlasenko394eebe2008-02-25 20:30:24 +000094 if (cc < 0) {
95 if (total) {
96 /* we already have some! */
97 /* user can do another read to know the error code */
98 return total;
99 }
100 return cc; /* read() returns -1 on failure. */
101 }
Denis Vlasenkoea620772006-10-14 02:23:43 +0000102 if (cc == 0)
103 break;
Denis Vlasenkoea620772006-10-14 02:23:43 +0000104 buf = ((char *)buf) + cc;
105 total += cc;
106 len -= cc;
107 }
108
109 return total;
110}
111
Denis Vlasenkof62ab2d2008-07-09 09:50:33 +0000112/* Die with an error message if we can't read the entire buffer. */
Denis Vlasenkodefc1ea2008-06-27 02:52:20 +0000113void FAST_FUNC xread(int fd, void *buf, size_t count)
Denis Vlasenkoea620772006-10-14 02:23:43 +0000114{
115 if (count) {
116 ssize_t size = full_read(fd, buf, count);
Denis Vlasenko77ad97f2008-05-13 02:27:31 +0000117 if ((size_t)size != count)
Denis Vlasenkoea620772006-10-14 02:23:43 +0000118 bb_error_msg_and_die("short read");
119 }
120}
121
Denis Vlasenkof62ab2d2008-07-09 09:50:33 +0000122/* Die with an error message if we can't read one character. */
Denis Vlasenkodefc1ea2008-06-27 02:52:20 +0000123unsigned char FAST_FUNC xread_char(int fd)
Denis Vlasenkoea620772006-10-14 02:23:43 +0000124{
125 char tmp;
Denis Vlasenkoea620772006-10-14 02:23:43 +0000126 xread(fd, &tmp, 1);
Denis Vlasenkoea620772006-10-14 02:23:43 +0000127 return tmp;
128}
129
Denis Vlasenkof62ab2d2008-07-09 09:50:33 +0000130/* Read one line a-la fgets. Works only on seekable streams */
Denis Vlasenkodefc1ea2008-06-27 02:52:20 +0000131char* FAST_FUNC reads(int fd, char *buffer, size_t size)
Denis Vlasenkoea620772006-10-14 02:23:43 +0000132{
133 char *p;
134
135 if (size < 2)
136 return NULL;
137 size = full_read(fd, buffer, size-1);
138 if ((ssize_t)size <= 0)
139 return NULL;
140
141 buffer[size] = '\0';
142 p = strchr(buffer, '\n');
143 if (p) {
144 off_t offset;
145 *p++ = '\0';
Denis Vlasenkof62ab2d2008-07-09 09:50:33 +0000146 /* avoid incorrect (unsigned) widening */
Denis Vlasenko8ee649a2008-03-26 20:04:27 +0000147 offset = (off_t)(p - buffer) - (off_t)size;
Denis Vlasenkof62ab2d2008-07-09 09:50:33 +0000148 /* set fd position right after '\n' */
Denis Vlasenkoea620772006-10-14 02:23:43 +0000149 if (offset && lseek(fd, offset, SEEK_CUR) == (off_t)-1)
150 return NULL;
151 }
152 return buffer;
153}
154
Denis Vlasenko8ee649a2008-03-26 20:04:27 +0000155// Reads one line a-la fgets (but doesn't save terminating '\n').
156// Reads byte-by-byte. Useful when it is important to not read ahead.
Denis Vlasenkoe376d452008-02-20 22:23:24 +0000157// Bytes are appended to pfx (which must be malloced, or NULL).
Denis Vlasenkodefc1ea2008-06-27 02:52:20 +0000158char* FAST_FUNC xmalloc_reads(int fd, char *buf, size_t *maxsz_p)
Denis Vlasenkod67cef22007-06-13 06:47:47 +0000159{
160 char *p;
Denis Vlasenko0b6c6a92008-03-24 00:04:42 +0000161 size_t sz = buf ? strlen(buf) : 0;
162 size_t maxsz = maxsz_p ? *maxsz_p : MAXINT(size_t);
Denis Vlasenkod67cef22007-06-13 06:47:47 +0000163
164 goto jump_in;
Denis Vlasenko0b6c6a92008-03-24 00:04:42 +0000165 while (sz < maxsz) {
Denis Vlasenko77ad97f2008-05-13 02:27:31 +0000166 if ((size_t)(p - buf) == sz) {
Denis Vlasenkod67cef22007-06-13 06:47:47 +0000167 jump_in:
168 buf = xrealloc(buf, sz + 128);
169 p = buf + sz;
170 sz += 128;
171 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +0000172 /* nonblock_safe_read() because we are used by e.g. shells */
173 if (nonblock_safe_read(fd, p, 1) != 1) { /* EOF/error */
Denis Vlasenkof99afb52008-02-24 23:32:36 +0000174 if (p == buf) { /* we read nothing */
Denis Vlasenkod67cef22007-06-13 06:47:47 +0000175 free(buf);
176 return NULL;
177 }
178 break;
179 }
180 if (*p == '\n')
181 break;
182 p++;
183 }
Denis Vlasenko8ee649a2008-03-26 20:04:27 +0000184 *p = '\0';
Denis Vlasenko0b6c6a92008-03-24 00:04:42 +0000185 if (maxsz_p)
Denis Vlasenko8ee649a2008-03-26 20:04:27 +0000186 *maxsz_p = p - buf;
187 p++;
Denis Vlasenkod67cef22007-06-13 06:47:47 +0000188 return xrealloc(buf, p - buf);
189}
190
Denis Vlasenkodefc1ea2008-06-27 02:52:20 +0000191ssize_t FAST_FUNC read_close(int fd, void *buf, size_t size)
Denis Vlasenkoea620772006-10-14 02:23:43 +0000192{
Denis Vlasenko98ebab82007-06-30 14:47:41 +0000193 /*int e;*/
Denis Vlasenkoea620772006-10-14 02:23:43 +0000194 size = full_read(fd, buf, size);
Denis Vlasenko98ebab82007-06-30 14:47:41 +0000195 /*e = errno;*/
Denis Vlasenkoea620772006-10-14 02:23:43 +0000196 close(fd);
Denis Vlasenko98ebab82007-06-30 14:47:41 +0000197 /*errno = e;*/
Denis Vlasenkoea620772006-10-14 02:23:43 +0000198 return size;
199}
200
Denis Vlasenkodefc1ea2008-06-27 02:52:20 +0000201ssize_t FAST_FUNC open_read_close(const char *filename, void *buf, size_t size)
Denis Vlasenkoea620772006-10-14 02:23:43 +0000202{
203 int fd = open(filename, O_RDONLY);
204 if (fd < 0)
205 return fd;
206 return read_close(fd, buf, size);
207}
208
Denis Vlasenkof62ab2d2008-07-09 09:50:33 +0000209
Denis Vlasenkofe733a92008-06-24 16:08:22 +0000210// Read (potentially big) files in one go. File size is estimated
Denis Vlasenkof62ab2d2008-07-09 09:50:33 +0000211// by stat. Extra '\0' byte is appended.
Denis Vlasenkob6052722008-07-10 17:43:01 +0000212void* FAST_FUNC xmalloc_read(int fd, size_t *maxsz_p)
Denis Vlasenkoea620772006-10-14 02:23:43 +0000213{
214 char *buf;
Denis Vlasenkof62ab2d2008-07-09 09:50:33 +0000215 size_t size, rd_size, total;
Denis Vlasenkob6052722008-07-10 17:43:01 +0000216 size_t to_read;
Denis Vlasenko0a144622008-04-20 14:45:43 +0000217 struct stat st;
218
Denis Vlasenkob6052722008-07-10 17:43:01 +0000219 to_read = maxsz_p ? *maxsz_p : MAXINT(ssize_t); /* max to read */
Denis Vlasenko0a144622008-04-20 14:45:43 +0000220
Denis Vlasenkof62ab2d2008-07-09 09:50:33 +0000221 /* Estimate file size */
222 st.st_size = 0; /* in case fstat fails, assume 0 */
Denis Vlasenko0a144622008-04-20 14:45:43 +0000223 fstat(fd, &st);
Denis Vlasenkof62ab2d2008-07-09 09:50:33 +0000224 /* /proc/N/stat files report st_size 0 */
Denis Vlasenko0a144622008-04-20 14:45:43 +0000225 /* In order to make such files readable, we add small const */
Denis Vlasenkof62ab2d2008-07-09 09:50:33 +0000226 size = (st.st_size | 0x3ff) + 1;
227
228 total = 0;
229 buf = NULL;
230 while (1) {
231 if (to_read < size)
232 size = to_read;
233 buf = xrealloc(buf, total + size + 1);
234 rd_size = full_read(fd, buf + total, size);
Denis Vlasenkob6052722008-07-10 17:43:01 +0000235 if ((ssize_t)rd_size == (ssize_t)(-1)) { /* error */
Denis Vlasenkof62ab2d2008-07-09 09:50:33 +0000236 free(buf);
237 return NULL;
238 }
239 total += rd_size;
240 if (rd_size < size) /* EOF */
241 break;
Denis Vlasenkob6052722008-07-10 17:43:01 +0000242 if (to_read <= rd_size)
Denis Vlasenkof62ab2d2008-07-09 09:50:33 +0000243 break;
Denis Vlasenkob6052722008-07-10 17:43:01 +0000244 to_read -= rd_size;
Denis Vlasenkof62ab2d2008-07-09 09:50:33 +0000245 /* grow by 1/8, but in [1k..64k] bounds */
246 size = ((total / 8) | 0x3ff) + 1;
247 if (size > 64*1024)
248 size = 64*1024;
Denis Vlasenko0a144622008-04-20 14:45:43 +0000249 }
Denis Vlasenkof62ab2d2008-07-09 09:50:33 +0000250 xrealloc(buf, total + 1);
251 buf[total] = '\0';
Denis Vlasenko0a144622008-04-20 14:45:43 +0000252
Denis Vlasenkob6052722008-07-10 17:43:01 +0000253 if (maxsz_p)
254 *maxsz_p = total;
Denis Vlasenko0a144622008-04-20 14:45:43 +0000255 return buf;
256}
257
258#ifdef USING_LSEEK_TO_GET_SIZE
259/* Alternatively, file size can be obtained by lseek to the end.
260 * The code is slightly bigger. Retained in case fstat approach
261 * will not work for some weird cases (/proc, block devices, etc).
262 * (NB: lseek also can fail to work for some weird files) */
263
264// Read (potentially big) files in one go. File size is estimated by
265// lseek to end.
Denis Vlasenkob6052722008-07-10 17:43:01 +0000266void* FAST_FUNC xmalloc_open_read_close(const char *filename, size_t *maxsz_p)
Denis Vlasenko0a144622008-04-20 14:45:43 +0000267{
268 char *buf;
269 size_t size;
270 int fd;
271 off_t len;
Denis Vlasenkod67cef22007-06-13 06:47:47 +0000272
Denis Vlasenkof3745ea2008-04-19 19:32:08 +0000273 fd = open(filename, O_RDONLY);
274 if (fd < 0)
275 return NULL;
Denis Vlasenko25cfe492008-04-20 01:27:59 +0000276
Denis Vlasenkob131b272006-12-17 17:30:01 +0000277 /* /proc/N/stat files report len 0 here */
278 /* In order to make such files readable, we add small const */
Denis Vlasenko25cfe492008-04-20 01:27:59 +0000279 size = 0x3ff; /* read only 1k on unseekable files */
280 len = lseek(fd, 0, SEEK_END) | 0x3ff; /* + up to 1k */
281 if (len != (off_t)-1) {
282 xlseek(fd, 0, SEEK_SET);
Denis Vlasenkob6052722008-07-10 17:43:01 +0000283 size = maxsz_p ? *maxsz_p : INT_MAX;
Denis Vlasenko25cfe492008-04-20 01:27:59 +0000284 if (len < size)
285 size = len;
286 }
287
Denis Vlasenkob131b272006-12-17 17:30:01 +0000288 buf = xmalloc(size + 1);
Denis Vlasenkoea620772006-10-14 02:23:43 +0000289 size = read_close(fd, buf, size);
Denis Vlasenko25cfe492008-04-20 01:27:59 +0000290 if ((ssize_t)size < 0) {
291 free(buf);
292 return NULL;
293 }
Denis Vlasenkob131b272006-12-17 17:30:01 +0000294 xrealloc(buf, size + 1);
Denis Vlasenkoea620772006-10-14 02:23:43 +0000295 buf[size] = '\0';
Denis Vlasenko25cfe492008-04-20 01:27:59 +0000296
Denis Vlasenkob6052722008-07-10 17:43:01 +0000297 if (maxsz_p)
298 *maxsz_p = size;
Denis Vlasenkoea620772006-10-14 02:23:43 +0000299 return buf;
300}
Denis Vlasenko0a144622008-04-20 14:45:43 +0000301#endif
Denis Vlasenkof3745ea2008-04-19 19:32:08 +0000302
Denis Vlasenkof62ab2d2008-07-09 09:50:33 +0000303// Read (potentially big) files in one go. File size is estimated
304// by stat.
Denis Vlasenkob6052722008-07-10 17:43:01 +0000305void* FAST_FUNC xmalloc_open_read_close(const char *filename, size_t *maxsz_p)
Denis Vlasenkof62ab2d2008-07-09 09:50:33 +0000306{
307 char *buf;
308 int fd;
309
310 fd = open(filename, O_RDONLY);
311 if (fd < 0)
312 return NULL;
313
Denis Vlasenkob6052722008-07-10 17:43:01 +0000314 buf = xmalloc_read(fd, maxsz_p);
Denis Vlasenkof62ab2d2008-07-09 09:50:33 +0000315 close(fd);
316 return buf;
317}
318
Denis Vlasenkob6052722008-07-10 17:43:01 +0000319void* FAST_FUNC xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p)
Denis Vlasenkof3745ea2008-04-19 19:32:08 +0000320{
Denis Vlasenkob6052722008-07-10 17:43:01 +0000321 void *buf = xmalloc_open_read_close(filename, maxsz_p);
Denis Vlasenkof3745ea2008-04-19 19:32:08 +0000322 if (!buf)
323 bb_perror_msg_and_die("can't read '%s'", filename);
324 return buf;
325}
Denis Vlasenkob6052722008-07-10 17:43:01 +0000326
327#if ENABLE_FEATURE_MODPROBE_SMALL_ZIPPED
328void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p)
329{
330 char *image;
331 char *suffix;
332
333 int fd = open(fname, O_RDONLY);
334 if (fd < 0)
335 return NULL;
336
337 suffix = strrchr(fname, '.');
338 if (suffix) {
339 if (strcmp(suffix, ".gz") == 0)
340 open_transformer(fd, unpack_gz_stream, "gunzip");
341 else if (strcmp(suffix, ".bz2") == 0)
342 open_transformer(fd, unpack_bz2_stream, "bunzip2");
343 }
344
345 image = xmalloc_read(fd, maxsz_p);
346 if (!image)
347 bb_perror_msg("read error from '%s'", fname);
348 close(fd);
349
350 return image;
351}
352#endif