2 * sysread.c - interface to system read/write
4 * This file is part of zsh, the Z shell.
6 * Copyright (c) 1998-2003 Peter Stephenson
9 * Permission is hereby granted, without written agreement and without
10 * license or royalty fees, to use, copy, modify, and distribute this
11 * software and to distribute modified versions of this software for any
12 * purpose, provided that the above copyright notice and the following
13 * two paragraphs appear in all copies of this software.
15 * In no event shall Peter Stephenson or the Zsh Development
16 * Group be liable to any party for direct, indirect, special, incidental,
17 * or consequential damages arising out of the use of this software and
18 * its documentation, even if Peter Stephenson, and the Zsh
19 * Development Group have been advised of the possibility of such damage.
21 * Peter Stephenson and the Zsh Development Group specifically
22 * disclaim any warranties, including, but not limited to, the implied
23 * warranties of merchantability and fitness for a particular purpose. The
24 * software provided hereunder is on an "as is" basis, and Peter Stephenson
25 * and the Zsh Development Group have no obligation to provide maintenance,
26 * support, updates, enhancements, or modifications.
36 #if defined(HAVE_POLL) && !defined(POLLIN)
40 #define SYSREAD_BUFSIZE 8192
44 getposint(char *instr
, char *nam
)
49 ret
= (int)zstrtol(instr
, &eptr
, 10);
50 if (*eptr
|| ret
< 0) {
51 zwarnnam(nam
, "integer expected: %s", instr
);
60 * Return values of bin_sysread:
61 * 0 Successfully read (and written if appropriate)
62 * 1 Error in parameters to command
63 * 2 Error on read, or polling read fd ) ERRNO set by
64 * 3 Error on write ) system
66 * 5 Zero bytes read, end of file
71 bin_sysread(char *nam
, char **args
, Options ops
, UNUSED(int func
))
73 int infd
= 0, outfd
= -1, bufsize
= SYSREAD_BUFSIZE
, count
;
74 char *outvar
= NULL
, *countvar
= NULL
, *inbuf
;
76 /* -i: input file descriptor if not stdin */
77 if (OPT_ISSET(ops
, 'i')) {
78 infd
= getposint(OPT_ARG(ops
, 'i'), nam
);
83 /* -o: output file descriptor, else store in REPLY */
84 if (OPT_ISSET(ops
, 'o')) {
86 zwarnnam(nam
, "no argument allowed with -o");
89 outfd
= getposint(OPT_ARG(ops
, 'o'), nam
);
94 /* -s: buffer size if not default SYSREAD_BUFSIZE */
95 if (OPT_ISSET(ops
, 's')) {
96 bufsize
= getposint(OPT_ARG(ops
, 's'), nam
);
101 /* -c: name of variable to store count of transferred bytes */
102 if (OPT_ISSET(ops
, 'c')) {
103 countvar
= OPT_ARG(ops
, 'c');
104 if (!isident(countvar
)) {
105 zwarnnam(nam
, "not an identifier: %s", countvar
);
112 * Variable in which to store result if doing a plain read.
113 * Default variable if not specified is REPLY.
114 * If writing, only stuff we couldn't write is stored here,
115 * no default in that case (we just discard it if no variable).
118 if (!isident(outvar
)) {
119 zwarnnam(nam
, "not an identifier: %s", outvar
);
124 inbuf
= zhalloc(bufsize
);
126 #if defined(HAVE_POLL) || defined(HAVE_SELECT)
128 if (OPT_ISSET(ops
, 't'))
131 struct pollfd poll_fd
;
136 poll_fd
.events
= POLLIN
;
138 to_mn
= matheval(OPT_ARG(ops
, 't'));
141 if (to_mn
.type
== MN_FLOAT
)
142 to_int
= (int) (1000 * to_mn
.u
.d
);
144 to_int
= 1000 * (int)to_mn
.u
.l
;
146 while ((ret
= poll(&poll_fd
, 1, to_int
)) < 0) {
147 if (errno
!= EINTR
|| errflag
|| retflag
|| breaks
|| contflag
)
151 /* treat non-timeout error as error on read */
156 struct timeval select_tv
;
163 to_mn
= matheval(OPT_ARG(ops
, 't'));
167 if (to_mn
.type
== MN_FLOAT
) {
168 select_tv
.tv_sec
= (int) to_mn
.u
.d
;
170 (int) ((to_mn
.u
.d
- select_tv
.tv_sec
) * 1e6
);
172 select_tv
.tv_sec
= (int) to_mn
.u
.l
;
173 select_tv
.tv_usec
= 0;
176 while ((ret
= select(infd
+1, (SELECT_ARG_2_T
) &fds
,
177 NULL
, NULL
,&select_tv
)) < 1) {
178 if (errno
!= EINTR
|| errflag
|| retflag
|| breaks
|| contflag
)
182 /* treat non-timeout error as error on read */
189 while ((count
= read(infd
, inbuf
, bufsize
)) < 0) {
190 if (errno
!= EINTR
|| errflag
|| retflag
|| breaks
|| contflag
)
194 setiparam(countvar
, count
);
204 ret
= write(outfd
, inbuf
, count
);
206 if (errno
== EINTR
&& !errflag
&&
207 !retflag
&& !breaks
&& !contflag
)
210 setsparam(outvar
, metafy(inbuf
, count
, META_DUP
));
212 setiparam(countvar
, count
);
223 /* do this even if we read zero bytes */
224 setsparam(outvar
, metafy(inbuf
, count
, META_DUP
));
226 return count
? 0 : 5;
231 * Return values of bin_syswrite:
232 * 0 Successfully written
233 * 1 Error in parameters to command
234 * 2 Error on write, ERRNO set by system
239 bin_syswrite(char *nam
, char **args
, Options ops
, UNUSED(int func
))
241 int outfd
= 1, len
, count
, totcount
;
242 char *countvar
= NULL
;
244 /* -o: output file descriptor if not stdout */
245 if (OPT_ISSET(ops
, 'o')) {
246 outfd
= getposint(OPT_ARG(ops
, 'o'), nam
);
251 /* -c: variable in which to store count of bytes written */
252 if (OPT_ISSET(ops
, 'c')) {
253 countvar
= OPT_ARG(ops
, 'c');
254 if (!isident(countvar
)) {
255 zwarnnam(nam
, "not an identifier: %s", countvar
);
261 unmetafy(*args
, &len
);
263 while ((count
= write(outfd
, *args
, len
)) < 0) {
264 if (errno
!= EINTR
|| errflag
|| retflag
|| breaks
|| contflag
)
267 setiparam(countvar
, totcount
);
276 setiparam(countvar
, totcount
);
283 * Return values of bin_syserror:
284 * 0 Successfully processed error
285 * (although if the number was invalid the string
287 * 1 Error in parameters
288 * 2 Name of error not recognised.
293 bin_syserror(char *nam
, char **args
, Options ops
, UNUSED(int func
))
296 char *errvar
= NULL
, *msg
, *pfx
= "", *str
;
298 /* variable in which to write error message */
299 if (OPT_ISSET(ops
, 'e')) {
300 errvar
= OPT_ARG(ops
, 'e');
301 if (!isident(errvar
)) {
302 zwarnnam(nam
, "not an identifier: %s", errvar
);
306 /* prefix for error message */
307 if (OPT_ISSET(ops
, 'p'))
308 pfx
= OPT_ARG(ops
, 'p');
314 while (*ptr
&& idigit(*ptr
))
316 if (!*ptr
&& ptr
> *args
)
320 for (eptr
= sys_errnames
; *eptr
; eptr
++) {
321 if (!strcmp(*eptr
, *args
)) {
322 num
= (eptr
- sys_errnames
) + 1;
333 str
= (char *)zalloc(strlen(msg
) + strlen(pfx
) + 1);
334 sprintf(str
, "%s%s", pfx
, msg
);
335 setsparam(errvar
, str
);
337 fprintf(stderr
, "%s%s\n", pfx
, msg
);
343 static struct builtin bintab
[] = {
344 BUILTIN("syserror", 0, bin_syserror
, 0, 1, 0, "e:p:", NULL
),
345 BUILTIN("sysread", 0, bin_sysread
, 0, 1, 0, "c:i:o:s:t:", NULL
),
346 BUILTIN("syswrite", 0, bin_syswrite
, 1, 1, 0, "c:o:", NULL
),
350 /* Functions for the errnos special parameter. */
354 errnosgetfn(UNUSED(Param pm
))
356 /* arrdup etc. should really take const pointers as arguments */
357 return arrdup((char **)sys_errnames
);
360 static const struct gsu_array errnos_gsu
=
361 { errnosgetfn
, arrsetfn
, stdunsetfn
};
364 /* Functions for the sysparams special parameter. */
368 fillpmsysparams(Param pm
, const char *name
)
370 char buf
[DIGBUFSIZE
];
373 pm
->node
.nam
= dupstring(name
);
374 pm
->node
.flags
= PM_SCALAR
| PM_READONLY
;
375 pm
->gsu
.s
= &nullsetscalar_gsu
;
376 if (!strcmp(name
, "pid")) {
378 } else if (!strcmp(name
, "ppid")) {
379 num
= (int)getppid();
381 pm
->u
.str
= dupstring("");
382 pm
->node
.flags
|= PM_UNSET
;
386 sprintf(buf
, "%d", num
);
387 pm
->u
.str
= dupstring(buf
);
393 getpmsysparams(UNUSED(HashTable ht
), const char *name
)
397 pm
= (Param
) hcalloc(sizeof(struct param
));
398 fillpmsysparams(pm
, name
);
405 scanpmsysparams(UNUSED(HashTable ht
), ScanFunc func
, int flags
)
409 fillpmsysparams(&spm
, "pid");
410 func(&spm
.node
, flags
);
411 fillpmsysparams(&spm
, "ppid");
412 func(&spm
.node
, flags
);
416 static struct paramdef partab
[] = {
417 SPECIALPMDEF("errnos", PM_ARRAY
|PM_READONLY
,
418 &errnos_gsu
, NULL
, NULL
),
419 SPECIALPMDEF("sysparams", PM_READONLY
,
420 NULL
, getpmsysparams
, scanpmsysparams
)
423 static struct features module_features
= {
424 bintab
, sizeof(bintab
)/sizeof(*bintab
),
427 partab
, sizeof(partab
)/sizeof(*partab
),
431 /* The load/unload routines required by the zsh library interface */
435 setup_(UNUSED(Module m
))
442 features_(Module m
, char ***features
)
444 *features
= featuresarray(m
, &module_features
);
450 enables_(Module m
, int **enables
)
452 return handlefeatures(m
, &module_features
, enables
);
467 return setfeatureenables(m
, &module_features
, NULL
);
472 finish_(UNUSED(Module m
))