26763: fix problem on failed cd -s to relative path
[zsh.git] / Src / Modules / system.c
blob4af464db05b7dfae454622e889ffd091989d16a4
1 /*
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
7 * All rights reserved.
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.
30 #include "system.mdh"
31 #include "system.pro"
33 #ifdef HAVE_POLL_H
34 # include <poll.h>
35 #endif
36 #if defined(HAVE_POLL) && !defined(POLLIN)
37 # undef HAVE_POLL
38 #endif
40 #define SYSREAD_BUFSIZE 8192
42 /**/
43 static int
44 getposint(char *instr, char *nam)
46 char *eptr;
47 int ret;
49 ret = (int)zstrtol(instr, &eptr, 10);
50 if (*eptr || ret < 0) {
51 zwarnnam(nam, "integer expected: %s", instr);
52 return -1;
55 return ret;
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
65 * 4 Timeout on read
66 * 5 Zero bytes read, end of file
69 /**/
70 static int
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);
79 if (infd < 0)
80 return 1;
83 /* -o: output file descriptor, else store in REPLY */
84 if (OPT_ISSET(ops, 'o')) {
85 if (*args) {
86 zwarnnam(nam, "no argument allowed with -o");
87 return 1;
89 outfd = getposint(OPT_ARG(ops, 'o'), nam);
90 if (outfd < 0)
91 return 1;
94 /* -s: buffer size if not default SYSREAD_BUFSIZE */
95 if (OPT_ISSET(ops, 's')) {
96 bufsize = getposint(OPT_ARG(ops, 's'), nam);
97 if (bufsize < 0)
98 return 1;
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);
106 return 1;
110 if (*args) {
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).
117 outvar = *args;
118 if (!isident(outvar)) {
119 zwarnnam(nam, "not an identifier: %s", outvar);
120 return 1;
124 inbuf = zhalloc(bufsize);
126 #if defined(HAVE_POLL) || defined(HAVE_SELECT)
127 /* -t: timeout */
128 if (OPT_ISSET(ops, 't'))
130 # ifdef HAVE_POLL
131 struct pollfd poll_fd;
132 mnumber to_mn;
133 int to_int, ret;
135 poll_fd.fd = infd;
136 poll_fd.events = POLLIN;
138 to_mn = matheval(OPT_ARG(ops, 't'));
139 if (errflag)
140 return 1;
141 if (to_mn.type == MN_FLOAT)
142 to_int = (int) (1000 * to_mn.u.d);
143 else
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)
148 break;
150 if (ret <= 0) {
151 /* treat non-timeout error as error on read */
152 return ret ? 2 : 4;
154 # else
155 /* using select */
156 struct timeval select_tv;
157 fd_set fds;
158 mnumber to_mn;
159 int ret;
161 FD_ZERO(&fds);
162 FD_SET(infd, &fds);
163 to_mn = matheval(OPT_ARG(ops, 't'));
164 if (errflag)
165 return 1;
167 if (to_mn.type == MN_FLOAT) {
168 select_tv.tv_sec = (int) to_mn.u.d;
169 select_tv.tv_usec =
170 (int) ((to_mn.u.d - select_tv.tv_sec) * 1e6);
171 } else {
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)
179 break;
181 if (ret <= 0) {
182 /* treat non-timeout error as error on read */
183 return ret ? 2 : 4;
185 # endif
187 #endif
189 while ((count = read(infd, inbuf, bufsize)) < 0) {
190 if (errno != EINTR || errflag || retflag || breaks || contflag)
191 break;
193 if (countvar)
194 setiparam(countvar, count);
195 if (count < 0)
196 return 2;
198 if (outfd >= 0) {
199 if (!count)
200 return 5;
201 while (count > 0) {
202 int ret;
204 ret = write(outfd, inbuf, count);
205 if (ret < 0) {
206 if (errno == EINTR && !errflag &&
207 !retflag && !breaks && !contflag)
208 continue;
209 if (outvar)
210 setsparam(outvar, metafy(inbuf, count, META_DUP));
211 if (countvar)
212 setiparam(countvar, count);
213 return 3;
215 inbuf += ret;
216 count -= ret;
218 return 0;
221 if (!outvar)
222 outvar = "REPLY";
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
237 /**/
238 static int
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);
247 if (outfd < 0)
248 return 1;
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);
256 return 1;
260 totcount = 0;
261 unmetafy(*args, &len);
262 while (len) {
263 while ((count = write(outfd, *args, len)) < 0) {
264 if (errno != EINTR || errflag || retflag || breaks || contflag)
266 if (countvar)
267 setiparam(countvar, totcount);
268 return 2;
271 *args += count;
272 totcount += count;
273 len -= count;
275 if (countvar)
276 setiparam(countvar, totcount);
278 return 0;
283 * Return values of bin_syserror:
284 * 0 Successfully processed error
285 * (although if the number was invalid the string
286 * may not be useful)
287 * 1 Error in parameters
288 * 2 Name of error not recognised.
291 /**/
292 static int
293 bin_syserror(char *nam, char **args, Options ops, UNUSED(int func))
295 int num = 0;
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);
303 return 1;
306 /* prefix for error message */
307 if (OPT_ISSET(ops, 'p'))
308 pfx = OPT_ARG(ops, 'p');
310 if (!*args)
311 num = errno;
312 else {
313 char *ptr = *args;
314 while (*ptr && idigit(*ptr))
315 ptr++;
316 if (!*ptr && ptr > *args)
317 num = atoi(*args);
318 else {
319 const char **eptr;
320 for (eptr = sys_errnames; *eptr; eptr++) {
321 if (!strcmp(*eptr, *args)) {
322 num = (eptr - sys_errnames) + 1;
323 break;
326 if (!*eptr)
327 return 2;
331 msg = strerror(num);
332 if (errvar) {
333 str = (char *)zalloc(strlen(msg) + strlen(pfx) + 1);
334 sprintf(str, "%s%s", pfx, msg);
335 setsparam(errvar, str);
336 } else {
337 fprintf(stderr, "%s%s\n", pfx, msg);
340 return 0;
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. */
352 /**/
353 static char **
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. */
366 /**/
367 static void
368 fillpmsysparams(Param pm, const char *name)
370 char buf[DIGBUFSIZE];
371 int num;
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")) {
377 num = (int)getpid();
378 } else if (!strcmp(name, "ppid")) {
379 num = (int)getppid();
380 } else {
381 pm->u.str = dupstring("");
382 pm->node.flags |= PM_UNSET;
383 return;
386 sprintf(buf, "%d", num);
387 pm->u.str = dupstring(buf);
391 /**/
392 static HashNode
393 getpmsysparams(UNUSED(HashTable ht), const char *name)
395 Param pm;
397 pm = (Param) hcalloc(sizeof(struct param));
398 fillpmsysparams(pm, name);
399 return &pm->node;
403 /**/
404 static void
405 scanpmsysparams(UNUSED(HashTable ht), ScanFunc func, int flags)
407 struct param spm;
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),
425 NULL, 0,
426 NULL, 0,
427 partab, sizeof(partab)/sizeof(*partab),
431 /* The load/unload routines required by the zsh library interface */
433 /**/
435 setup_(UNUSED(Module m))
437 return 0;
440 /**/
442 features_(Module m, char ***features)
444 *features = featuresarray(m, &module_features);
445 return 0;
448 /**/
450 enables_(Module m, int **enables)
452 return handlefeatures(m, &module_features, enables);
455 /**/
457 boot_(Module m)
459 return 0;
463 /**/
465 cleanup_(Module m)
467 return setfeatureenables(m, &module_features, NULL);
470 /**/
472 finish_(UNUSED(Module m))
474 return 0;