1 #line 982 "../../src/builtin/snarf.m4"
2 /* -*- buffer-read-only: t -*- vi: set ro:
3    THIS FILE IS GENERATED AUTOMATICALLY.  PLEASE DO NOT EDIT.
4 */
5 #line 982
6 #ifdef HAVE_CONFIG_H
7 #line 982
8 # include <config.h>
9 #line 982
10 #endif
11 #line 982
12 #include <sys/types.h>
13 #line 982
14 
15 #line 982
16 #include "mailfromd.h"
17 #line 982
18 #include "prog.h"
19 #line 982
20 #include "builtin.h"
21 #line 982
22 
23 #line 180 "io.bi"
24 static mu_debug_handle_t debug_handle;
25 #line 982 "../../src/builtin/snarf.m4"
26 
27 #line 1022 "../../src/builtin/snarf.m4"
28 
29 /* End of snarf.m4 */
30 #line 1 "io.bi"
31 /* This file is part of Mailfromd.             -*- c -*-
32    Copyright (C) 2006-2021 Sergey Poznyakoff
33 
34    This program is free software; you can redistribute it and/or modify
35    it under the terms of the GNU General Public License as published by
36    the Free Software Foundation; either version 3, or (at your option)
37    any later version.
38 
39    This program is distributed in the hope that it will be useful,
40    but WITHOUT ANY WARRANTY; without even the implied warranty of
41    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
42    GNU General Public License for more details.
43 
44    You should have received a copy of the GNU General Public License
45    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
46 
47 
48 
49 #include <mflib/status.h>
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #include <sys/wait.h>
53 #include "global.h"
54 #include "msg.h"
55 
56 static size_t nstreams = MAX_IOSTREAMS;
57 
58 static struct mu_cfg_param io_cfg_param[] = {
59 	{ "max-streams", mu_c_size, &nstreams, 0, NULL,
60 	  N_("Maximum number of stream descriptors.") },
61 	{ NULL }
62 };
63 
64 struct io_stream {
65 	char *name;
66 	mu_locker_t lock;
67 	int fd[2];
68 	pid_t pid;
69 	char *buf;
70 	size_t bufsize;
71 	int (*shutdown)(struct io_stream *, int what);
72 	void (*cleanup)(void*);
73 	void *cleanup_data;
74 	char *delim;
75 };
76 
77 #define IFD(s) ((s).fd[0])
78 #define OFD(s) ((s).fd[1] == -1 ? (s).fd[0] : (s).fd[1])
79 
80 static void
flush_stream(struct io_stream * str)81 flush_stream(struct io_stream *str)
82 {
83 	/*FIXME*/
84 }
85 
86 static void
close_stream(struct io_stream * str)87 close_stream(struct io_stream *str)
88 {
89 	if (OFD(*str) == -1)
90 		return;
91 	flush_stream(str);
92 	close(OFD(*str));
93 	if (IFD(*str) != -1)
94 		close(IFD(*str));
95 	if (str->pid) {
96 		int status;
97 		waitpid(str->pid, &status, 0);
98 	}
99 	str->fd[0] = -1;
100 	str->fd[1] = -1;
101 	str->pid = 0;
102 	if (str->cleanup)
103 		str->cleanup(str->cleanup_data);
104 	str->cleanup = NULL;
105 	str->cleanup_data = NULL;
106 	if (str->name) {
107 		free(str->name);
108 		str->name = NULL;
109 	}
110 	if (str->delim) {
111 		free(str->delim);
112 		str->delim = NULL;
113 	}
114 }
115 
116 /* Read bytes from the stream STR into its buffer, until
117    DELIM is encountered. Return number of bytes read. */
118 static int
read_stream_delim(struct io_stream * str,char * delim)119 read_stream_delim(struct io_stream *str, char *delim)
120 {
121 	int fd = IFD(*str);
122 	size_t i = 0;
123 	int rc;
124 	size_t delim_len = strlen(delim);
125 
126 	for (;;) {
127 		if (str->bufsize == i) {
128 			if (str->bufsize == 0)
129 				str->bufsize = 16;
130 			str->buf = mu_2nrealloc(str->buf, &str->bufsize,
131 					      sizeof str->buf[1]);
132 		}
133 		rc = read(fd, str->buf + i, 1);
134 		if (rc == -1)
135 			return -1;
136 		else if (rc == 0)
137 			return 0;
138 		i++;
139 		if (i >= delim_len &&
140 		    memcmp(str->buf + i - delim_len, delim, delim_len) == 0) {
141 			str->buf[i - delim_len] = 0;
142 			break;
143 		}
144 	}
145 	return i;
146 }
147 
148 #define REDIRECT_STDIN_P(f) ((f) & (O_WRONLY|O_RDWR))
149 #define REDIRECT_STDOUT_P(f) (!((f) & O_WRONLY))
150 
151 #define STDERR_SHUT        0
152 #define STDERR_NULL        1
153 #define STDERR_LOG         2
154 #define STDERR_FILE        3
155 #define STDERR_FILE_APPEND 4
156 
157 #define LOG_TAG_PFX "mailfromd:"
158 #define LOG_TAG_PFX_LEN (sizeof(LOG_TAG_PFX)-1)
159 
160 static void
stderr_to_log(char * arg,const char * cmd)161 stderr_to_log(char *arg, const char *cmd)
162 {
163 	int p[2];
164 	pid_t pid;
165 
166 	if (pipe(p)) {
167 		mu_error(_("pipe failed: %s"), mu_strerror(errno));
168 		close(2);
169 		return;
170 	}
171 
172 	pid = fork();
173 
174 	if (pid == (pid_t) -1) {
175 		mu_error(_("fork failed: %s"), mu_strerror(errno));
176 		close(p[0]);
177 		close(p[1]);
178 		close(2);
179 		return;
180 	}
181 
182 	/* Child */
183 	if (pid == 0) {
184 		FILE *fp;
185 		fd_set fdset;
186 		size_t len;
187 		char buf[1024];
188 		char *tag;
189 		int fac = mu_log_facility, pri = LOG_ERR;
190 
191 		if (arg) {
192 			char *p = strchr(arg, '.');
193 
194 			if (p)
195 				*p++ = 0;
196 			if (mu_string_to_syslog_facility(arg, &fac)) {
197 				mu_error(_("unknown syslog facility (%s), "
198 					   "redirecting stderr to %s"),
199 					 arg,
200 					 mu_syslog_facility_to_string(fac));
201 			}
202 
203 			if (p && mu_string_to_syslog_priority(p, &pri)) {
204 				mu_error(_("unknown syslog priority (%s), "
205 					   "redirecting stderr to %s"),
206 					 arg,
207 					 mu_syslog_priority_to_string(pri));
208 			}
209 		}
210 
211 #line 180 "io.bi"
212 
213 #line 180
214 mu_debug(debug_handle, MU_DEBUG_TRACE2,("redirecting stderr to syslog %s.%s",
215 		           mu_syslog_facility_to_string(fac),
216 		           mu_syslog_priority_to_string(pri)));
217 #line 184
218 
219 		len = strcspn(cmd, " \t");
220 		tag = malloc(LOG_TAG_PFX_LEN + len + 1);
221 		if (!tag)
222 			tag = (char*) cmd;
223 		else {
224 			strcpy(tag, LOG_TAG_PFX);
225 			memcpy(tag + LOG_TAG_PFX_LEN, cmd, len);
226 			tag[LOG_TAG_PFX_LEN + len] = 0;
227 		}
228 		mf_proctitle_format("%s redirector", cmd);
229 
230 		FD_ZERO(&fdset);
231 		FD_SET(p[0], &fdset);
232 		logger_fdset(&fdset);
233 		close_fds_except(&fdset);
234 
235 		fp = fdopen(p[0], "r");
236 		logger_open();
237 		while (fgets(buf, sizeof(buf), fp))
238 			syslog(pri, "%s", buf);
239 		exit(0);
240 	}
241 
242 	/* Parent */
243 	close(p[0]);
244 	dup2(p[1], 2);
245 	close(p[1]);
246 }
247 
248 static void
stderr_handler(int mode,char * arg,const char * cmd)249 stderr_handler(int mode, char *arg, const char *cmd)
250 {
251 	int fd;
252 	int append = O_TRUNC;
253 
254 	switch (mode) {
255 	case STDERR_SHUT:
256 		close(2);
257 		break;
258 
259 	case STDERR_NULL:
260 		arg = "/dev/null";
261 	case STDERR_FILE_APPEND:
262 		append = O_APPEND;
263 	case STDERR_FILE:
264 		if (!arg || !*arg) {
265 			close(2);
266 			break;
267 		}
268 
269 #line 234
270 
271 #line 234
272 mu_debug(debug_handle, MU_DEBUG_TRACE2,("redirecting stderr to %s", arg));
273 		fd = open(arg, O_CREAT|O_WRONLY|append, 0644);
274 		if (fd < 0) {
275 			mu_error(_("cannot open file %s for appending: %s"),
276 				 arg, mu_strerror(errno));
277 			close(2);
278 			return;
279 		}
280 		if (fd != 2) {
281 			dup2(fd, 2);
282 			close(fd);
283 		}
284 		break;
285 
286 	case STDERR_LOG:
287 		stderr_to_log(arg, cmd);
288 	}
289 }
290 
291 static void
parse_stderr_redirect(const char ** pcmd,int * perr,char ** parg)292 parse_stderr_redirect(const char **pcmd, int *perr, char **parg)
293 {
294 	int err;
295 	size_t len;
296 	char *arg;
297 	const char *cmdline = *pcmd;
298 
299 	while (*cmdline && mu_isspace(*cmdline))
300 		cmdline++;
301 	if (strncmp(cmdline, "2>file:", 7) == 0) {
302 		cmdline += 7;
303 		err = STDERR_FILE;
304 	} else if (strncmp(cmdline, "2>>file:", 8) == 0) {
305 		cmdline += 8;
306 		err = STDERR_FILE_APPEND;
307 	} else if (strncmp(cmdline, "2>null:", 7) == 0) {
308 		cmdline += 7;
309 		err = STDERR_NULL;
310 	} else if (strncmp(cmdline, "2>syslog:", 9) == 0) {
311 		cmdline += 9;
312 		err = STDERR_LOG;
313 	} else
314 		return;
315 
316 	len = strcspn(cmdline, " \t");
317 	if (len > 0 && cmdline[len-1] == 0)
318 		return;
319 	if (len == 0)
320 		arg = NULL;
321 	else {
322 		arg = malloc(len + 1);
323 		if (!arg)
324 			return;
325 		memcpy(arg, cmdline, len);
326 		arg[len] = 0;
327 	}
328 
329 	*pcmd = cmdline + len;
330 	*perr = err;
331 	*parg = arg;
332 }
333 
334 
335 static int
open_program_stream_ioe(eval_environ_t env,struct io_stream * str,const char * cmdline,int flags,int ioe[2])336 open_program_stream_ioe(eval_environ_t env,
337 			struct io_stream *str, const char *cmdline,
338 			int flags,
339 			int ioe[2])
340 {
341 	int rightp[2], leftp[2];
342 	int rc = 0;
343 	pid_t pid;
344 	int err = STDERR_SHUT;
345 	char *arg = NULL;
346 	struct mu_wordsplit ws;
347 
348 	parse_stderr_redirect(&cmdline, &err, &arg);
349 	while (*cmdline && (*cmdline == ' ' || *cmdline == '\t'))
350 		cmdline++;
351 
352 	if (REDIRECT_STDIN_P(flags)) {
353 		if (pipe(leftp)) {
354 			mu_diag_funcall(MU_DIAG_ERROR, "pipe", "leftp",
355 					errno);
356 			free(arg);
357 			(
358 #line 319
359 	env_throw_bi(env, mfe_failure, NULL, "pipe failed")
360 #line 319
361 );
362 		}
363 	}
364 
365 	if (REDIRECT_STDOUT_P(flags)) {
366 		if (pipe(rightp)) {
367 			mu_diag_funcall(MU_DIAG_ERROR, "pipe", "rightp",
368 					errno);
369 			free(arg);
370 			if (REDIRECT_STDIN_P(flags)) {
371 				close(leftp[0]);
372 				close(leftp[1]);
373 			}
374 		}
375 	}
376 
377 	switch (pid = fork()) {
378 		/* The child branch.  */
379 	case 0:
380 		/* attach the pipes */
381 
382 		/* Right-end */
383 		if (REDIRECT_STDOUT_P(flags)) {
384 			if (rightp[1] != 1)
385 				dup2(rightp[1], 1);
386 		} else if (ioe && ioe[1] != -1 && ioe[1] != 1) {
387 			dup2(ioe[1], 1);
388 		}
389 
390 		/* Left-end */
391 		if (REDIRECT_STDIN_P(flags)) {
392 			if (leftp[0] != 0)
393 				dup2(leftp[0], 0);
394 		} else if (ioe && ioe[0] != -1 && ioe[0] != 0) {
395 			dup2(ioe[0], 0);
396 		}
397 
398 		if (ioe && ioe[2] != -1 && ioe[2] != 2)
399 			dup2(ioe[2], 2);
400 		else
401 			stderr_handler(err, arg, cmdline);
402 
403 		/* Close unneeded descriptors */
404 		close_fds_above(2);
405 
406 
407 #line 364
408 
409 #line 364
410 mu_debug(debug_handle, MU_DEBUG_TRACE3,("running %s", cmdline));
411 		if (mu_wordsplit(cmdline, &ws,
412 				 MU_WRDSF_DEFFLAGS & ~MU_WRDSF_CESCAPES)) {
413 			mu_error(_("cannot parse command line %s: %s"),
414 				 cmdline, mu_wordsplit_strerror(&ws));
415 			exit(127);
416 		}
417 		execvp(ws.ws_wordv[0], ws.ws_wordv);
418 		mu_error(_("cannot run %s: %s"),
419 			 cmdline, mu_strerror(errno));
420 		exit(127);
421 		/********************/
422 
423 		/* Parent branches: */
424 	case -1:
425 		/* Fork has failed */
426 		/* Restore things */
427 		rc = errno;
428 		if (REDIRECT_STDOUT_P(flags)) {
429 			close(rightp[0]);
430 			close(rightp[1]);
431 		}
432 		if (REDIRECT_STDIN_P(flags)) {
433 			close(leftp[0]);
434 			close(leftp[1]);
435 		}
436 		break;
437 
438 	default:
439 		str->pid = pid;
440 		if (REDIRECT_STDOUT_P(flags)) {
441 			str->fd[0] = rightp[0];
442 			close(rightp[1]);
443 		} else
444 			str->fd[0] = -1;
445 
446 		if (REDIRECT_STDIN_P(flags)) {
447 			str->fd[1] = leftp[1];
448 			close(leftp[0]);
449 		} else
450 			str->fd[1] = -1;
451 	}
452 	free(arg);
453 	return rc;
454 }
455 
456 static int
open_program_stream(eval_environ_t env,struct io_stream * str,const char * cmdline,int flags)457 open_program_stream(eval_environ_t env,
458 		    struct io_stream *str, const char *cmdline,
459 		    int flags)
460 {
461 	return open_program_stream_ioe(env, str, cmdline, flags, NULL);
462 }
463 
464 static int
open_file_stream(eval_environ_t env,struct io_stream * str,const char * file,int flags)465 open_file_stream(eval_environ_t env,
466 		 struct io_stream *str, const char *file, int flags)
467 {
468 	str->fd[0] = open(file, flags, 0644); /* FIXME: mode? */
469 	if (str->fd[0] == -1)
470 		return errno;
471 	return 0;
472 }
473 
474 
475 
476 static int
open_parsed_inet_stream(eval_environ_t env,struct io_stream * str,const char * cstr,char * proto,char * port,char * path,int flags)477 open_parsed_inet_stream(eval_environ_t env,
478 			struct io_stream *str,
479 			const char *cstr,
480 			char *proto, char *port, char *path,
481 			int flags)
482 {
483 	union {
484 		struct sockaddr sa;
485 		struct sockaddr_in s_in;
486 		struct sockaddr_un s_un;
487 #ifdef GACOPYZ_IPV6
488 		struct sockaddr_in6 s_in6;
489 #endif
490 	} addr;
491 
492 	socklen_t socklen;
493 	int fd;
494 	int rc;
495 
496 	if (!proto
497 	    || strcmp(proto, "unix") == 0 || strcmp(proto, "local") == 0) {
498 		struct stat st;
499 
500 			if (!(port == NULL))
501 #line 454
502 		(
503 #line 454
504 	env_throw_bi(env, mfe_failure, NULL, _("invalid connection type: %s; "
505 			    "port is meaningless for UNIX sockets"),cstr)
506 #line 454
507 )
508 #line 458
509 ;
510 
511 			if (!(strlen(path) <= sizeof addr.s_un.sun_path))
512 #line 460
513 		(
514 #line 460
515 	env_throw_bi(env, mfe_range, NULL, _("%s: UNIX socket name too long"),path)
516 #line 460
517 )
518 #line 463
519 ;
520 
521 		addr.sa.sa_family = PF_UNIX;
522 		socklen = sizeof(addr.s_un);
523 		strcpy(addr.s_un.sun_path, path);
524 
525 		if (stat(path, &st)) {
526 			(
527 #line 470
528 	env_throw_bi(env, mfe_failure, NULL, _("%s: cannot stat socket: %s"),path,strerror(errno))
529 #line 470
530 );
531 #line 473
532 		} else {
533 			/* FIXME: Check permissions? */
534 				if (!(S_ISSOCK(st.st_mode)))
535 #line 475
536 		(
537 #line 475
538 	env_throw_bi(env, mfe_failure, NULL, _("%s: not a socket"),path)
539 #line 475
540 )
541 #line 478
542 ;
543 		}
544 
545 	} else if (strcmp(proto, "inet") == 0) {
546 		short pnum;
547 		long num;
548 		char *p;
549 
550 		addr.sa.sa_family = PF_INET;
551 		socklen = sizeof(addr.s_in);
552 
553 			if (!(port != NULL))
554 #line 489
555 		(
556 #line 489
557 	env_throw_bi(env, mfe_failure, NULL, _("invalid connection type: %s; "
558 			    "missing port number"),cstr)
559 #line 489
560 )
561 #line 493
562 ;
563 
564 		num = pnum = strtol(port, &p, 0);
565 		if (*p == 0) {
566 				if (!(num == pnum))
567 #line 497
568 		(
569 #line 497
570 	env_throw_bi(env, mfe_range, NULL, _("invalid connection type: "
571 				    "%s; bad port number"),cstr)
572 #line 497
573 )
574 #line 501
575 ;
576 			pnum = htons(pnum);
577 		} else {
578 			struct servent *sp = getservbyname(port, "tcp");
579 
580 				if (!(sp != NULL))
581 #line 506
582 		(
583 #line 506
584 	env_throw_bi(env, mfe_failure, NULL, _("invalid connection type: "
585 				    "%s; unknown port name"),cstr)
586 #line 506
587 )
588 #line 510
589 ;
590 			pnum = sp->s_port;
591 		}
592 
593 		if (!path)
594 			addr.s_in.sin_addr.s_addr = INADDR_ANY;
595 		else {
596 			struct hostent *hp = gethostbyname(path);
597 				if (!(hp != NULL))
598 #line 518
599 		(
600 #line 518
601 	env_throw_bi(env, mfe_failure, NULL, _("unknown host name %s"),path)
602 #line 518
603 )
604 #line 521
605 ;
606 			addr.sa.sa_family = hp->h_addrtype;
607 			switch (hp->h_addrtype) {
608 			case AF_INET:
609 				memmove(&addr.s_in.sin_addr, hp->h_addr, 4);
610 				addr.s_in.sin_port = pnum;
611 				break;
612 
613 			default:
614 				(
615 #line 530
616 	env_throw_bi(env, mfe_range, NULL, _("invalid connection type: "
617 					   "%s; unsupported address family"),cstr)
618 #line 530
619 );
620 #line 534
621 			}
622 		}
623 #ifdef GACOPYZ_IPV6
624 	} else if (strcmp(proto, "inet6") == 0) {
625 		struct addrinfo hints;
626 		struct addrinfo *res;
627 
628 			if (!(port != NULL))
629 #line 541
630 		(
631 #line 541
632 	env_throw_bi(env, mfe_failure, NULL, _("invalid connection type: %s; "
633 			    "missing port number"),cstr)
634 #line 541
635 )
636 #line 545
637 ;
638 
639 		memset(&hints, 0, sizeof(hints));
640 		hints.ai_family = AF_INET6;
641 		hints.ai_socktype = SOCK_STREAM;
642 		if (!path)
643 			hints.ai_flags |= AI_PASSIVE;
644 
645 		rc = getaddrinfo(path, port, &hints, &res);
646 
647 		switch (rc) {
648 		case 0:
649 			break;
650 
651 		case EAI_SYSTEM:
652 			(
653 #line 560
654 	env_throw_bi(env, mfe_failure, NULL, _("%s:%s: cannot parse address: %s"),path,port,strerror(errno))
655 #line 560
656 );
657 #line 563
658 
659 		case EAI_BADFLAGS:
660 		case EAI_SOCKTYPE:
661 			(
662 #line 566
663 	env_throw_bi(env, mfe_failure, NULL, _("%s:%d: internal error converting %s:%s"),__FILE__,__LINE__,path,port)
664 #line 566
665 );
666 #line 569
667 
668 		case EAI_MEMORY:
669 			mu_alloc_die();
670 
671 		default:
672 			(
673 #line 574
674 	env_throw_bi(env, mfe_failure, NULL, "%s:%s: %s",path,port,gai_strerror(rc))
675 #line 574
676 );
677 #line 577
678 		}
679 
680 		socklen = res->ai_addrlen;
681 		if (socklen > sizeof(addr)) {
682 			freeaddrinfo(res);
683 			(
684 #line 582
685 	env_throw_bi(env, mfe_failure, NULL, _("%s:%s: address length too big (%lu)"),path,port,(unsigned long) socklen)
686 #line 582
687 );
688 #line 586
689 		}
690 		memcpy(&addr, res->ai_addr, res->ai_addrlen);
691 		freeaddrinfo(res);
692 #endif
693 	} else {
694 		(
695 #line 591
696 	env_throw_bi(env, mfe_range, NULL, _("unsupported protocol: %s"),proto)
697 #line 591
698 );
699 #line 594
700 	}
701 
702 	fd = socket(addr.sa.sa_family, SOCK_STREAM, 0);
703 		if (!(fd != -1))
704 #line 597
705 		(
706 #line 597
707 	env_throw_bi(env, mfe_failure, NULL, _("unable to create new socket: %s"),strerror(errno))
708 #line 597
709 )
710 #line 600
711 ;
712 
713 	/* FIXME: Bind to the source ? */
714 
715 	rc = connect(fd, &addr.sa, socklen);
716 	if (rc) {
717 		close(fd);
718 		(
719 #line 607
720 	env_throw_bi(env, mfe_failure, NULL, _("cannot connect to %s: %s"),cstr,strerror(errno))
721 #line 607
722 );
723 #line 610
724 	}
725 
726 	str->fd[0] = fd;
727 	return 0;
728 }
729 
730 static int
shutdown_inet_stream(struct io_stream * str,int how)731 shutdown_inet_stream(struct io_stream *str, int how)
732 {
733 	switch (how) {
734 	case 0:
735 		how = SHUT_RD;
736 		break;
737 
738 	case 1:
739 		how = SHUT_WR;
740 		break;
741 
742 	case 2:
743 		how = SHUT_RDWR;
744 		break;
745 
746 	default:
747 		return EINVAL;
748 	}
749 	if (shutdown(str->fd[0], how))
750 		return errno;
751 	return 0;
752 }
753 
754 static int
open_inet_stream(eval_environ_t env,struct io_stream * str,const char * addr,int flags)755 open_inet_stream(eval_environ_t env,
756 		 struct io_stream *str, const char *addr, int flags)
757 {
758 	int rc;
759 	char *proto, *port, *path;
760 
761 	if (gacopyz_parse_connection(addr, &proto, &port, &path)
762 	    != MI_SUCCESS)
763 		rc = ENOMEM; /* FIXME: or EINVAL? */
764 	else {
765 		rc = open_parsed_inet_stream(env,
766 					     str, addr,
767 					     proto, port, path, flags);
768 		str->shutdown = shutdown_inet_stream;
769 		free(proto);
770 		free(port);
771 		free(path);
772 	}
773 	return rc;
774 }
775 
776 
777 static void *
alloc_streams()778 alloc_streams()
779 {
780 	struct io_stream *p, *stab = mu_calloc(nstreams, sizeof *stab);
781 	for (p = stab; p < stab + nstreams; p++)
782 		p->fd[0] = p->fd[1] = -1;
783 	return stab;
784 }
785 
786 static void
destroy_streams(void * data)787 destroy_streams(void *data)
788 {
789 	struct io_stream *stab = data;
790 	struct io_stream *p;
791 	for (p = stab; p < stab + nstreams; p++) {
792 		close_stream(p);
793 		free(p->buf);
794 	}
795 	free(stab);
796 }
797 
798 
799 #line 684
800 
801 #line 684
802 static int IO_id;
803 #line 684 "io.bi"
804 
805 
806 int
_bi_io_fd(eval_environ_t env,int fd,int what)807 _bi_io_fd(eval_environ_t env, int fd, int what)
808 {
809 	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
810 	int descr;
811 
812 		if (!(fd >= 0 && fd < nstreams && what>=0 && what<=1))
813 #line 692
814 		(
815 #line 692
816 	env_throw_bi(env, mfe_range, NULL, _("invalid file descriptor"))
817 #line 692
818 )
819 #line 694
820 ;
821 	descr = what == 0 ? IFD(iotab[fd]) : OFD(iotab[fd]);
822 		if (!(descr >= 0))
823 #line 696
824 		(
825 #line 696
826 	env_throw_bi(env, mfe_range, NULL, _("invalid file descriptor"))
827 #line 696
828 )
829 #line 698
830 ;
831 	return descr;
832 }
833 
834 
835 void
836 #line 703
bi_open(eval_environ_t env)837 bi_open(eval_environ_t env)
838 #line 703
839 
840 #line 703
841 
842 #line 703 "io.bi"
843 {
844 #line 703
845 
846 #line 703
847 
848 #line 703
849 
850 #line 703
851 char *  name;
852 #line 703
853 
854 #line 703
855 get_string_arg(env, 0, &name);
856 #line 703
857 
858 #line 703
859 
860 #line 703
861         adjust_stack(env, 1);
862 #line 703
863 
864 #line 703
865 
866 #line 703
867 	if (builtin_module_trace(BUILTIN_IDX_io))
868 #line 703
869 		prog_trace(env, "open %s",name);;
870 #line 703
871 
872 {
873 	int i, rc;
874 	int flags = 0;
875 	int (*opf)(eval_environ_t env,
876 		   struct io_stream *, const char *, int) = open_file_stream;
877 	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
878 
879 	for (i = 0; i < nstreams; i++) {
880 		if (iotab[i].fd[0] == -1)
881 			break;
882 	}
883 		if (!(i < nstreams))
884 #line 715
885 		(
886 #line 715
887 	env_throw_bi(env, mfe_failure, "open", _("no more files available"))
888 #line 715
889 )
890 #line 717
891 ;
892 
893 
894 #line 719
895 
896 #line 719
897 mu_debug(debug_handle, MU_DEBUG_TRACE1,("opening stream %s", name));
898 	iotab[i].name = mu_strdup(name);
899 	iotab[i].delim = NULL;
900 	if (*name == '>') {
901 		flags |= O_RDWR|O_CREAT;
902 		name++;
903 		if (*name == '>') {
904 			flags |= O_APPEND;
905 			name++;
906 		} else
907 			flags |= O_TRUNC;
908 	} else if (*name == '|') {
909 		opf = open_program_stream;
910 		flags = O_WRONLY;
911 		name++;
912 		if (*name == '&') {
913 			flags = O_RDWR;
914 			name++;
915 		} else if (*name == '<') {
916 			flags = O_RDONLY;
917 			name++;
918 		}
919 	} else if (*name == '@') {
920 		name++;
921 		opf = open_inet_stream;
922 		flags = O_RDWR;
923 	} else
924 		flags = O_RDONLY;
925 
926 	for (;*name && mu_isspace(*name); name++)
927 		;
928 
929 	rc = opf(env, &iotab[i], name, flags);
930 
931 		if (!(rc == 0))
932 #line 753
933 		(
934 #line 753
935 	env_throw_bi(env, mfe_failure, "open", _("cannot open stream %s: %s"),name,mu_strerror(rc))
936 #line 753
937 )
938 #line 756
939 ;
940 
941 #line 757
942 
943 #line 757
944 mu_debug(debug_handle, MU_DEBUG_TRACE1,("open(%s) = %d", name, i));
945 
946 #line 758
947 do {
948 #line 758
949   push(env, (STKVAL)(mft_number)(i));
950 #line 758
951   goto endlab;
952 #line 758
953 } while (0);
954 }
955 endlab:
956 #line 760
957         env_function_cleanup_flush(env, NULL);
958 #line 760
959 	return;
960 #line 760
961 }
962 
963 void
964 #line 762
bi_spawn(eval_environ_t env)965 bi_spawn(eval_environ_t env)
966 #line 762
967 
968 #line 762
969 
970 #line 762 "io.bi"
971 {
972 #line 762
973 
974 #line 762
975 
976 #line 762
977 long __bi_argcnt;
978 #line 762
979 char *  name;
980 #line 762
981         long  fin;
982 #line 762
983         long  fout;
984 #line 762
985         long  ferr;
986 #line 762
987 
988 #line 762
989 get_string_arg(env, 1, &name);
990 #line 762
991         get_numeric_arg(env, 2, &fin);
992 #line 762
993         get_numeric_arg(env, 3, &fout);
994 #line 762
995         get_numeric_arg(env, 4, &ferr);
996 #line 762
997 
998 #line 762
999 get_numeric_arg(env, 0, &__bi_argcnt);
1000 #line 762
1001         adjust_stack(env, __bi_argcnt + 1);
1002 #line 762
1003 
1004 #line 762
1005 
1006 #line 762
1007 	if (builtin_module_trace(BUILTIN_IDX_io))
1008 #line 762
1009 		prog_trace(env, "spawn %s %lu %lu %lu",name, ((__bi_argcnt > 1) ? fin : 0), ((__bi_argcnt > 2) ? fout : 0), ((__bi_argcnt > 3) ? ferr : 0));;
1010 
1011 {
1012 	int i, rc;
1013 	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
1014 	int ioe[3];
1015 	int flags;
1016 
1017 	for (i = 0; i < nstreams; i++) {
1018 		if (iotab[i].fd[0] == -1)
1019 			break;
1020 	}
1021 		if (!(i < nstreams))
1022 #line 774
1023 		(
1024 #line 774
1025 	env_throw_bi(env, mfe_failure, "spawn", _("no more files available"))
1026 #line 774
1027 )
1028 #line 776
1029 ;
1030 
1031 
1032 #line 778
1033 
1034 #line 778
1035 mu_debug(debug_handle, MU_DEBUG_TRACE1,("spawning %s", name));
1036 	iotab[i].name = mu_strdup(name);
1037 	iotab[i].delim = NULL;
1038 
1039 	flags = O_WRONLY;
1040 	if (*name == '|')
1041 		name++;
1042 	if (*name == '&') {
1043 		flags = O_RDWR;
1044 		name++;
1045 	} else if (*name == '<') {
1046 		flags = O_RDONLY;
1047 		name++;
1048 	}
1049 
1050 	for (;*name && mu_isspace(*name); name++)
1051 		;
1052 
1053 	if ((__bi_argcnt > 1))
1054 		ioe[0] = _bi_io_fd(env, ((__bi_argcnt > 1) ? fin : 0), 0);
1055 	else
1056 		ioe[0] = -1;
1057 	if ((__bi_argcnt > 2))
1058 		ioe[1] = _bi_io_fd(env, ((__bi_argcnt > 2) ? fout : 0), 1);
1059 	else
1060 		ioe[1] = -1;
1061 	if ((__bi_argcnt > 3))
1062 		ioe[2] = _bi_io_fd(env, ((__bi_argcnt > 2) ? fout : 0), 1);
1063 	else
1064 		ioe[2] = -1;
1065 
1066 	rc = open_program_stream_ioe(env, &iotab[i], name, flags, ioe);
1067 
1068 		if (!(rc == 0))
1069 #line 811
1070 		(
1071 #line 811
1072 	env_throw_bi(env, mfe_failure, "spawn", _("cannot open stream %s: %s"),name,mu_strerror(rc))
1073 #line 811
1074 )
1075 #line 814
1076 ;
1077 
1078 #line 815
1079 
1080 #line 815
1081 mu_debug(debug_handle, MU_DEBUG_TRACE1,("spawn(%s) = %d", name, i));
1082 
1083 #line 816
1084 do {
1085 #line 816
1086   push(env, (STKVAL)(mft_number)(i));
1087 #line 816
1088   goto endlab;
1089 #line 816
1090 } while (0);
1091 
1092 }
1093 endlab:
1094 #line 819
1095         env_function_cleanup_flush(env, NULL);
1096 #line 819
1097 	return;
1098 #line 819
1099 }
1100 
1101 
1102 void
1103 #line 822
bi_tempfile(eval_environ_t env)1104 bi_tempfile(eval_environ_t env)
1105 #line 822
1106 
1107 #line 822
1108 
1109 #line 822 "io.bi"
1110 {
1111 #line 822
1112 
1113 #line 822
1114 
1115 #line 822
1116 long __bi_argcnt;
1117 #line 822
1118 char * MFL_DATASEG tempdir;
1119 #line 822
1120 
1121 #line 822
1122 get_string_arg(env, 1, &tempdir);
1123 #line 822
1124 
1125 #line 822
1126 get_numeric_arg(env, 0, &__bi_argcnt);
1127 #line 822
1128         adjust_stack(env, __bi_argcnt + 1);
1129 #line 822
1130 
1131 #line 822
1132 
1133 #line 822
1134 	if (builtin_module_trace(BUILTIN_IDX_io))
1135 #line 822
1136 		prog_trace(env, "tempfile %s",((__bi_argcnt > 0) ? tempdir : ""));;
1137 #line 822
1138 
1139 {
1140 	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
1141 	int i;
1142 	char *dir = ((__bi_argcnt > 0) ? tempdir : "/tmp");
1143 	size_t dirlen = strlen(dir);
1144 	mode_t u;
1145 	int fd;
1146 	char *template;
1147 #define PATTERN "mfdXXXXXX"
1148 
1149 	for (i = 0; i < nstreams; i++) {
1150 		if (iotab[i].fd[0] == -1)
1151 			break;
1152 	}
1153 		if (!(i < nstreams))
1154 #line 837
1155 		(
1156 #line 837
1157 	env_throw_bi(env, mfe_failure, "tempfile", _("no more files available"))
1158 #line 837
1159 )
1160 #line 839
1161 ;
1162 
1163 
1164 	while (dirlen > 0 && dir[dirlen-1] == '/')
1165 		dirlen--;
1166 
1167 	template = mf_c_val(heap_tempspace(env, (dirlen ? dirlen + 1 : 0) +
1168 #line 845
1169 				      sizeof(PATTERN)), ptr);
1170 #line 847
1171 	if (dirlen) {
1172 		memcpy(template, dir, dirlen);
1173 		template[dirlen++] = '/';
1174 	}
1175 	strcpy(template + dirlen, PATTERN);
1176 	u = umask(077);
1177 	fd = mkstemp(template);
1178 	umask(u);
1179 		if (!(fd >= 0))
1180 #line 855
1181 		(
1182 #line 855
1183 	env_throw_bi(env, mfe_failure, "tempfile", "mkstemp failed: %s",mu_strerror(errno))
1184 #line 855
1185 )
1186 #line 858
1187 ;
1188 	unlink(template);
1189 
1190 	iotab[i].fd[0] = fd;
1191 
1192 
1193 #line 863
1194 do {
1195 #line 863
1196   push(env, (STKVAL)(mft_number)(i));
1197 #line 863
1198   goto endlab;
1199 #line 863
1200 } while (0);
1201 #undef PATTERN
1202 }
1203 endlab:
1204 #line 866
1205         env_function_cleanup_flush(env, NULL);
1206 #line 866
1207 	return;
1208 #line 866
1209 }
1210 
1211 void
1212 #line 868
bi_close(eval_environ_t env)1213 bi_close(eval_environ_t env)
1214 #line 868
1215 
1216 #line 868
1217 
1218 #line 868 "io.bi"
1219 {
1220 #line 868
1221 
1222 #line 868
1223 
1224 #line 868
1225 
1226 #line 868
1227 long  fd;
1228 #line 868
1229 
1230 #line 868
1231 get_numeric_arg(env, 0, &fd);
1232 #line 868
1233 
1234 #line 868
1235 
1236 #line 868
1237         adjust_stack(env, 1);
1238 #line 868
1239 
1240 #line 868
1241 
1242 #line 868
1243 	if (builtin_module_trace(BUILTIN_IDX_io))
1244 #line 868
1245 		prog_trace(env, "close %lu",fd);;
1246 #line 868
1247 
1248 {
1249 	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
1250 
1251 		if (!(fd >= 0 && fd < nstreams))
1252 #line 872
1253 		(
1254 #line 872
1255 	env_throw_bi(env, mfe_range, "close", _("invalid file descriptor"))
1256 #line 872
1257 )
1258 #line 874
1259 ;
1260 	close_stream(&iotab[fd]);
1261 }
1262 
1263 #line 877
1264         env_function_cleanup_flush(env, NULL);
1265 #line 877
1266 	return;
1267 #line 877
1268 }
1269 
1270 static struct builtin_const_trans shutdown_modes[] = {
1271 	{ _MFL_SHUT_RD, SHUT_RD },
1272 	{ _MFL_SHUT_WR, SHUT_WR },
1273 	{ _MFL_SHUT_RDWR, SHUT_RDWR }
1274 };
1275 
1276 void
1277 #line 885
bi_shutdown(eval_environ_t env)1278 bi_shutdown(eval_environ_t env)
1279 #line 885
1280 
1281 #line 885
1282 
1283 #line 885 "io.bi"
1284 {
1285 #line 885
1286 
1287 #line 885
1288 
1289 #line 885
1290 
1291 #line 885
1292 long  fd;
1293 #line 885
1294         long  how;
1295 #line 885
1296 
1297 #line 885
1298 get_numeric_arg(env, 0, &fd);
1299 #line 885
1300         get_numeric_arg(env, 1, &how);
1301 #line 885
1302 
1303 #line 885
1304 
1305 #line 885
1306         adjust_stack(env, 2);
1307 #line 885
1308 
1309 #line 885
1310 
1311 #line 885
1312 	if (builtin_module_trace(BUILTIN_IDX_io))
1313 #line 885
1314 		prog_trace(env, "shutdown %lu %lu",fd, how);;
1315 #line 885
1316 
1317 {
1318 	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
1319 	struct io_stream *ioptr;
1320 	int mode;
1321 
1322 		if (!(fd >= 0 && fd < nstreams))
1323 #line 891
1324 		(
1325 #line 891
1326 	env_throw_bi(env, mfe_range, "shutdown", _("invalid file descriptor"))
1327 #line 891
1328 )
1329 #line 893
1330 ;
1331 		if (!(how >= 0 && how <= 2))
1332 #line 894
1333 		(
1334 #line 894
1335 	env_throw_bi(env, mfe_range, "shutdown", _("invalid file descriptor"))
1336 #line 894
1337 )
1338 #line 896
1339 ;
1340 		if (!(_builtin_const_to_c(shutdown_modes,
1341 #line 897
1342 				      MU_ARRAY_SIZE(shutdown_modes),
1343 #line 897
1344 				      how,
1345 #line 897
1346 				      &mode) == 0))
1347 #line 897
1348 		(
1349 #line 897
1350 	env_throw_bi(env, mfe_failure, "shutdown", "bad shutdown mode")
1351 #line 897
1352 )
1353 #line 902
1354 ;
1355 
1356 	ioptr = &iotab[fd];
1357 	if (ioptr->shutdown) {
1358 		int rc = ioptr->shutdown(ioptr, mode);
1359 			if (!(rc == 0))
1360 #line 907
1361 		(
1362 #line 907
1363 	env_throw_bi(env, mfe_io, "shutdown", "shutdown failed: %s",mu_strerror(rc))
1364 #line 907
1365 )
1366 #line 910
1367 ;
1368 	} else if (how == 2)
1369 		close_stream(ioptr);
1370 	else if (ioptr->fd[how]) {
1371 		close(ioptr->fd[how]);
1372 		ioptr->fd[how] = -1;
1373 	}
1374 }
1375 
1376 #line 918
1377         env_function_cleanup_flush(env, NULL);
1378 #line 918
1379 	return;
1380 #line 918
1381 }
1382 
1383 void
1384 #line 920
bi_write(eval_environ_t env)1385 bi_write(eval_environ_t env)
1386 #line 920
1387 
1388 #line 920
1389 
1390 #line 920 "io.bi"
1391 {
1392 #line 920
1393 
1394 #line 920
1395 
1396 #line 920
1397 long __bi_argcnt;
1398 #line 920
1399 long  fd;
1400 #line 920
1401         char *  str;
1402 #line 920
1403         long  n;
1404 #line 920
1405 
1406 #line 920
1407 get_numeric_arg(env, 1, &fd);
1408 #line 920
1409         get_string_arg(env, 2, &str);
1410 #line 920
1411         get_numeric_arg(env, 3, &n);
1412 #line 920
1413 
1414 #line 920
1415 get_numeric_arg(env, 0, &__bi_argcnt);
1416 #line 920
1417         adjust_stack(env, __bi_argcnt + 1);
1418 #line 920
1419 
1420 #line 920
1421 
1422 #line 920
1423 	if (builtin_module_trace(BUILTIN_IDX_io))
1424 #line 920
1425 		prog_trace(env, "write %lu %s %lu",fd, str, ((__bi_argcnt > 2) ? n : 0));;
1426 #line 920
1427 
1428 {
1429 	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
1430 	int rc;
1431 
1432 
1433 #line 925
1434 
1435 #line 925
1436 mu_debug(debug_handle, MU_DEBUG_TRACE1,("writing %s to %lu", str, fd));
1437 		if (!(fd >= 0 && fd < nstreams && OFD(iotab[fd]) != -1))
1438 #line 926
1439 		(
1440 #line 926
1441 	env_throw_bi(env, mfe_range, "write", _("invalid file descriptor"))
1442 #line 926
1443 )
1444 #line 928
1445 ;
1446 	if (!(__bi_argcnt > 2))
1447 		n = strlen (str);
1448 	rc = write(OFD(iotab[fd]), str, n);
1449 		if (!(n == rc))
1450 #line 932
1451 		(
1452 #line 932
1453 	env_throw_bi(env, mfe_io, "write", _("write error on %s: %s"),iotab[fd].name,mu_strerror(errno))
1454 #line 932
1455 )
1456 #line 935
1457 ;
1458 }
1459 
1460 #line 937
1461         env_function_cleanup_flush(env, NULL);
1462 #line 937
1463 	return;
1464 #line 937
1465 }
1466 
1467 
1468 void
1469 #line 940
bi_write_body(eval_environ_t env)1470 bi_write_body(eval_environ_t env)
1471 #line 940
1472 
1473 #line 940
1474 
1475 #line 940 "io.bi"
1476 {
1477 #line 940
1478 
1479 #line 940
1480 
1481 #line 940
1482 
1483 #line 940
1484 long  fd;
1485 #line 940
1486         void *  str;
1487 #line 940
1488         long  n;
1489 #line 940
1490 
1491 #line 940
1492 get_numeric_arg(env, 0, &fd);
1493 #line 940
1494         get_pointer_arg(env, 1, &str);
1495 #line 940
1496         get_numeric_arg(env, 2, &n);
1497 #line 940
1498 
1499 #line 940
1500 
1501 #line 940
1502         adjust_stack(env, 3);
1503 #line 940
1504 
1505 #line 940
1506 
1507 #line 940
1508 	if (builtin_module_trace(BUILTIN_IDX_io))
1509 #line 940
1510 		prog_trace(env, "write_body %lu %p %lu",fd, str, n);;
1511 #line 940
1512 
1513 {
1514 	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
1515 	int rc;
1516 
1517 		if (!(fd >= 0 && fd < nstreams && OFD(iotab[fd]) != -1))
1518 #line 945
1519 		(
1520 #line 945
1521 	env_throw_bi(env, mfe_range, "write_body", _("invalid file descriptor"))
1522 #line 945
1523 )
1524 #line 947
1525 ;
1526 	rc = write(OFD(iotab[fd]), str, n);
1527 		if (!(n == rc))
1528 #line 949
1529 		(
1530 #line 949
1531 	env_throw_bi(env, mfe_io, "write_body", _("write error on %s: %s"),iotab[fd].name,mu_strerror(errno))
1532 #line 949
1533 )
1534 #line 952
1535 ;
1536 }
1537 
1538 #line 954
1539         env_function_cleanup_flush(env, NULL);
1540 #line 954
1541 	return;
1542 #line 954
1543 }
1544 
1545 void
1546 #line 956
bi_read(eval_environ_t env)1547 bi_read(eval_environ_t env)
1548 #line 956
1549 
1550 #line 956
1551 
1552 #line 956 "io.bi"
1553 {
1554 #line 956
1555 
1556 #line 956
1557 
1558 #line 956
1559 
1560 #line 956
1561 long  fd;
1562 #line 956
1563         long  size;
1564 #line 956
1565 
1566 #line 956
1567 get_numeric_arg(env, 0, &fd);
1568 #line 956
1569         get_numeric_arg(env, 1, &size);
1570 #line 956
1571 
1572 #line 956
1573 
1574 #line 956
1575         adjust_stack(env, 2);
1576 #line 956
1577 
1578 #line 956
1579 
1580 #line 956
1581 	if (builtin_module_trace(BUILTIN_IDX_io))
1582 #line 956
1583 		prog_trace(env, "read %lu %lu",fd, size);;
1584 #line 956
1585 
1586 {
1587 	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
1588 	int rc;
1589 	size_t off;
1590 	char *s = (char*) env_data_ref(env, (off = heap_reserve(env, size + 1)));
1591 
1592 		if (!(fd >= 0 && fd < nstreams && IFD(iotab[fd]) != -1))
1593 #line 963
1594 		(
1595 #line 963
1596 	env_throw_bi(env, mfe_range, "read", _("invalid file descriptor"))
1597 #line 963
1598 )
1599 #line 965
1600 ;
1601 
1602 	rc = read(IFD(iotab[fd]), s, size);
1603 	if (rc == 0)
1604 		(
1605 #line 969
1606 	env_throw_bi(env, mfe_eof, "read", _("EOF on %s"),iotab[fd].name)
1607 #line 969
1608 );
1609 #line 971
1610 		if (!(rc == size))
1611 #line 971
1612 		(
1613 #line 971
1614 	env_throw_bi(env, mfe_io, "read", _("read error on %s: %s"),iotab[fd].name,mu_strerror(errno))
1615 #line 971
1616 )
1617 #line 974
1618 ;
1619 	s[size] = 0;
1620 
1621 #line 976
1622 do {
1623 #line 976
1624   push(env, (STKVAL) (mft_size) (off));
1625 #line 976
1626   goto endlab;
1627 #line 976
1628 } while (0);
1629 }
1630 endlab:
1631 #line 978
1632         env_function_cleanup_flush(env, NULL);
1633 #line 978
1634 	return;
1635 #line 978
1636 }
1637 
1638 void
1639 #line 980
bi_rewind(eval_environ_t env)1640 bi_rewind(eval_environ_t env)
1641 #line 980
1642 
1643 #line 980
1644 
1645 #line 980 "io.bi"
1646 {
1647 #line 980
1648 
1649 #line 980
1650 
1651 #line 980
1652 
1653 #line 980
1654 long  fd;
1655 #line 980
1656 
1657 #line 980
1658 get_numeric_arg(env, 0, &fd);
1659 #line 980
1660 
1661 #line 980
1662 
1663 #line 980
1664         adjust_stack(env, 1);
1665 #line 980
1666 
1667 #line 980
1668 
1669 #line 980
1670 	if (builtin_module_trace(BUILTIN_IDX_io))
1671 #line 980
1672 		prog_trace(env, "rewind %lu",fd);;
1673 #line 980
1674 
1675 {
1676 	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
1677 
1678 		if (!(fd >= 0 && fd < nstreams && IFD(iotab[fd]) != -1))
1679 #line 984
1680 		(
1681 #line 984
1682 	env_throw_bi(env, mfe_range, "rewind", _("invalid file descriptor"))
1683 #line 984
1684 )
1685 #line 986
1686 ;
1687 	if (lseek(IFD(iotab[fd]), 0, SEEK_SET) == -1)
1688 		(
1689 #line 988
1690 	env_throw_bi(env, mfe_io, "rewind", "seek failed: %s",mu_strerror(errno))
1691 #line 988
1692 );
1693 #line 991
1694 }
1695 
1696 #line 992
1697         env_function_cleanup_flush(env, NULL);
1698 #line 992
1699 	return;
1700 #line 992
1701 }
1702 
1703 
1704 #define MINBUFSIZE 128
1705 #define MAXBUFSIZE 65535
1706 
1707 void
1708 #line 998
bi_copy(eval_environ_t env)1709 bi_copy(eval_environ_t env)
1710 #line 998
1711 
1712 #line 998
1713 
1714 #line 998 "io.bi"
1715 {
1716 #line 998
1717 
1718 #line 998
1719 
1720 #line 998
1721 
1722 #line 998
1723 long  dst;
1724 #line 998
1725         long  src;
1726 #line 998
1727 
1728 #line 998
1729 get_numeric_arg(env, 0, &dst);
1730 #line 998
1731         get_numeric_arg(env, 1, &src);
1732 #line 998
1733 
1734 #line 998
1735 
1736 #line 998
1737         adjust_stack(env, 2);
1738 #line 998
1739 
1740 #line 998
1741 
1742 #line 998
1743 	if (builtin_module_trace(BUILTIN_IDX_io))
1744 #line 998
1745 		prog_trace(env, "copy %lu %lu",dst, src);;
1746 #line 998
1747 
1748 {
1749 	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
1750 	int ifd, ofd;
1751 	char *buffer;
1752 	size_t bufsize = MAXBUFSIZE;
1753 	char bs[MINBUFSIZE];
1754 	off_t cur, end;
1755 	size_t total = 0;
1756 	ssize_t rdbytes;
1757 
1758 		if (!(src >= 0 && src < nstreams && (ifd = IFD(iotab[src])) != -1))
1759 #line 1009
1760 		(
1761 #line 1009
1762 	env_throw_bi(env, mfe_range, "copy", _("invalid source file descriptor"))
1763 #line 1009
1764 )
1765 #line 1011
1766 ;
1767 		if (!(dst >= 0 && dst < nstreams && (ofd = OFD(iotab[dst])) != -1))
1768 #line 1012
1769 		(
1770 #line 1012
1771 	env_throw_bi(env, mfe_range, "copy", _("invalid destination file descriptor"))
1772 #line 1012
1773 )
1774 #line 1014
1775 ;
1776 
1777 	cur = lseek (ifd, 0, SEEK_CUR);
1778 	if (cur != -1) {
1779 		end = lseek (ifd, 0, SEEK_END);
1780 		if (end != -1) {
1781 			if (end < MAXBUFSIZE)
1782 				bufsize = end;
1783 			lseek (ifd, cur, SEEK_SET);
1784 		}
1785 	}
1786 
1787 	for (; (buffer = malloc (bufsize)) == NULL; bufsize >>= 1)
1788 		if (bufsize < MINBUFSIZE) {
1789 			buffer = bs;
1790 			bufsize = MINBUFSIZE;
1791 			break;
1792 		}
1793 
1794 	while ((rdbytes = read(ifd, buffer, bufsize)) > 0) {
1795 		char *p = buffer;
1796 		while (rdbytes) {
1797 			ssize_t wrbytes = write(ofd, p, rdbytes);
1798 			if (wrbytes == -1) {
1799 				if (buffer != bs)
1800 					free(buffer);
1801 				(
1802 #line 1040
1803 	env_throw_bi(env, mfe_io, "copy", "write error: %s",mu_strerror(errno))
1804 #line 1040
1805 );
1806 #line 1043
1807 			} else if (wrbytes == 0) {
1808 				if (buffer != bs)
1809 					free(buffer);
1810 				(
1811 #line 1046
1812 	env_throw_bi(env, mfe_io, "copy", "short write")
1813 #line 1046
1814 );
1815 #line 1048
1816 			}
1817 			p += wrbytes;
1818 			rdbytes -= wrbytes;
1819 			total += wrbytes;
1820 		}
1821 	}
1822 	if (buffer != bs)
1823 		free(buffer);
1824 
1825 #line 1056
1826 do {
1827 #line 1056
1828   push(env, (STKVAL)(mft_number)(total));
1829 #line 1056
1830   goto endlab;
1831 #line 1056
1832 } while (0);
1833 }
1834 endlab:
1835 #line 1058
1836         env_function_cleanup_flush(env, NULL);
1837 #line 1058
1838 	return;
1839 #line 1058
1840 }
1841 
1842 void
1843 #line 1060
bi_getdelim(eval_environ_t env)1844 bi_getdelim(eval_environ_t env)
1845 #line 1060
1846 
1847 #line 1060
1848 
1849 #line 1060 "io.bi"
1850 {
1851 #line 1060
1852 
1853 #line 1060
1854 
1855 #line 1060
1856 
1857 #line 1060
1858 long  fd;
1859 #line 1060
1860         char * MFL_DATASEG delim;
1861 #line 1060
1862 
1863 #line 1060
1864 get_numeric_arg(env, 0, &fd);
1865 #line 1060
1866         get_string_arg(env, 1, &delim);
1867 #line 1060
1868 
1869 #line 1060
1870 
1871 #line 1060
1872         adjust_stack(env, 2);
1873 #line 1060
1874 
1875 #line 1060
1876 
1877 #line 1060
1878 	if (builtin_module_trace(BUILTIN_IDX_io))
1879 #line 1060
1880 		prog_trace(env, "getdelim %lu %s",fd, delim);;
1881 #line 1060
1882 
1883 {
1884 	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
1885 	struct io_stream *ioptr;
1886 	int rc;
1887 
1888 		if (!(fd >= 0 && fd < nstreams && IFD(iotab[fd]) != -1))
1889 #line 1066
1890 		(
1891 #line 1066
1892 	env_throw_bi(env, mfe_range, "getdelim", _("invalid file descriptor"))
1893 #line 1066
1894 )
1895 #line 1068
1896 ;
1897 	ioptr = &iotab[fd];
1898 	rc = read_stream_delim(ioptr, delim);
1899 	if (rc == 0)
1900 		(
1901 #line 1072
1902 	env_throw_bi(env, mfe_eof, "getdelim", _("EOF on %s"),ioptr->name)
1903 #line 1072
1904 );
1905 		if (!(rc > 0))
1906 #line 1073
1907 		(
1908 #line 1073
1909 	env_throw_bi(env, mfe_io, "getdelim", _("read error on %s: %s"),ioptr->name,mu_strerror(errno))
1910 #line 1073
1911 )
1912 #line 1076
1913 ;
1914 
1915 #line 1077
1916 do {
1917 #line 1077
1918   pushs(env, ioptr->buf);
1919 #line 1077
1920   goto endlab;
1921 #line 1077
1922 } while (0);
1923 }
1924 endlab:
1925 #line 1079
1926         env_function_cleanup_flush(env, NULL);
1927 #line 1079
1928 	return;
1929 #line 1079
1930 }
1931 
1932 void
1933 #line 1081
bi_getline(eval_environ_t env)1934 bi_getline(eval_environ_t env)
1935 #line 1081
1936 
1937 #line 1081
1938 
1939 #line 1081 "io.bi"
1940 {
1941 #line 1081
1942 
1943 #line 1081
1944 
1945 #line 1081
1946 
1947 #line 1081
1948 long  fd;
1949 #line 1081
1950 
1951 #line 1081
1952 get_numeric_arg(env, 0, &fd);
1953 #line 1081
1954 
1955 #line 1081
1956 
1957 #line 1081
1958         adjust_stack(env, 1);
1959 #line 1081
1960 
1961 #line 1081
1962 
1963 #line 1081
1964 	if (builtin_module_trace(BUILTIN_IDX_io))
1965 #line 1081
1966 		prog_trace(env, "getline %lu",fd);;
1967 #line 1081
1968 
1969 {
1970 	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
1971 	struct io_stream *ioptr;
1972 	int rc;
1973 
1974 		if (!(fd >= 0 && fd < nstreams && IFD(iotab[fd]) != -1))
1975 #line 1087
1976 		(
1977 #line 1087
1978 	env_throw_bi(env, mfe_range, "getline", _("invalid file descriptor"))
1979 #line 1087
1980 )
1981 #line 1089
1982 ;
1983 	ioptr = &iotab[fd];
1984 	rc = read_stream_delim(ioptr, ioptr->delim ? ioptr->delim : "\n");
1985 	if (rc == 0)
1986 		(
1987 #line 1093
1988 	env_throw_bi(env, mfe_eof, "getline", _("EOF on %s"),ioptr->name)
1989 #line 1093
1990 );
1991 #line 1095
1992 		if (!(rc > 0))
1993 #line 1095
1994 		(
1995 #line 1095
1996 	env_throw_bi(env, mfe_io, "getline", _("read error on %s: %s"),ioptr->name,mu_strerror(errno))
1997 #line 1095
1998 )
1999 #line 1098
2000 ;
2001 
2002 #line 1099
2003 do {
2004 #line 1099
2005   pushs(env, ioptr->buf);
2006 #line 1099
2007   goto endlab;
2008 #line 1099
2009 } while (0);
2010 }
2011 endlab:
2012 #line 1101
2013         env_function_cleanup_flush(env, NULL);
2014 #line 1101
2015 	return;
2016 #line 1101
2017 }
2018 
2019 void
2020 #line 1103
bi_fd_set_delimiter(eval_environ_t env)2021 bi_fd_set_delimiter(eval_environ_t env)
2022 #line 1103
2023 
2024 #line 1103
2025 
2026 #line 1103 "io.bi"
2027 {
2028 #line 1103
2029 
2030 #line 1103
2031 
2032 #line 1103
2033 
2034 #line 1103
2035 long  fd;
2036 #line 1103
2037         char *  delim;
2038 #line 1103
2039 
2040 #line 1103
2041 get_numeric_arg(env, 0, &fd);
2042 #line 1103
2043         get_string_arg(env, 1, &delim);
2044 #line 1103
2045 
2046 #line 1103
2047 
2048 #line 1103
2049         adjust_stack(env, 2);
2050 #line 1103
2051 
2052 #line 1103
2053 
2054 #line 1103
2055 	if (builtin_module_trace(BUILTIN_IDX_io))
2056 #line 1103
2057 		prog_trace(env, "fd_set_delimiter %lu %s",fd, delim);;
2058 #line 1103
2059 
2060 {
2061 	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
2062 	struct io_stream *ioptr;
2063 
2064 		if (!(fd >= 0 && fd < nstreams && IFD(iotab[fd]) != -1))
2065 #line 1108
2066 		(
2067 #line 1108
2068 	env_throw_bi(env, mfe_range, "fd_set_delimiter", _("invalid file descriptor"))
2069 #line 1108
2070 )
2071 #line 1110
2072 ;
2073 	ioptr = &iotab[fd];
2074 	free(ioptr->delim);
2075 	ioptr->delim = mu_strdup(delim);
2076 }
2077 
2078 #line 1115
2079         env_function_cleanup_flush(env, NULL);
2080 #line 1115
2081 	return;
2082 #line 1115
2083 }
2084 
2085 void
2086 #line 1117
bi_fd_delimiter(eval_environ_t env)2087 bi_fd_delimiter(eval_environ_t env)
2088 #line 1117
2089 
2090 #line 1117
2091 
2092 #line 1117 "io.bi"
2093 {
2094 #line 1117
2095 
2096 #line 1117
2097 
2098 #line 1117
2099 
2100 #line 1117
2101 long  fd;
2102 #line 1117
2103         char * MFL_DATASEG delim;
2104 #line 1117
2105 
2106 #line 1117
2107 get_numeric_arg(env, 0, &fd);
2108 #line 1117
2109         get_string_arg(env, 1, &delim);
2110 #line 1117
2111 
2112 #line 1117
2113 
2114 #line 1117
2115         adjust_stack(env, 2);
2116 #line 1117
2117 
2118 #line 1117
2119 
2120 #line 1117
2121 	if (builtin_module_trace(BUILTIN_IDX_io))
2122 #line 1117
2123 		prog_trace(env, "fd_delimiter %lu %s",fd, delim);;
2124 #line 1117
2125 
2126 {
2127 	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
2128 	struct io_stream *ioptr;
2129 
2130 		if (!(fd >= 0 && fd < nstreams && IFD(iotab[fd]) != -1))
2131 #line 1122
2132 		(
2133 #line 1122
2134 	env_throw_bi(env, mfe_range, "fd_delimiter", _("invalid file descriptor"))
2135 #line 1122
2136 )
2137 #line 1124
2138 ;
2139 	ioptr = &iotab[fd];
2140 
2141 #line 1126
2142 do {
2143 #line 1126
2144   pushs(env, ioptr->delim ? ioptr->delim : "\n");
2145 #line 1126
2146   goto endlab;
2147 #line 1126
2148 } while (0);
2149 }
2150 endlab:
2151 #line 1128
2152         env_function_cleanup_flush(env, NULL);
2153 #line 1128
2154 	return;
2155 #line 1128
2156 }
2157 
2158 
2159 #line 982 "../../src/builtin/snarf.m4"
2160 
2161 #line 982
2162 
2163 #line 982
2164 
2165 #line 982
2166 void
2167 #line 982
io_init_builtin(void)2168 io_init_builtin(void)
2169 #line 982
2170 {
2171 #line 982
2172 		debug_handle = mu_debug_register_category("bi_io");
2173 #line 982
2174 
2175 #line 982
2176 	#line 684 "io.bi"
2177 IO_id = builtin_priv_register(alloc_streams, destroy_streams,
2178 #line 684
2179 NULL);
2180 #line 703 "io.bi"
2181 va_builtin_install_ex("open", bi_open, 0, dtype_number, 1, 0, 0|0, dtype_string);
2182 #line 762 "io.bi"
2183 va_builtin_install_ex("spawn", bi_spawn, 0, dtype_number, 4, 3, 0|0, dtype_string, dtype_number, dtype_number, dtype_number);
2184 #line 822 "io.bi"
2185 va_builtin_install_ex("tempfile", bi_tempfile, 0, dtype_number, 1, 1, 0|0, dtype_string);
2186 #line 868 "io.bi"
2187 va_builtin_install_ex("close", bi_close, 0, dtype_unspecified, 1, 0, 0|0, dtype_number);
2188 #line 885 "io.bi"
2189 va_builtin_install_ex("shutdown", bi_shutdown, 0, dtype_unspecified, 2, 0, 0|0, dtype_number, dtype_number);
2190 #line 920 "io.bi"
2191 va_builtin_install_ex("write", bi_write, 0, dtype_unspecified, 3, 1, 0|0, dtype_number, dtype_string, dtype_number);
2192 #line 940 "io.bi"
2193 va_builtin_install_ex("write_body", bi_write_body, STATMASK(smtp_state_body), dtype_unspecified, 3, 0, 0|0, dtype_number, dtype_pointer, dtype_number);
2194 #line 956 "io.bi"
2195 va_builtin_install_ex("read", bi_read, 0, dtype_string, 2, 0, 0|0, dtype_number, dtype_number);
2196 #line 980 "io.bi"
2197 va_builtin_install_ex("rewind", bi_rewind, 0, dtype_unspecified, 1, 0, 0|0, dtype_number);
2198 #line 998 "io.bi"
2199 va_builtin_install_ex("copy", bi_copy, 0, dtype_number, 2, 0, 0|0, dtype_number, dtype_number);
2200 #line 1060 "io.bi"
2201 va_builtin_install_ex("getdelim", bi_getdelim, 0, dtype_string, 2, 0, 0|0, dtype_number, dtype_string);
2202 #line 1081 "io.bi"
2203 va_builtin_install_ex("getline", bi_getline, 0, dtype_string, 1, 0, 0|0, dtype_number);
2204 #line 1103 "io.bi"
2205 va_builtin_install_ex("fd_set_delimiter", bi_fd_set_delimiter, 0, dtype_unspecified, 2, 0, 0|0, dtype_number, dtype_string);
2206 #line 1117 "io.bi"
2207 va_builtin_install_ex("fd_delimiter", bi_fd_delimiter, 0, dtype_string, 2, 0, 0|0, dtype_number, dtype_string);
2208 
2209 #line 982 "../../src/builtin/snarf.m4"
2210 
2211 #line 982
2212 	 mf_add_runtime_params(io_cfg_param);
2213 #line 982
2214 
2215 #line 982
2216 }
2217 #line 982 "../../src/builtin/snarf.m4"
2218 
2219