cmds.c revision 161781
1/*	$OpenBSD: cmds.c,v 1.26 2006/06/06 23:24:52 deraadt Exp $	*/
2/*	$NetBSD: cmds.c,v 1.7 1997/02/11 09:24:03 mrg Exp $	*/
3
4/*
5 * Copyright (c) 1983, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: head/usr.bin/tip/tip/cmds.c 161781 2006-08-31 19:19:44Z ru $");
35
36#ifndef lint
37#if 0
38static char sccsid[] = "@(#)cmds.c	8.1 (Berkeley) 6/6/93";
39static const char rcsid[] = "$OpenBSD: cmds.c,v 1.26 2006/06/06 23:24:52 deraadt Exp $";
40#endif
41#endif /* not lint */
42
43#include "tip.h"
44#include "pathnames.h"
45
46#include <vis.h>
47
48/*
49 * tip
50 *
51 * miscellaneous commands
52 */
53
54int	quant[] = { 60, 60, 24 };
55
56char	null = '\0';
57char	*sep[] = { "second", "minute", "hour" };
58static char *argv[10];		/* argument vector for take and put */
59
60static void	transfer(char *, int, char *);
61static void	stopsnd(int);	/* SIGINT handler during file transfers */
62static void	intcopy(int);	/* interrupt routine for file transfers */
63static void	transmit(FILE *, char *, char *);
64static void	send(int);
65static void	execute(char *);
66static int	args(char *, char **, int);
67static void	prtime(char *, time_t);
68static void	tandem(char *);
69static void	hardwareflow(char *);
70void		linedisc(char *);
71static int	anyof(char *, char *);
72
73/*
74 * FTP - remote ==> local
75 *  get a file from the remote host
76 */
77void
78getfl(int c)
79{
80	char buf[256], *cp;
81
82	putchar(c);
83	/*
84	 * get the UNIX receiving file's name
85	 */
86	if (prompt("Local file name? ", copyname, sizeof(copyname)))
87		return;
88	cp = expand(copyname);
89	if ((sfd = creat(cp, 0666)) < 0) {
90		printf("\r\n%s: cannot creat\r\n", copyname);
91		return;
92	}
93
94	/*
95	 * collect parameters
96	 */
97	if (prompt("List command for remote system? ", buf, sizeof(buf))) {
98		unlink(copyname);
99		return;
100	}
101	transfer(buf, sfd, value(EOFREAD));
102}
103
104/*
105 * Cu-like take command
106 */
107void
108cu_take(int c)
109{
110	int fd, argc;
111	char line[BUFSIZ], *cp;
112
113	if (prompt("[take] ", copyname, sizeof(copyname)))
114		return;
115	if ((argc = args(copyname, argv, sizeof(argv)/sizeof(argv[0]))) < 1 ||
116	    argc > 2) {
117		printf("usage: <take> from [to]\r\n");
118		return;
119	}
120	if (argc == 1)
121		argv[1] = argv[0];
122	cp = expand(argv[1]);
123	if ((fd = creat(cp, 0666)) < 0) {
124		printf("\r\n%s: cannot create\r\n", argv[1]);
125		return;
126	}
127	(void)snprintf(line, sizeof(line), "cat %s;echo ''|tr '\\012' '\\01'", argv[0]);
128	transfer(line, fd, "\01");
129}
130
131static	jmp_buf intbuf;
132
133/*
134 * Bulk transfer routine --
135 *  used by getfl(), cu_take(), and pipefile()
136 */
137static void
138transfer(char *buf, int fd, char *eofchars)
139{
140	int ct, eof;
141	char c, buffer[BUFSIZ];
142	char *p = buffer;
143	size_t cnt;
144	time_t start;
145	sig_t f;
146	char r;
147
148	if (number(value(FRAMESIZE)) > BUFSIZ || number(value(FRAMESIZE)) < 1) {
149		printf("framesize must be >= 1 and <= %d\r\n", BUFSIZ);
150		close(fd);
151		return;
152	}
153
154	parwrite(FD, buf, size(buf));
155	quit = 0;
156	kill(tipout_pid, SIGIOT);
157	read(repdes[0], (char *)&ccc, 1);  /* Wait until read process stops */
158
159	/*
160	 * finish command
161	 */
162	r = '\r';
163	parwrite(FD, &r, 1);
164	do
165		read(FD, &c, 1);
166	while ((c&STRIP_PAR) != '\n');
167	tcsetattr(0, TCSAFLUSH, &defchars);
168
169	(void) setjmp(intbuf);
170	f = signal(SIGINT, intcopy);
171	start = time(0);
172	for (ct = 0; !quit;) {
173		eof = read(FD, &c, 1) <= 0;
174		c &= STRIP_PAR;
175		if (quit)
176			continue;
177		if (eof || any(c, eofchars))
178			break;
179		if (c == 0)
180			continue;	/* ignore nulls */
181		if (c == '\r')
182			continue;
183		*p++ = c;
184
185		if (c == '\n' && boolean(value(VERBOSE)))
186			printf("\r%d", ++ct);
187		if ((cnt = (p-buffer)) == (size_t)number(value(FRAMESIZE))) {
188			if ((size_t)write(fd, buffer, cnt) != cnt) {
189				printf("\r\nwrite error\r\n");
190				quit = 1;
191			}
192			p = buffer;
193		}
194	}
195	if ((cnt = (p-buffer)))
196		if ((size_t)write(fd, buffer, cnt) != cnt)
197			printf("\r\nwrite error\r\n");
198
199	if (boolean(value(VERBOSE)))
200		prtime(" lines transferred in ", time(0)-start);
201	tcsetattr(0, TCSAFLUSH, &term);
202	write(fildes[1], (char *)&ccc, 1);
203	signal(SIGINT, f);
204	close(fd);
205}
206
207/*
208 * FTP - remote ==> local process
209 *   send remote input to local process via pipe
210 */
211/*ARGSUSED*/
212void
213pipefile(int c)
214{
215	int pdes[2];
216	char buf[256];
217	int status, p;
218	pid_t cpid;
219
220	if (prompt("Local command? ", buf, sizeof(buf)))
221		return;
222
223	if (pipe(pdes)) {
224		printf("can't establish pipe\r\n");
225		return;
226	}
227
228	if ((cpid = fork()) < 0) {
229		printf("can't fork!\r\n");
230		return;
231	} else if (cpid) {
232		if (prompt("List command for remote system? ", buf, sizeof(buf))) {
233			close(pdes[0]), close(pdes[1]);
234			kill (cpid, SIGKILL);
235		} else {
236			close(pdes[0]);
237			signal(SIGPIPE, intcopy);
238			transfer(buf, pdes[1], value(EOFREAD));
239			signal(SIGPIPE, SIG_DFL);
240			while ((p = wait(&status)) > 0 && p != cpid)
241				;
242		}
243	} else {
244		int f;
245
246		dup2(pdes[0], 0);
247		close(pdes[0]);
248		for (f = 3; f < 20; f++)
249			close(f);
250		execute(buf);
251		printf("can't execl!\r\n");
252		exit(0);
253	}
254}
255
256/*
257 * Interrupt service routine for FTP
258 */
259/*ARGSUSED*/
260static void
261stopsnd(int signo)
262{
263	stop = 1;
264	signal(SIGINT, SIG_IGN);
265}
266
267/*
268 * FTP - local ==> remote
269 *  send local file to remote host
270 *  terminate transmission with pseudo EOF sequence
271 */
272void
273sendfile(int c)
274{
275	FILE *fp;
276	char *fnamex;
277
278	putchar(c);
279	/*
280	 * get file name
281	 */
282	if (prompt("Local file name? ", fname, sizeof(fname)))
283		return;
284
285	/*
286	 * look up file
287	 */
288	fnamex = expand(fname);
289	if ((fp = fopen(fnamex, "r")) == NULL) {
290		printf("%s: cannot open\r\n", fname);
291		return;
292	}
293	transmit(fp, value(EOFWRITE), NULL);
294	if (!boolean(value(ECHOCHECK)))
295		tcdrain(FD);
296}
297
298/*
299 * Bulk transfer routine to remote host --
300 *   used by sendfile() and cu_put()
301 */
302static void
303transmit(FILE *fp, char *eofchars, char *command)
304{
305	char *pc, lastc;
306	int c, ccount, lcount;
307	time_t start_t, stop_t;
308	sig_t f;
309
310	kill(tipout_pid, SIGIOT);	/* put TIPOUT into a wait state */
311	stop = 0;
312	f = signal(SIGINT, stopsnd);
313	tcsetattr(0, TCSAFLUSH, &defchars);
314	read(repdes[0], (char *)&ccc, 1);
315	if (command != NULL) {
316		for (pc = command; *pc; pc++)
317			send(*pc);
318		if (boolean(value(ECHOCHECK)))
319			read(FD, (char *)&c, 1);	/* trailing \n */
320		else {
321			tcdrain(FD);
322			sleep(5); /* wait for remote stty to take effect */
323		}
324	}
325	lcount = 0;
326	lastc = '\0';
327	start_t = time(0);
328	while (1) {
329		ccount = 0;
330		do {
331			c = getc(fp);
332			if (stop)
333				goto out;
334			if (c == EOF)
335				goto out;
336			if (c == 0177 && !boolean(value(RAWFTP)))
337				continue;
338			lastc = c;
339			if (c < 040) {
340				if (c == '\n') {
341					if (!boolean(value(RAWFTP)))
342						c = '\r';
343				} else if (c == '\t') {
344					if (!boolean(value(RAWFTP))) {
345						if (boolean(value(TABEXPAND))) {
346							send(' ');
347							while ((++ccount % 8) != 0)
348								send(' ');
349							continue;
350						}
351					}
352				} else
353					if (!boolean(value(RAWFTP)))
354						continue;
355			}
356			send(c);
357		} while (c != '\r' && !boolean(value(RAWFTP)));
358		if (boolean(value(VERBOSE)))
359			printf("\r%d", ++lcount);
360		if (boolean(value(ECHOCHECK))) {
361			timedout = 0;
362			alarm((unsigned int)lvalue(ETIMEOUT));
363			do {	/* wait for prompt */
364				read(FD, (char *)&c, 1);
365				if (timedout || stop) {
366					if (timedout)
367						printf("\r\ntimed out at eol\r\n");
368					alarm(0);
369					goto out;
370				}
371			} while ((c&STRIP_PAR) != character(value(PROMPT)));
372			alarm(0);
373		}
374	}
375out:
376	if (lastc != '\n' && !boolean(value(RAWFTP)))
377		send('\r');
378	if (eofchars) {
379		for (pc = eofchars; *pc; pc++)
380			send(*pc);
381	}
382	stop_t = time(0);
383	fclose(fp);
384	signal(SIGINT, f);
385	if (boolean(value(VERBOSE))) {
386		if (boolean(value(RAWFTP)))
387			prtime(" chars transferred in ", stop_t-start_t);
388		else
389			prtime(" lines transferred in ", stop_t-start_t);
390	}
391	write(fildes[1], (char *)&ccc, 1);
392	tcsetattr(0, TCSAFLUSH, &term);
393}
394
395/*
396 * Cu-like put command
397 */
398/*ARGSUSED*/
399void
400cu_put(int c)
401{
402	FILE *fp;
403	char line[BUFSIZ];
404	int argc;
405	char *copynamex;
406
407	if (prompt("[put] ", copyname, sizeof(copyname)))
408		return;
409	if ((argc = args(copyname, argv, sizeof(argv)/sizeof(argv[0]))) < 1 ||
410	    argc > 2) {
411		printf("usage: <put> from [to]\r\n");
412		return;
413	}
414	if (argc == 1)
415		argv[1] = argv[0];
416	copynamex = expand(argv[0]);
417	if ((fp = fopen(copynamex, "r")) == NULL) {
418		printf("%s: cannot open\r\n", copynamex);
419		return;
420	}
421	if (boolean(value(ECHOCHECK)))
422		(void)snprintf(line, sizeof(line), "cat>%s\r", argv[1]);
423	else
424		(void)snprintf(line, sizeof(line),
425		    "stty -echo;cat>%s;stty echo\r", argv[1]);
426	transmit(fp, "\04", line);
427}
428
429/*
430 * FTP - send single character
431 *  wait for echo & handle timeout
432 */
433static void
434send(int c)
435{
436	char cc;
437	int retry = 0;
438
439	cc = c;
440	parwrite(FD, &cc, 1);
441	if (number(value(CDELAY)) > 0 && c != '\r')
442		usleep(number(value(CDELAY)));
443	if (!boolean(value(ECHOCHECK))) {
444		if (number(value(LDELAY)) > 0 && c == '\r')
445			usleep(number(value(LDELAY)));
446		return;
447	}
448tryagain:
449	timedout = 0;
450	alarm((unsigned int)lvalue(ETIMEOUT));
451	read(FD, &cc, 1);
452	alarm(0);
453	if (timedout) {
454		printf("\r\ntimeout error (%s)\r\n", ctrl(c));
455		if (retry++ > 3)
456			return;
457		parwrite(FD, &null, 1); /* poke it */
458		goto tryagain;
459	}
460}
461
462/*ARGSUSED*/
463void
464timeout(int signo)
465{
466	signal(SIGALRM, timeout);
467	timedout = 1;
468}
469
470/*
471 * Stolen from consh() -- puts a remote file on the output of a local command.
472 *	Identical to consh() except for where stdout goes.
473 */
474void
475pipeout(int c)
476{
477	char buf[256];
478	int status, p;
479	pid_t cpid;
480	time_t start = time(NULL);
481
482	putchar(c);
483	if (prompt("Local command? ", buf, sizeof(buf)))
484		return;
485	kill(tipout_pid, SIGIOT);	/* put TIPOUT into a wait state */
486	signal(SIGINT, SIG_IGN);
487	signal(SIGQUIT, SIG_IGN);
488	tcsetattr(0, TCSAFLUSH, &defchars);
489	read(repdes[0], (char *)&ccc, 1);
490	/*
491	 * Set up file descriptors in the child and
492	 *  let it go...
493	 */
494	if ((cpid = fork()) < 0)
495		printf("can't fork!\r\n");
496	else if (cpid) {
497		start = time(NULL);
498		while ((p = wait(&status)) > 0 && p != cpid)
499			;
500	} else {
501		int i;
502
503		dup2(FD, 1);
504		for (i = 3; i < 20; i++)
505			close(i);
506		signal(SIGINT, SIG_DFL);
507		signal(SIGQUIT, SIG_DFL);
508		execute(buf);
509		printf("can't find `%s'\r\n", buf);
510		exit(0);
511	}
512	if (boolean(value(VERBOSE)))
513		prtime("away for ", time(0)-start);
514	write(fildes[1], (char *)&ccc, 1);
515	tcsetattr(0, TCSAFLUSH, &term);
516	signal(SIGINT, SIG_DFL);
517	signal(SIGQUIT, SIG_DFL);
518}
519
520#ifdef CONNECT
521/*
522 * Fork a program with:
523 *  0 <-> remote tty in
524 *  1 <-> remote tty out
525 *  2 <-> local tty stderr
526 */
527void
528consh(int c)
529{
530	char buf[256];
531	int status, p;
532	pid_t cpid;
533	time_t start = time(NULL);
534
535	putchar(c);
536	if (prompt("Local command? ", buf, sizeof(buf)))
537		return;
538	kill(tipout_pid, SIGIOT);	/* put TIPOUT into a wait state */
539	signal(SIGINT, SIG_IGN);
540	signal(SIGQUIT, SIG_IGN);
541	tcsetattr(0, TCSAFLUSH, &defchars);
542	read(repdes[0], (char *)&ccc, 1);
543	/*
544	 * Set up file descriptors in the child and
545	 *  let it go...
546	 */
547	if ((cpid = fork()) < 0)
548		printf("can't fork!\r\n");
549	else if (cpid) {
550		start = time(0);
551		while ((p = wait(&status)) > 0 && p != cpid)
552			;
553	} else {
554		int i;
555
556		dup2(FD, 0);
557		dup2(3, 1);
558		for (i = 3; i < 20; i++)
559			close(i);
560		signal(SIGINT, SIG_DFL);
561		signal(SIGQUIT, SIG_DFL);
562		execute(buf);
563		printf("can't find `%s'\r\n", buf);
564		exit(0);
565	}
566	if (boolean(value(VERBOSE)))
567		prtime("away for ", time(0)-start);
568	write(fildes[1], (char *)&ccc, 1);
569	tcsetattr(0, TCSAFLUSH, &term);
570	signal(SIGINT, SIG_DFL);
571	signal(SIGQUIT, SIG_DFL);
572}
573#endif
574
575/*
576 * Escape to local shell
577 */
578/*ARGSUSED*/
579void
580shell(int c)
581{
582	int status;
583	char *cp;
584	pid_t shpid;
585
586	printf("[sh]\r\n");
587	signal(SIGINT, SIG_IGN);
588	signal(SIGQUIT, SIG_IGN);
589	unraw();
590	if ((shpid = fork())) {
591		while (shpid != wait(&status));
592		raw();
593		printf("\r\n!\r\n");
594		signal(SIGINT, SIG_DFL);
595		signal(SIGQUIT, SIG_DFL);
596		return;
597	} else {
598		signal(SIGQUIT, SIG_DFL);
599		signal(SIGINT, SIG_DFL);
600		if ((cp = strrchr(value(SHELL), '/')) == NULL)
601			cp = value(SHELL);
602		else
603			cp++;
604		shell_uid();
605		execl(value(SHELL), cp, (char *)NULL);
606		printf("\r\ncan't execl!\r\n");
607		exit(1);
608	}
609}
610
611/*
612 * TIPIN portion of scripting
613 *   initiate the conversation with TIPOUT
614 */
615void
616setscript(void)
617{
618	char c;
619
620	/*
621	 * enable TIPOUT side for dialogue
622	 */
623	kill(tipout_pid, SIGEMT);
624	if (boolean(value(SCRIPT)))
625		write(fildes[1], value(RECORD), size(value(RECORD)));
626	write(fildes[1], "\n", 1);
627	/*
628	 * wait for TIPOUT to finish
629	 */
630	read(repdes[0], &c, 1);
631	if (c == 'n')
632		printf("can't create %s\r\n", value(RECORD));
633}
634
635/*
636 * Change current working directory of
637 *   local portion of tip
638 */
639/*ARGSUSED*/
640void
641chdirectory(int c)
642{
643	char dirname[PATH_MAX];
644	char *cp = dirname;
645
646	if (prompt("[cd] ", dirname, sizeof(dirname))) {
647		if (stoprompt)
648			return;
649		cp = value(HOME);
650	}
651	if (chdir(cp) < 0)
652		printf("%s: bad directory\r\n", cp);
653	printf("!\r\n");
654}
655
656void
657tipabort(char *msg)
658{
659
660	signal(SIGTERM, SIG_IGN);
661	kill(tipout_pid, SIGTERM);
662	disconnect(msg);
663	if (msg != NOSTR)
664		printf("\r\n%s", msg);
665	printf("\r\n[EOT]\r\n");
666	daemon_uid();
667	(void)uu_unlock(uucplock);
668	unraw();
669	exit(0);
670}
671
672/*ARGSUSED*/
673void
674finish(int c)
675{
676	char *dismsg;
677
678	if ((dismsg = value(DISCONNECT)) != NOSTR) {
679		write(FD, dismsg, strlen(dismsg));
680		sleep(5);
681	}
682	tipabort(NOSTR);
683}
684
685/*ARGSUSED*/
686static void
687intcopy(int signo)
688{
689	raw();
690	quit = 1;
691	longjmp(intbuf, 1);
692}
693
694static void
695execute(char *s)
696{
697	char *cp;
698
699	if ((cp = strrchr(value(SHELL), '/')) == NULL)
700		cp = value(SHELL);
701	else
702		cp++;
703	shell_uid();
704	execl(value(SHELL), cp, "-c", s, (char *)NULL);
705}
706
707static int
708args(char *buf, char *a[], int num)
709{
710	char *p = buf, *start;
711	char **parg = a;
712	int n = 0;
713
714	do {
715		while (*p && (*p == ' ' || *p == '\t'))
716			p++;
717		start = p;
718		if (*p)
719			*parg = p;
720		while (*p && (*p != ' ' && *p != '\t'))
721			p++;
722		if (p != start)
723			parg++, n++;
724		if (*p)
725			*p++ = '\0';
726	} while (*p && n < num);
727
728	return(n);
729}
730
731static void
732prtime(char *s, time_t a)
733{
734	int i;
735	int nums[3];
736
737	for (i = 0; i < 3; i++) {
738		nums[i] = (int)(a % quant[i]);
739		a /= quant[i];
740	}
741	printf("%s", s);
742	while (--i >= 0)
743		if (nums[i] || (i == 0 && nums[1] == 0 && nums[2] == 0))
744			printf("%d %s%c ", nums[i], sep[i],
745				nums[i] == 1 ? '\0' : 's');
746	printf("\r\n!\r\n");
747}
748
749/*ARGSUSED*/
750void
751variable(int c)
752{
753	char	buf[256];
754
755	if (prompt("[set] ", buf, sizeof(buf)))
756		return;
757	vlex(buf);
758	if (vtable[BEAUTIFY].v_access&CHANGED) {
759		vtable[BEAUTIFY].v_access &= ~CHANGED;
760		kill(tipout_pid, SIGSYS);
761	}
762	if (vtable[SCRIPT].v_access&CHANGED) {
763		vtable[SCRIPT].v_access &= ~CHANGED;
764		setscript();
765		/*
766		 * So that "set record=blah script" doesn't
767		 *  cause two transactions to occur.
768		 */
769		if (vtable[RECORD].v_access&CHANGED)
770			vtable[RECORD].v_access &= ~CHANGED;
771	}
772	if (vtable[RECORD].v_access&CHANGED) {
773		vtable[RECORD].v_access &= ~CHANGED;
774		if (boolean(value(SCRIPT)))
775			setscript();
776	}
777	if (vtable[TAND].v_access&CHANGED) {
778		vtable[TAND].v_access &= ~CHANGED;
779		if (boolean(value(TAND)))
780			tandem("on");
781		else
782			tandem("off");
783	}
784	if (vtable[LECHO].v_access&CHANGED) {
785		vtable[LECHO].v_access &= ~CHANGED;
786		HD = boolean(value(LECHO));
787	}
788	if (vtable[PARITY].v_access&CHANGED) {
789		vtable[PARITY].v_access &= ~CHANGED;
790		setparity(NOSTR);
791	}
792	if (vtable[HARDWAREFLOW].v_access&CHANGED) {
793		vtable[HARDWAREFLOW].v_access &= ~CHANGED;
794		if (boolean(value(HARDWAREFLOW)))
795			hardwareflow("on");
796		else
797			hardwareflow("off");
798	}
799	if (vtable[LINEDISC].v_access&CHANGED) {
800		vtable[LINEDISC].v_access &= ~CHANGED;
801		linedisc(NOSTR);
802	}
803}
804
805/*ARGSUSED*/
806void
807listvariables(int c)
808{
809	value_t *p;
810	char *buf;
811	char charbuf[5];	/* for vis(3), 4 chars for encoding, plus nul */
812
813	puts("v\r");
814	for (p = vtable; p->v_name; p++) {
815		fputs(p->v_name, stdout);
816		switch (p->v_type&TMASK) {
817		case STRING:
818			if (p->v_value) {
819				buf = malloc(4*strlen(p->v_value) + 1);
820				if (buf == NULL) {
821					fprintf(stderr, "Unable to malloc()\n");
822					abort();
823				}
824				strvis(buf, p->v_value, VIS_WHITE);
825				printf(" %s", buf);
826				free(buf);
827			}
828			putchar('\r');
829			putchar('\n');
830			break;
831		case NUMBER:
832			printf(" %ld\r\n", number(p->v_value));
833			break;
834		case BOOL:
835			printf(" %s\r\n",
836			    !boolean(p->v_value) ? "false" : "true");
837			break;
838		case CHAR:
839			vis(charbuf, character(p->v_value), VIS_WHITE, 0);
840			printf(" %s\r\n", charbuf);
841			break;
842		}
843	}
844}
845
846/*
847 * Turn tandem mode on or off for remote tty.
848 */
849static void
850tandem(char *option)
851{
852	struct termios	rmtty;
853
854	tcgetattr(FD, &rmtty);
855	if (strcmp(option, "on") == 0) {
856		rmtty.c_iflag |= IXOFF;
857		term.c_iflag |= IXOFF;
858	} else {
859		rmtty.c_iflag &= ~IXOFF;
860		term.c_iflag &= ~IXOFF;
861	}
862	tcsetattr(FD, TCSADRAIN, &rmtty);
863	tcsetattr(0, TCSADRAIN, &term);
864}
865
866/*
867 * Turn hardware flow control on or off for remote tty.
868 */
869static void
870hardwareflow(char *option)
871{
872	struct termios	rmtty;
873
874	tcgetattr(FD, &rmtty);
875	if (strcmp(option, "on") == 0)
876		rmtty.c_iflag |= CRTSCTS;
877	else
878		rmtty.c_iflag &= ~CRTSCTS;
879	tcsetattr(FD, TCSADRAIN, &rmtty);
880}
881
882/*
883 * Change line discipline to the specified one.
884 */
885void
886linedisc(char *option)
887{
888	int ld = (int)(intptr_t)value(LINEDISC);
889
890	ioctl(FD, TIOCSETD, &ld);
891}
892
893/*
894 * Send a break.
895 */
896/*ARGSUSED*/
897void
898genbrk(int c)
899{
900	ioctl(FD, TIOCSBRK, NULL);
901	sleep(1);
902	ioctl(FD, TIOCCBRK, NULL);
903}
904
905/*
906 * Suspend tip
907 */
908void
909suspend(int c)
910{
911	unraw();
912	kill(c == CTRL('y') ? getpid() : 0, SIGTSTP);
913	raw();
914}
915
916/*
917 *	expand a file name if it includes shell meta characters
918 */
919char *
920expand(char name[])
921{
922	static char xname[BUFSIZ];
923	char cmdbuf[BUFSIZ];
924	int l;
925	char *cp, *Shell;
926	int s, pivec[2];
927	pid_t pid;
928
929	if (!anyof(name, "~{[*?$`'\"\\"))
930		return(name);
931	/* sigint = signal(SIGINT, SIG_IGN); */
932	if (pipe(pivec) < 0) {
933		perror("pipe");
934		/* signal(SIGINT, sigint) */
935		return(name);
936	}
937	(void)snprintf(cmdbuf, sizeof(cmdbuf), "echo %s", name);
938	if ((pid = vfork()) == 0) {
939		Shell = value(SHELL);
940		if (Shell == NOSTR)
941			Shell = _PATH_BSHELL;
942		close(pivec[0]);
943		close(1);
944		dup(pivec[1]);
945		close(pivec[1]);
946		close(2);
947		shell_uid();
948		execl(Shell, Shell, "-c", cmdbuf, (char *)NULL);
949		_exit(1);
950	}
951	if (pid == -1) {
952		perror("fork");
953		close(pivec[0]);
954		close(pivec[1]);
955		return(NOSTR);
956	}
957	close(pivec[1]);
958	l = read(pivec[0], xname, BUFSIZ);
959	close(pivec[0]);
960	while (wait(&s) != pid);
961		;
962	s &= 0377;
963	if (s != 0 && s != SIGPIPE) {
964		fprintf(stderr, "\"Echo\" failed\n");
965		return(NOSTR);
966	}
967	if (l < 0) {
968		perror("read");
969		return(NOSTR);
970	}
971	if (l == 0) {
972		fprintf(stderr, "\"%s\": No match\n", name);
973		return(NOSTR);
974	}
975	if (l == BUFSIZ) {
976		fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
977		return(NOSTR);
978	}
979	xname[l] = 0;
980	for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
981		;
982	*++cp = '\0';
983	return(xname);
984}
985
986/*
987 * Are any of the characters in the two strings the same?
988 */
989static int
990anyof(char *s1, char *s2)
991{
992	int c;
993
994	while ((c = *s1++))
995		if (any(c, s2))
996			return(1);
997	return(0);
998}
999