source: MondoRescue/branches/3.3/mindi-busybox/libbb/read_printf.c@ 3647

Last change on this file since 3647 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 5.9 KB
Line 
1/* 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 source tree.
8 */
9#include "libbb.h"
10
11
12/* Suppose that you are a shell. You start child processes.
13 * They work and eventually exit. You want to get user input.
14 * You read stdin. But what happens if last child switched
15 * its stdin into O_NONBLOCK mode?
16 *
17 * *** SURPRISE! It will affect the parent too! ***
18 * *** BIG SURPRISE! It stays even after child exits! ***
19 *
20 * This is a design bug in UNIX API.
21 * fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK);
22 * will set nonblocking mode not only on _your_ stdin, but
23 * also on stdin of your parent, etc.
24 *
25 * In general,
26 * fd2 = dup(fd1);
27 * fcntl(fd2, F_SETFL, fcntl(fd2, F_GETFL) | O_NONBLOCK);
28 * sets both fd1 and fd2 to O_NONBLOCK. This includes cases
29 * where duping is done implicitly by fork() etc.
30 *
31 * We need
32 * fcntl(fd2, F_SETFD, fcntl(fd2, F_GETFD) | O_NONBLOCK);
33 * (note SETFD, not SETFL!) but such thing doesn't exist.
34 *
35 * Alternatively, we need nonblocking_read(fd, ...) which doesn't
36 * require O_NONBLOCK dance at all. Actually, it exists:
37 * n = recv(fd, buf, len, MSG_DONTWAIT);
38 * "MSG_DONTWAIT:
39 * Enables non-blocking operation; if the operation
40 * would block, EAGAIN is returned."
41 * but recv() works only for sockets!
42 *
43 * So far I don't see any good solution, I can only propose
44 * that affected readers should be careful and use this routine,
45 * which detects EAGAIN and uses poll() to wait on the fd.
46 * Thankfully, poll() doesn't care about O_NONBLOCK flag.
47 */
48ssize_t FAST_FUNC nonblock_immune_read(int fd, void *buf, size_t count)
49{
50 struct pollfd pfd[1];
51 ssize_t n;
52
53 while (1) {
54 n = safe_read(fd, buf, count);
55 if (n >= 0 || errno != EAGAIN)
56 return n;
57 /* fd is in O_NONBLOCK mode. Wait using poll and repeat */
58 pfd[0].fd = fd;
59 pfd[0].events = POLLIN;
60 /* note: safe_poll pulls in printf */
61 safe_poll(pfd, 1, -1);
62 }
63}
64
65// Reads one line a-la fgets (but doesn't save terminating '\n').
66// Reads byte-by-byte. Useful when it is important to not read ahead.
67// Bytes are appended to pfx (which must be malloced, or NULL).
68char* FAST_FUNC xmalloc_reads(int fd, size_t *maxsz_p)
69{
70 char *p;
71 char *buf = NULL;
72 size_t sz = 0;
73 size_t maxsz = maxsz_p ? *maxsz_p : (INT_MAX - 4095);
74
75 goto jump_in;
76
77 while (sz < maxsz) {
78 if ((size_t)(p - buf) == sz) {
79 jump_in:
80 buf = xrealloc(buf, sz + 128);
81 p = buf + sz;
82 sz += 128;
83 }
84 if (nonblock_immune_read(fd, p, 1) != 1) {
85 /* EOF/error */
86 if (p == buf) { /* we read nothing */
87 free(buf);
88 return NULL;
89 }
90 break;
91 }
92 if (*p == '\n')
93 break;
94 p++;
95 }
96 *p = '\0';
97 if (maxsz_p)
98 *maxsz_p = p - buf;
99 p++;
100 return xrealloc(buf, p - buf);
101}
102
103// Read (potentially big) files in one go. File size is estimated
104// by stat. Extra '\0' byte is appended.
105void* FAST_FUNC xmalloc_read(int fd, size_t *maxsz_p)
106{
107 char *buf;
108 size_t size, rd_size, total;
109 size_t to_read;
110 struct stat st;
111
112 to_read = maxsz_p ? *maxsz_p : (INT_MAX - 4095); /* max to read */
113
114 /* Estimate file size */
115 st.st_size = 0; /* in case fstat fails, assume 0 */
116 fstat(fd, &st);
117 /* /proc/N/stat files report st_size 0 */
118 /* In order to make such files readable, we add small const */
119 size = (st.st_size | 0x3ff) + 1;
120
121 total = 0;
122 buf = NULL;
123 while (1) {
124 if (to_read < size)
125 size = to_read;
126 buf = xrealloc(buf, total + size + 1);
127 rd_size = full_read(fd, buf + total, size);
128 if ((ssize_t)rd_size == (ssize_t)(-1)) { /* error */
129 free(buf);
130 return NULL;
131 }
132 total += rd_size;
133 if (rd_size < size) /* EOF */
134 break;
135 if (to_read <= rd_size)
136 break;
137 to_read -= rd_size;
138 /* grow by 1/8, but in [1k..64k] bounds */
139 size = ((total / 8) | 0x3ff) + 1;
140 if (size > 64*1024)
141 size = 64*1024;
142 }
143 buf = xrealloc(buf, total + 1);
144 buf[total] = '\0';
145
146 if (maxsz_p)
147 *maxsz_p = total;
148 return buf;
149}
150
151#ifdef USING_LSEEK_TO_GET_SIZE
152/* Alternatively, file size can be obtained by lseek to the end.
153 * The code is slightly bigger. Retained in case fstat approach
154 * will not work for some weird cases (/proc, block devices, etc).
155 * (NB: lseek also can fail to work for some weird files) */
156
157// Read (potentially big) files in one go. File size is estimated by
158// lseek to end.
159void* FAST_FUNC xmalloc_open_read_close(const char *filename, size_t *maxsz_p)
160{
161 char *buf;
162 size_t size;
163 int fd;
164 off_t len;
165
166 fd = open(filename, O_RDONLY);
167 if (fd < 0)
168 return NULL;
169
170 /* /proc/N/stat files report len 0 here */
171 /* In order to make such files readable, we add small const */
172 size = 0x3ff; /* read only 1k on unseekable files */
173 len = lseek(fd, 0, SEEK_END) | 0x3ff; /* + up to 1k */
174 if (len != (off_t)-1) {
175 xlseek(fd, 0, SEEK_SET);
176 size = maxsz_p ? *maxsz_p : (INT_MAX - 4095);
177 if (len < size)
178 size = len;
179 }
180
181 buf = xmalloc(size + 1);
182 size = read_close(fd, buf, size);
183 if ((ssize_t)size < 0) {
184 free(buf);
185 return NULL;
186 }
187 buf = xrealloc(buf, size + 1);
188 buf[size] = '\0';
189
190 if (maxsz_p)
191 *maxsz_p = size;
192 return buf;
193}
194#endif
195
196// Read (potentially big) files in one go. File size is estimated
197// by stat.
198void* FAST_FUNC xmalloc_open_read_close(const char *filename, size_t *maxsz_p)
199{
200 char *buf;
201 int fd;
202
203 fd = open(filename, O_RDONLY);
204 if (fd < 0)
205 return NULL;
206
207 buf = xmalloc_read(fd, maxsz_p);
208 close(fd);
209 return buf;
210}
211
212/* Die with an error message if we can't read the entire buffer. */
213void FAST_FUNC xread(int fd, void *buf, size_t count)
214{
215 if (count) {
216 ssize_t size = full_read(fd, buf, count);
217 if ((size_t)size != count)
218 bb_error_msg_and_die("short read");
219 }
220}
221
222/* Die with an error message if we can't read one character. */
223unsigned char FAST_FUNC xread_char(int fd)
224{
225 char tmp;
226 xread(fd, &tmp, 1);
227 return tmp;
228}
229
230void* FAST_FUNC xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p)
231{
232 void *buf = xmalloc_open_read_close(filename, maxsz_p);
233 if (!buf)
234 bb_perror_msg_and_die("can't read '%s'", filename);
235 return buf;
236}
Note: See TracBrowser for help on using the repository browser.