|
1 // sysread.c - interface to system read/write |
|
2 // |
|
3 // © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved. |
|
4 // |
|
5 /* |
|
6 * This file is part of zsh, the Z shell. |
|
7 * |
|
8 * Copyright (c) 1998-2003 Peter Stephenson |
|
9 * All rights reserved. |
|
10 * |
|
11 * Permission is hereby granted, without written agreement and without |
|
12 * license or royalty fees, to use, copy, modify, and distribute this |
|
13 * software and to distribute modified versions of this software for any |
|
14 * purpose, provided that the above copyright notice and the following |
|
15 * two paragraphs appear in all copies of this software. |
|
16 * |
|
17 * In no event shall Peter Stephenson or the Zsh Development |
|
18 * Group be liable to any party for direct, indirect, special, incidental, |
|
19 * or consequential damages arising out of the use of this software and |
|
20 * its documentation, even if Peter Stephenson, and the Zsh |
|
21 * Development Group have been advised of the possibility of such damage. |
|
22 * |
|
23 * Peter Stephenson and the Zsh Development Group specifically |
|
24 * disclaim any warranties, including, but not limited to, the implied |
|
25 * warranties of merchantability and fitness for a particular purpose. The |
|
26 * software provided hereunder is on an "as is" basis, and Peter Stephenson |
|
27 * and the Zsh Development Group have no obligation to provide maintenance, |
|
28 * support, updates, enhancements, or modifications. |
|
29 * |
|
30 */ |
|
31 #include "system.mdh" |
|
32 #include "system.pro" |
|
33 |
|
34 #ifdef __SYMBIAN32__ |
|
35 #include "dummy.h" //poll |
|
36 #endif //__SYMBIAN32__ |
|
37 |
|
38 #ifdef HAVE_POLL_H |
|
39 #ifndef __SYMBIAN32__ |
|
40 # include <sys/poll.h> |
|
41 #else |
|
42 #include "poll.h" |
|
43 #endif |
|
44 #endif |
|
45 #if defined(HAVE_POLL) && !defined(POLLIN) |
|
46 # undef HAVE_POLL |
|
47 #endif |
|
48 |
|
49 #ifdef __SYMBIAN32__ |
|
50 #ifdef __WINSCW__ |
|
51 #pragma warn_unusedarg off |
|
52 #endif//__WINSCW__ |
|
53 #endif//__SYMBIAN32__ |
|
54 |
|
55 #define SYSREAD_BUFSIZE 8192 |
|
56 |
|
57 /**/ |
|
58 static int |
|
59 getposint(char *instr, char *nam) |
|
60 { |
|
61 char *eptr; |
|
62 int ret; |
|
63 |
|
64 ret = (int)zstrtol(instr, &eptr, 10); |
|
65 if (*eptr || ret < 0) { |
|
66 zwarnnam(nam, "integer expected: %s", instr, 0); |
|
67 return -1; |
|
68 } |
|
69 |
|
70 return ret; |
|
71 } |
|
72 |
|
73 |
|
74 /* |
|
75 * Return values of bin_sysread: |
|
76 * 0 Successfully read (and written if appropriate) |
|
77 * 1 Error in parameters to command |
|
78 * 2 Error on read, or polling read fd ) ERRNO set by |
|
79 * 3 Error on write ) system |
|
80 * 4 Timeout on read |
|
81 * 5 Zero bytes read, end of file |
|
82 */ |
|
83 |
|
84 /**/ |
|
85 static int |
|
86 bin_sysread(char *nam, char **args, Options ops, UNUSED(int func)) |
|
87 { |
|
88 int infd = 0, outfd = -1, bufsize = SYSREAD_BUFSIZE, count; |
|
89 char *outvar = NULL, *countvar = NULL, *inbuf; |
|
90 |
|
91 /* -i: input file descriptor if not stdin */ |
|
92 if (OPT_ISSET(ops, 'i')) { |
|
93 infd = getposint(OPT_ARG(ops, 'i'), nam); |
|
94 if (infd < 0) |
|
95 return 1; |
|
96 } |
|
97 |
|
98 /* -o: output file descriptor, else store in REPLY */ |
|
99 if (OPT_ISSET(ops, 'o')) { |
|
100 if (*args) { |
|
101 zwarnnam(nam, "no argument allowed with -o", NULL, 0); |
|
102 return 1; |
|
103 } |
|
104 outfd = getposint(OPT_ARG(ops, 'o'), nam); |
|
105 if (outfd < 0) |
|
106 return 1; |
|
107 } |
|
108 |
|
109 /* -s: buffer size if not default SYSREAD_BUFSIZE */ |
|
110 if (OPT_ISSET(ops, 's')) { |
|
111 bufsize = getposint(OPT_ARG(ops, 's'), nam); |
|
112 if (bufsize < 0) |
|
113 return 1; |
|
114 } |
|
115 |
|
116 /* -c: name of variable to store count of transferred bytes */ |
|
117 if (OPT_ISSET(ops, 'c')) { |
|
118 countvar = OPT_ARG(ops, 'c'); |
|
119 if (!isident(countvar)) { |
|
120 zwarnnam(nam, "not an identifier: %s", countvar, 0); |
|
121 return 1; |
|
122 } |
|
123 } |
|
124 |
|
125 if (*args) { |
|
126 /* |
|
127 * Variable in which to store result if doing a plain read. |
|
128 * Default variable if not specified is REPLY. |
|
129 * If writing, only stuff we couldn't write is stored here, |
|
130 * no default in that case (we just discard it if no variable). |
|
131 */ |
|
132 outvar = *args; |
|
133 if (!isident(outvar)) { |
|
134 zwarnnam(nam, "not an identifier: %s", outvar, 0); |
|
135 return 1; |
|
136 } |
|
137 } |
|
138 |
|
139 inbuf = zhalloc(bufsize); |
|
140 |
|
141 #if defined(HAVE_POLL) || defined(HAVE_SELECT) |
|
142 /* -t: timeout */ |
|
143 if (OPT_ISSET(ops, 't')) |
|
144 { |
|
145 # ifdef HAVE_POLL |
|
146 struct pollfd poll_fd; |
|
147 mnumber to_mn; |
|
148 int to_int, ret; |
|
149 |
|
150 poll_fd.fd = infd; |
|
151 poll_fd.events = POLLIN; |
|
152 |
|
153 to_mn = matheval(OPT_ARG(ops, 't')); |
|
154 if (errflag) |
|
155 return 1; |
|
156 if (to_mn.type == MN_FLOAT) |
|
157 to_int = (int) (1000 * to_mn.u.d); |
|
158 else |
|
159 to_int = 1000 * (int)to_mn.u.l; |
|
160 |
|
161 while ((ret = poll(&poll_fd, 1, to_int)) < 0) { |
|
162 if (errno != EINTR || errflag || retflag || breaks || contflag) |
|
163 break; |
|
164 } |
|
165 if (ret <= 0) { |
|
166 /* treat non-timeout error as error on read */ |
|
167 return ret ? 2 : 4; |
|
168 } |
|
169 # else |
|
170 /* using select */ |
|
171 struct timeval select_tv; |
|
172 fd_set fds; |
|
173 mnumber to_mn; |
|
174 int ret; |
|
175 |
|
176 FD_ZERO(&fds); |
|
177 FD_SET(infd, &fds); |
|
178 to_mn = matheval(OPT_ARG(ops, 't')); |
|
179 if (errflag) |
|
180 return 1; |
|
181 |
|
182 if (to_mn.type == MN_FLOAT) { |
|
183 select_tv.tv_sec = (int) to_mn.u.d; |
|
184 select_tv.tv_usec = |
|
185 (int) ((to_mn.u.d - select_tv.tv_sec) * 1e6); |
|
186 } else { |
|
187 select_tv.tv_sec = (int) to_mn.u.l; |
|
188 select_tv.tv_usec = 0; |
|
189 } |
|
190 |
|
191 while ((ret = select(infd+1, (SELECT_ARG_2_T) &fds, |
|
192 NULL, NULL,&select_tv)) < 1) { |
|
193 if (errno != EINTR || errflag || retflag || breaks || contflag) |
|
194 break; |
|
195 } |
|
196 if (ret <= 0) { |
|
197 /* treat non-timeout error as error on read */ |
|
198 return ret ? 2 : 4; |
|
199 } |
|
200 # endif |
|
201 } |
|
202 #endif |
|
203 |
|
204 while ((count = read(infd, inbuf, bufsize)) < 0) { |
|
205 if (errno != EINTR || errflag || retflag || breaks || contflag) |
|
206 break; |
|
207 } |
|
208 if (countvar) |
|
209 setiparam(countvar, count); |
|
210 if (count < 0) |
|
211 return 2; |
|
212 |
|
213 if (outfd >= 0) { |
|
214 if (!count) |
|
215 return 5; |
|
216 while (count > 0) { |
|
217 int ret; |
|
218 |
|
219 ret = write(outfd, inbuf, count); |
|
220 if (ret < 0) { |
|
221 if (errno == EINTR && !errflag && |
|
222 !retflag && !breaks && !contflag) |
|
223 continue; |
|
224 if (outvar) |
|
225 setsparam(outvar, metafy(inbuf, count, META_DUP)); |
|
226 if (countvar) |
|
227 setiparam(countvar, count); |
|
228 return 3; |
|
229 } |
|
230 inbuf += ret; |
|
231 count -= ret; |
|
232 } |
|
233 return 0; |
|
234 } |
|
235 |
|
236 if (!outvar) |
|
237 outvar = "REPLY"; |
|
238 /* do this even if we read zero bytes */ |
|
239 setsparam(outvar, metafy(inbuf, count, META_DUP)); |
|
240 |
|
241 return count ? 0 : 5; |
|
242 } |
|
243 |
|
244 |
|
245 /* |
|
246 * Return values of bin_syswrite: |
|
247 * 0 Successfully written |
|
248 * 1 Error in parameters to command |
|
249 * 2 Error on write, ERRNO set by system |
|
250 */ |
|
251 |
|
252 /**/ |
|
253 static int |
|
254 bin_syswrite(char *nam, char **args, Options ops, UNUSED(int func)) |
|
255 { |
|
256 int outfd = 1, len, count, totcount; |
|
257 char *countvar = NULL; |
|
258 |
|
259 /* -o: output file descriptor if not stdout */ |
|
260 if (OPT_ISSET(ops, 'o')) { |
|
261 outfd = getposint(OPT_ARG(ops, 'o'), nam); |
|
262 if (outfd < 0) |
|
263 return 1; |
|
264 } |
|
265 |
|
266 /* -c: variable in which to store count of bytes written */ |
|
267 if (OPT_ISSET(ops, 'c')) { |
|
268 countvar = OPT_ARG(ops, 'c'); |
|
269 if (!isident(countvar)) { |
|
270 zwarnnam(nam, "not an identifier: %s", countvar, 0); |
|
271 return 1; |
|
272 } |
|
273 } |
|
274 |
|
275 totcount = 0; |
|
276 unmetafy(*args, &len); |
|
277 while (len) { |
|
278 while ((count = write(outfd, *args, len)) < 0) { |
|
279 if (errno != EINTR || errflag || retflag || breaks || contflag) |
|
280 { |
|
281 if (countvar) |
|
282 setiparam(countvar, totcount); |
|
283 return 2; |
|
284 } |
|
285 } |
|
286 *args += count; |
|
287 totcount += count; |
|
288 len -= count; |
|
289 } |
|
290 if (countvar) |
|
291 setiparam(countvar, totcount); |
|
292 |
|
293 return 0; |
|
294 } |
|
295 |
|
296 |
|
297 /* |
|
298 * Return values of bin_syserror: |
|
299 * 0 Successfully processed error |
|
300 * (although if the number was invalid the string |
|
301 * may not be useful) |
|
302 * 1 Error in parameters |
|
303 * 2 Name of error not recognised. |
|
304 */ |
|
305 |
|
306 /**/ |
|
307 static int |
|
308 bin_syserror(char *nam, char **args, Options ops, UNUSED(int func)) |
|
309 { |
|
310 int num = 0; |
|
311 char *errvar = NULL, *msg, *pfx = "", *str; |
|
312 |
|
313 /* variable in which to write error message */ |
|
314 if (OPT_ISSET(ops, 'e')) { |
|
315 errvar = OPT_ARG(ops, 'e'); |
|
316 if (!isident(errvar)) { |
|
317 zwarnnam(nam, "not an identifier: %s", errvar, 0); |
|
318 return 1; |
|
319 } |
|
320 } |
|
321 /* prefix for error message */ |
|
322 if (OPT_ISSET(ops, 'p')) |
|
323 pfx = OPT_ARG(ops, 'p'); |
|
324 |
|
325 if (!*args) |
|
326 num = errno; |
|
327 else { |
|
328 char *ptr = *args; |
|
329 while (*ptr && idigit(*ptr)) |
|
330 ptr++; |
|
331 if (!*ptr && ptr > *args) |
|
332 num = atoi(*args); |
|
333 else { |
|
334 const char **eptr; |
|
335 for (eptr = sys_errnames; *eptr; eptr++) { |
|
336 if (!strcmp(*eptr, *args)) { |
|
337 num = (eptr - sys_errnames) + 1; |
|
338 break; |
|
339 } |
|
340 } |
|
341 if (!*eptr) |
|
342 return 2; |
|
343 } |
|
344 } |
|
345 |
|
346 msg = strerror(num); |
|
347 if (errvar) { |
|
348 str = (char *)zalloc(strlen(msg) + strlen(pfx) + 1); |
|
349 sprintf(str, "%s%s", pfx, msg); |
|
350 setsparam(errvar, str); |
|
351 } else { |
|
352 fprintf(stderr, "%s%s\n", pfx, msg); |
|
353 } |
|
354 |
|
355 return 0; |
|
356 } |
|
357 |
|
358 |
|
359 /* Functions for the errnos special parameter. */ |
|
360 |
|
361 /**/ |
|
362 static char ** |
|
363 errnosgetfn(UNUSED(Param pm)) |
|
364 { |
|
365 /* arrdup etc. should really take const pointers as arguments */ |
|
366 return arrdup((char **)sys_errnames); |
|
367 } |
|
368 |
|
369 |
|
370 static struct builtin bintab[] = { |
|
371 BUILTIN("syserror", 0, bin_syserror, 0, 1, 0, "e:p:", NULL), |
|
372 BUILTIN("sysread", 0, bin_sysread, 0, 1, 0, "c:i:o:s:t:", NULL), |
|
373 BUILTIN("syswrite", 0, bin_syswrite, 1, 1, 0, "c:o:", NULL), |
|
374 }; |
|
375 |
|
376 static const struct gsu_array errnos_gsu = |
|
377 { errnosgetfn, arrsetfn, stdunsetfn }; |
|
378 |
|
379 /* The load/unload routines required by the zsh library interface */ |
|
380 |
|
381 /**/ |
|
382 int |
|
383 setup_(UNUSED(Module m)) |
|
384 { |
|
385 return 0; |
|
386 } |
|
387 |
|
388 /**/ |
|
389 static void |
|
390 tidyparam(Param pm) |
|
391 { |
|
392 if (!pm) |
|
393 return; |
|
394 pm->flags &= ~PM_READONLY; |
|
395 unsetparam_pm(pm, 0, 1); |
|
396 } |
|
397 |
|
398 |
|
399 /**/ |
|
400 int |
|
401 boot_(Module m) |
|
402 { |
|
403 Param pm_nos; |
|
404 |
|
405 /* this takes care of an autoload on errnos */ |
|
406 unsetparam("errnos"); |
|
407 if (!(pm_nos = createparam("errnos", PM_ARRAY|PM_SPECIAL|PM_READONLY| |
|
408 PM_HIDE|PM_HIDEVAL|PM_REMOVABLE))) |
|
409 return 1; |
|
410 pm_nos->gsu.a = &errnos_gsu; |
|
411 |
|
412 if (!addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab))) { |
|
413 tidyparam(pm_nos); |
|
414 return 1; |
|
415 } |
|
416 return 0; |
|
417 } |
|
418 |
|
419 |
|
420 /**/ |
|
421 int |
|
422 cleanup_(Module m) |
|
423 { |
|
424 tidyparam((Param)paramtab->getnode(paramtab, "errnos")); |
|
425 |
|
426 deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); |
|
427 return 0; |
|
428 } |
|
429 |
|
430 /**/ |
|
431 int |
|
432 finish_(UNUSED(Module m)) |
|
433 { |
|
434 return 0; |
|
435 } |