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