xref: /illumos-gate/usr/src/cmd/tip/cmds.c (revision bd335c6465ddbafe543900df4b03247bfa288eff)
1 /*
2  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 /*
6  * Copyright (c) 1983 Regents of the University of California.
7  * All rights reserved.  The Berkeley software License Agreement
8  * specifies the terms and conditions for redistribution.
9  */
10 
11 #ident	"%Z%%M%	%I%	%E% SMI"	/* from UCB 5.4 5/5/86 */
12 
13 #include "tip.h"
14 #ifdef USG
15 #include <unistd.h>
16 #else
17 #include <vfork.h>
18 #endif
19 
20 /*
21  * tip
22  *
23  * miscellaneous commands
24  */
25 
26 int	quant[] = { 60, 60, 24 };
27 
28 char	null = '\0';
29 char	*sep[] = { "second", "minute", "hour" };
30 static	char *argv[10];		/* argument vector for take and put */
31 
32 sigjmp_buf intbuf;		/* for interrupts and timeouts */
33 
34 void	timeout();		/* timeout function called on alarm */
35 void	intcopy();		/* interrupt routine for file transfers */
36 
37 /*
38  * FTP - remote ==> local
39  *  get a file from the remote host
40  */
41 getfl(c)
42 	char c;
43 {
44 	char buf[256], *cp, *expand();
45 
46 	putchar(c);
47 	/*
48 	 * get the UNIX receiving file's name
49 	 */
50 	if (prompt("Local file name? ", copyname, sizeof (copyname)))
51 		return;
52 	cp = expand(copyname);
53 	if (cp == NOSTR)
54 		return;
55 	if ((sfd = creat(cp, 0666)) < 0) {
56 		printf("\r\n%s: cannot creat\r\n", copyname);
57 		return;
58 	}
59 
60 	/*
61 	 * collect parameters
62 	 */
63 	if (prompt("List command for remote system? ", buf, sizeof (buf))) {
64 		unlink(copyname);
65 		return;
66 	}
67 	transfer(buf, sfd, value(EOFREAD));
68 }
69 
70 /*
71  * Cu-like take command
72  */
73 cu_take(cc)
74 	char cc;
75 {
76 	int fd, argc;
77 	char line[BUFSIZ], *expand(), *cp;
78 
79 	if (prompt("[take] ", copyname, sizeof (copyname)))
80 		return;
81 	argc = args(copyname, argv, sizeof (argv)/sizeof (char *));
82 	if (argc < 1 || argc > 2) {
83 		printf("usage: <take> from [to]\r\n");
84 		return;
85 	}
86 	if (argc == 1)
87 		argv[1] = argv[0];
88 	cp = expand(argv[1]);
89 	if (cp == NOSTR)
90 		return;
91 	if ((fd = creat(cp, 0666)) < 0) {
92 		printf("\r\n%s: cannot create\r\n", argv[1]);
93 		return;
94 	}
95 	sprintf(line, "cat %s; echo \01", argv[0]);
96 	transfer(line, fd, "\01");
97 }
98 
99 /*
100  * Bulk transfer routine --
101  *  used by getfl(), cu_take(), and pipefile()
102  */
103 transfer(buf, fd, eofchars)
104 	char *buf, *eofchars;
105 {
106 	register int ct;
107 	char c, buffer[BUFSIZ];
108 	char *p = buffer;	/* can't be register because of longjmp */
109 	register int cnt, eof, bol;
110 	time_t start;
111 	void (*f)();
112 
113 	parwrite(FD, buf, strlen(buf));
114 	kill(pid, SIGIOT);
115 	read(repdes[0], (char *)&ccc, 1);  /* Wait until read process stops */
116 
117 	/*
118 	 * finish command
119 	 */
120 	parwrite(FD, "\r", 1);
121 	do
122 		read(FD, &c, 1);
123 	while ((c&0177) != '\n');
124 
125 	if (sigsetjmp(intbuf, 1))
126 		goto out;
127 	f = signal(SIGINT, intcopy);
128 	intr("on");
129 
130 	start = time(0);
131 	bol = 1;
132 	ct = 0;
133 	for (;;) {
134 		eof = read(FD, &c, 1) <= 0;
135 		if (noparity)
136 			c &= 0377;
137 		else
138 			c &= 0177;
139 		if (eof || (bol && any(c, eofchars)))
140 			break;
141 		if (c == 0)
142 			continue;	/* ignore nulls */
143 		if (c == '\r')
144 			continue;
145 		*p++ = c;
146 
147 		if (c == '\n') {
148 			bol = 1;
149 			if (boolean(value(VERBOSE)))
150 				printf("\r%d", ++ct);
151 		} else
152 			bol = 0;
153 		if ((cnt = (p-buffer)) == number(value(FRAMESIZE))) {
154 			if (write(fd, buffer, cnt) != cnt) {
155 				printf("\r\nwrite error\r\n");
156 				goto out;
157 			}
158 			p = buffer;
159 		}
160 	}
161 out:
162 	if (cnt = (p-buffer))
163 		if (write(fd, buffer, cnt) != cnt)
164 			printf("\r\nwrite error\r\n");
165 
166 	if (boolean(value(VERBOSE)))
167 		prtime(" lines transferred in ", time(0)-start);
168 	intr("off");
169 	write(fildes[1], (char *)&ccc, 1);
170 	signal(SIGINT, f);
171 	close(fd);
172 }
173 
174 /*
175  * FTP - remote ==> local process
176  *   send remote input to local process via pipe
177  */
178 pipefile()
179 {
180 	int cpid, pdes[2];
181 	char buf[256];
182 	int status, p;
183 	extern int errno;
184 
185 	if (prompt("Local command? ", buf, sizeof (buf)))
186 		return;
187 
188 	if (pipe(pdes)) {
189 		printf("can't establish pipe\r\n");
190 		return;
191 	}
192 
193 	if ((cpid = fork()) < 0) {
194 		printf("can't fork!\r\n");
195 		return;
196 	} else if (cpid) {
197 		if (prompt("List command for remote system? ", buf,
198 			    sizeof (buf))) {
199 			close(pdes[0]), close(pdes[1]);
200 			kill(cpid, SIGKILL);
201 		} else {
202 			close(pdes[0]);
203 			signal(SIGPIPE, intcopy);
204 			transfer(buf, pdes[1], value(EOFREAD));
205 			signal(SIGPIPE, SIG_DFL);
206 			while ((p = wait(&status)) > 0 && p != cpid)
207 				;
208 		}
209 	} else {
210 		register int f;
211 
212 		userperm();
213 		dup2(pdes[0], 0);
214 		close(pdes[0]);
215 		for (f = 3; f < 20; f++)
216 			close(f);
217 		execute(buf);
218 		printf("can't execl!\r\n");
219 		exit(0);
220 	}
221 }
222 
223 /*
224  * FTP - local ==> remote
225  *  send local file to remote host
226  *  terminate transmission with pseudo EOF sequence
227  */
228 sendfile(cc)
229 	char cc;
230 {
231 	FILE *fd;
232 	char *fnamex;
233 	char *expand();
234 
235 	putchar(cc);
236 	/*
237 	 * get file name
238 	 */
239 	if (prompt("Local file name? ", fname, sizeof (fname)))
240 		return;
241 
242 	/*
243 	 * look up file
244 	 */
245 	fnamex = expand(fname);
246 	if (fnamex == NOSTR)
247 		return;
248 	if ((fd = fopen(fnamex, "r")) == NULL) {
249 		printf("%s: cannot open\r\n", fname);
250 		return;
251 	}
252 	transmit(fd, value(EOFWRITE), NULL);
253 	if (!boolean(value(ECHOCHECK))) {
254 		struct termios buf;
255 
256 		ioctl(FD, TCGETS, (char *)&buf);	/* this does a */
257 		ioctl(FD, TCSETSF, (char *)&buf);	/*   wflushtty */
258 	}
259 }
260 
261 /*
262  * Bulk transfer routine to remote host --
263  *   used by sendfile() and cu_put()
264  */
265 transmit(fd, eofchars, command)
266 	FILE *fd;
267 	char *eofchars, *command;
268 {
269 	void (*ointr)();
270 	char *pc, lastc, rc;
271 	int c, ccount, lcount;
272 	time_t start_t, stop_t;
273 
274 	kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
275 	timedout = 0;
276 	if (sigsetjmp(intbuf, 1)) {
277 		if (timedout)
278 			printf("\r\ntimed out at eol\r\n");
279 		alarm(0);
280 		goto out;
281 	}
282 	ointr = signal(SIGINT, intcopy);
283 	intr("on");
284 	read(repdes[0], (char *)&ccc, 1);
285 	if (command != NULL) {
286 		for (pc = command; *pc; pc++)
287 			send(*pc);
288 		if (boolean(value(ECHOCHECK)))
289 			read(FD, (char *)&c, 1);	/* trailing \n */
290 		else {
291 			struct termios buf;
292 
293 			sleep(5); /* wait for remote stty to take effect */
294 			ioctl(FD, TCGETS, (char *)&buf); /* this does a */
295 			ioctl(FD, TCSETSF, (char *)&buf); /*   wflushtty */
296 		}
297 	}
298 	lcount = 0;
299 	lastc = '\0';
300 	start_t = time(0);
301 	if (boolean(value(RAWFTP))) {
302 		while ((c = getc(fd)) != EOF) {
303 			lcount++;
304 			send(c);
305 			if (boolean(value(VERBOSE)) && lcount%100 == 0)
306 				printf("\r%d", lcount);
307 		}
308 		if (boolean(value(VERBOSE)))
309 			printf("\r%d", lcount);
310 		goto out;
311 	}
312 	for (;;) {
313 		ccount = 0;
314 		do {
315 			c = getc(fd);
316 			if (c == EOF)
317 				goto out;
318 			if (c == 0177)
319 				continue;
320 			lastc = c;
321 			if (c < 040) {
322 				if (c == '\n') {
323 					c = '\r';
324 				} else if (c == '\t') {
325 					if (boolean(value(TABEXPAND))) {
326 						send(' ');
327 						while ((++ccount % 8) != 0)
328 							send(' ');
329 						continue;
330 					}
331 				} else
332 					continue;
333 			}
334 			send(c);
335 		} while (c != '\r');
336 		if (boolean(value(VERBOSE)))
337 			printf("\r%d", ++lcount);
338 		if (boolean(value(ECHOCHECK))) {
339 			alarm(number(value(ETIMEOUT)));
340 			do {	/* wait for prompt */
341 				read(FD, &rc, 1);
342 			} while ((rc&0177) != character(value(PROMPT)));
343 			alarm(0);
344 		}
345 	}
346 out:
347 	if (lastc != '\n' && !boolean(value(RAWFTP)))
348 		send('\r');
349 	if (eofchars)
350 		for (pc = eofchars; *pc; pc++)
351 			send(*pc);
352 	stop_t = time(0);
353 	fclose(fd);
354 	if (boolean(value(VERBOSE)))
355 		if (boolean(value(RAWFTP)))
356 			prtime(" chars transferred in ", stop_t-start_t);
357 		else
358 			prtime(" lines transferred in ", stop_t-start_t);
359 	write(fildes[1], (char *)&ccc, 1);
360 	intr("off");
361 	signal(SIGINT, ointr);
362 }
363 
364 /*
365  * Cu-like put command
366  */
367 cu_put(cc)
368 	char cc;
369 {
370 	FILE *fd;
371 	char line[BUFSIZ];
372 	int argc;
373 	char *expand();
374 	char *copynamex;
375 
376 	if (prompt("[put] ", copyname, sizeof (copyname)))
377 		return;
378 	argc = args(copyname, argv, sizeof (argv)/sizeof (char *));
379 	if (argc < 1 || argc > 2) {
380 		printf("usage: <put> from [to]\r\n");
381 		return;
382 	}
383 	if (argc == 1)
384 		argv[1] = argv[0];
385 	copynamex = expand(argv[0]);
386 	if (copynamex == NOSTR)
387 		return;
388 	if ((fd = fopen(copynamex, "r")) == NULL) {
389 		printf("%s: cannot open\r\n", copynamex);
390 		return;
391 	}
392 	if (boolean(value(ECHOCHECK)))
393 		sprintf(line, "cat>%s\r", argv[1]);
394 	else
395 		sprintf(line, "stty -echo; cat>%s; stty echo\r", argv[1]);
396 	transmit(fd, "\04", line);
397 }
398 
399 /*
400  * FTP - send single character
401  *  wait for echo & handle timeout
402  */
403 send(c)
404 	char c;
405 {
406 	char cc;
407 	int retry = 0;
408 
409 	cc = c;
410 	parwrite(FD, &cc, 1);
411 #ifdef notdef
412 	if (number(value(CDELAY)) > 0 && c != '\r')
413 		nap(number(value(CDELAY)));
414 #endif
415 	if (!boolean(value(ECHOCHECK))) {
416 #ifdef notdef
417 		if (number(value(LDELAY)) > 0 && c == '\r')
418 			nap(number(value(LDELAY)));
419 #endif
420 		return;
421 	}
422 tryagain:
423 	timedout = 0;
424 	if (sigsetjmp(intbuf, 1) && timedout) {
425 		printf("\r\ntimeout error (%s)\r\n", ctrl(c));
426 		if (retry++ > 3)
427 			return;
428 		parwrite(FD, &null, 1); /* poke it */
429 		goto tryagain;
430 	}
431 	alarm(number(value(ETIMEOUT)));
432 	read(FD, &cc, 1);
433 	alarm(0);
434 }
435 
436 void
437 timeout()
438 {
439 	signal(SIGALRM, (sig_handler_t)timeout);
440 	timedout = 1;
441 	siglongjmp(intbuf, 1);
442 }
443 
444 /*
445  * Stolen from consh() -- puts a remote file on the output of a local command.
446  *	Identical to consh() except for where stdout goes.
447  */
448 pipeout(c)
449 {
450 	char buf[256];
451 	int cpid, status, p;
452 	time_t start;
453 
454 	putchar(c);
455 	if (prompt("Local command? ", buf, sizeof (buf)))
456 		return;
457 	kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
458 	signal(SIGINT, SIG_IGN);
459 	signal(SIGQUIT, SIG_IGN);
460 	intr("on");
461 	read(repdes[0], (char *)&ccc, 1);
462 	/*
463 	 * Set up file descriptors in the child and
464 	 *  let it go...
465 	 */
466 	if ((cpid = fork()) < 0)
467 		printf("can't fork!\r\n");
468 	else if (cpid) {
469 		start = time(0);
470 		while ((p = wait(&status)) > 0 && p != cpid)
471 			;
472 	} else {
473 		register int i;
474 
475 		userperm();
476 		dup2(FD, 1);
477 		for (i = 3; i < 20; i++)
478 			close(i);
479 		signal(SIGINT, SIG_DFL);
480 		signal(SIGQUIT, SIG_DFL);
481 		execute(buf);
482 		printf("can't find `%s'\r\n", buf);
483 		exit(0);
484 	}
485 	if (boolean(value(VERBOSE)))
486 		prtime("away for ", time(0)-start);
487 	write(fildes[1], (char *)&ccc, 1);
488 	intr("off");
489 	signal(SIGINT, SIG_DFL);
490 	signal(SIGQUIT, SIG_DFL);
491 }
492 
493 /*
494  * Fork a program with:
495  *  0 <-> remote tty in
496  *  1 <-> remote tty out
497  *  2 <-> local tty stderr out
498  */
499 consh(c)
500 {
501 	char buf[256];
502 	int cpid, status, p;
503 	void (*ointr)(), (*oquit)();
504 	time_t start;
505 
506 	putchar(c);
507 	if (prompt("Local command? ", buf, sizeof (buf)))
508 		return;
509 	kill(pid, SIGIOT);	/* put TIPOUT into a wait state */
510 	read(repdes[0], (char *)&ccc, 1);
511 	ointr = signal(SIGINT, SIG_IGN);
512 	oquit = signal(SIGQUIT, SIG_IGN);
513 	unraw();
514 	/*
515 	 * Set up file descriptors in the child and
516 	 *  let it go...
517 	 */
518 	if ((cpid = fork()) < 0)
519 		printf("can't fork!\r\n");
520 	else if (cpid) {
521 		start = time(0);
522 		while ((p = wait(&status)) > 0 && p != cpid)
523 			;
524 		raw();
525 		signal(SIGINT, ointr);
526 		signal(SIGQUIT, oquit);
527 	} else {
528 		register int i;
529 
530 		userperm();
531 		dup2(FD, 0);
532 		dup2(0, 1);
533 		for (i = 3; i < 20; i++)
534 			close(i);
535 		signal(SIGINT, SIG_DFL);
536 		signal(SIGQUIT, SIG_DFL);
537 		execute(buf);
538 		printf("can't find `%s'\r\n", buf);
539 		exit(0);
540 	}
541 	if (boolean(value(VERBOSE)))
542 		prtime("\r\naway for ", time(0)-start);
543 	write(fildes[1], (char *)&ccc, 1);
544 }
545 
546 /*
547  * Escape to local shell
548  */
549 shell()
550 {
551 	int shpid, status;
552 	void (*ointr)(), (*oquit)();
553 	char *cp;
554 
555 	printf("[sh]\r\n");
556 	ointr = signal(SIGINT, SIG_IGN);
557 	oquit = signal(SIGQUIT, SIG_IGN);
558 	unraw();
559 	if (shpid = fork()) {
560 		while (shpid != wait(&status))
561 			;
562 		raw();
563 		printf("\r\n!\r\n");
564 		signal(SIGINT, ointr);
565 		signal(SIGQUIT, oquit);
566 	} else {
567 		userperm();
568 		signal(SIGQUIT, SIG_DFL);
569 		signal(SIGINT, SIG_DFL);
570 		if ((cp = strrchr(value(SHELL), '/')) == NULL)
571 			cp = value(SHELL);
572 		else
573 			cp++;
574 		execl(value(SHELL), cp, 0);
575 		printf("\r\ncan't execl!\r\n");
576 		exit(1);
577 	}
578 }
579 
580 /*
581  * TIPIN portion of scripting
582  *   initiate the conversation with TIPOUT
583  */
584 setscript()
585 {
586 	char c;
587 	/*
588 	 * enable TIPOUT side for dialogue
589 	 */
590 	kill(pid, SIGEMT);
591 	if (boolean(value(SCRIPT)))
592 		write(fildes[1], value(RECORD), strlen(value(RECORD)));
593 	write(fildes[1], "\n", 1);
594 	/*
595 	 * wait for TIPOUT to finish
596 	 */
597 	read(repdes[0], &c, 1);
598 	if (c == 'n')
599 		fprintf(stderr, "tip: can't create record file %s\r\n",
600 		    value(RECORD));
601 }
602 
603 /*
604  * Change current working directory of
605  *   local portion of tip
606  */
607 chdirectory()
608 {
609 	char dirname[80];
610 	register char *cp = dirname;
611 
612 	if (prompt("[cd] ", dirname, sizeof (dirname))) {
613 		if (stoprompt)
614 			return;
615 		cp = value(HOME);
616 	}
617 	if (chdir(cp) < 0)
618 		printf("%s: bad directory\r\n", cp);
619 	printf("!\r\n");
620 }
621 
622 /* XXX - really should rename this routine to avoid conflict with libc */
623 abort(msg)
624 	char *msg;
625 {
626 
627 	signal(SIGCHLD, SIG_DFL);	/* don't want to hear about our child */
628 	kill(pid, SIGTERM);
629 	myperm();
630 	disconnect(msg);
631 	if (msg != NOSTR)
632 		printf("\r\n%s", msg);
633 	printf("\r\n[EOT]\r\n");
634 	delock(uucplock);
635 	unraw();
636 	exit(0);
637 }
638 
639 finish()
640 {
641 	char *dismsg;
642 
643 	if ((dismsg = value(DISCONNECT)) != NOSTR) {
644 		write(FD, dismsg, strlen(dismsg));
645 		sleep(5);
646 	}
647 	abort(NOSTR);
648 }
649 
650 void
651 intcopy()
652 {
653 
654 	signal(SIGINT, SIG_IGN);
655 	siglongjmp(intbuf, 1);
656 }
657 
658 execute(s)
659 	char *s;
660 {
661 	register char *cp;
662 
663 	if ((cp = strrchr(value(SHELL), '/')) == NULL)
664 		cp = value(SHELL);
665 	else
666 		cp++;
667 	execl(value(SHELL), cp, "-c", s, 0);
668 }
669 
670 args(buf, a, na)
671 	char *buf, *a[];
672 	size_t na;
673 {
674 	register char *p = buf, *start;
675 	register char **parg = a;
676 	register int n = 0;
677 
678 	do {
679 		while (*p && (*p == ' ' || *p == '\t'))
680 			p++;
681 		start = p;
682 		if (*p)
683 			*parg = p;
684 		while (*p && (*p != ' ' && *p != '\t'))
685 			p++;
686 		if (p != start)
687 			parg++, n++;
688 		if (*p)
689 			*p++ = '\0';
690 	} while (*p && n < na);
691 
692 	return (n);
693 }
694 
695 prtime(s, a)
696 	char *s;
697 	time_t a;
698 {
699 	register i;
700 	int nums[3];
701 
702 	for (i = 0; i < 3; i++) {
703 		nums[i] = (int)(a % quant[i]);
704 		a /= quant[i];
705 	}
706 	printf("%s", s);
707 	while (--i >= 0)
708 		if (nums[i] || i == 0 && nums[1] == 0 && nums[2] == 0)
709 			printf("%d %s%c ", nums[i], sep[i],
710 				nums[i] == 1 ? '\0' : 's');
711 	printf("\r\n!\r\n");
712 }
713 
714 variable()
715 {
716 	char	buf[256];
717 
718 	if (prompt("[set] ", buf, sizeof (buf)))
719 		return;
720 	vlex(buf);
721 	if (vtable[BEAUTIFY].v_access&CHANGED) {
722 		vtable[BEAUTIFY].v_access &= ~CHANGED;
723 		kill(pid, SIGSYS);
724 	}
725 	if (vtable[SCRIPT].v_access&CHANGED) {
726 		vtable[SCRIPT].v_access &= ~CHANGED;
727 		setscript();
728 		/*
729 		 * So that "set record=blah script" doesn't
730 		 *  cause two transactions to occur.
731 		 */
732 		if (vtable[RECORD].v_access&CHANGED)
733 			vtable[RECORD].v_access &= ~CHANGED;
734 	}
735 	if (vtable[RECORD].v_access&CHANGED) {
736 		vtable[RECORD].v_access &= ~CHANGED;
737 		if (boolean(value(SCRIPT)))
738 			setscript();
739 	}
740 	if (vtable[TAND].v_access&CHANGED) {
741 		vtable[TAND].v_access &= ~CHANGED;
742 		if (boolean(value(TAND)))
743 			tandem("on");
744 		else
745 			tandem("off");
746 	}
747 	if (vtable[LECHO].v_access&CHANGED) {
748 		vtable[LECHO].v_access &= ~CHANGED;
749 		boolean(value(HALFDUPLEX)) = boolean(value(LECHO));
750 	}
751 	if (vtable[PARITY].v_access&CHANGED) {
752 		vtable[PARITY].v_access &= ~CHANGED;
753 		setparity(NULL);
754 	}
755 	if (vtable[BAUDRATE].v_access&CHANGED) {
756 		vtable[BAUDRATE].v_access &= ~CHANGED;
757 		ttysetup(speed(number(value(BAUDRATE))));
758 	}
759 	if (vtable[HARDWAREFLOW].v_access & CHANGED) {
760 		vtable[HARDWAREFLOW].v_access &= ~CHANGED;
761 		if (boolean(value(HARDWAREFLOW)))
762 			hardwareflow("on");
763 		else
764 			hardwareflow("off");
765 	}
766 }
767 
768 /*
769  * Turn tandem mode on or off for remote tty.
770  */
771 tandem(option)
772 	char *option;
773 {
774 	struct termios rmtty;
775 
776 	ioctl(FD, TCGETS, (char *)&rmtty);
777 	if (equal(option, "on")) {
778 		rmtty.c_iflag |= IXOFF|IXON;
779 		arg.c_iflag |= IXOFF|IXON;
780 		rmtty.c_cc[VSTART] = defarg.c_cc[VSTART];
781 		rmtty.c_cc[VSTOP] = defarg.c_cc[VSTOP];
782 	} else {
783 		rmtty.c_iflag &= ~(IXOFF|IXON);
784 		arg.c_iflag &= ~(IXOFF|IXON);
785 	}
786 	ioctl(FD, TCSETSF, (char *)&rmtty);
787 	ioctl(0, TCSETSF, (char *)&arg);
788 }
789 
790 /*
791  * Turn hardwareflow mode on or off for remote tty.
792  */
793 hardwareflow(option)
794 	char *option;
795 {
796 	struct termios rmtty;
797 
798 	ioctl(FD, TCGETS, (char *)&rmtty);
799 	if (equal(option, "on")) {
800 		rmtty.c_cflag |= (CRTSCTS|CRTSXOFF);
801 	} else {
802 		rmtty.c_cflag &= ~(CRTSCTS|CRTSXOFF);
803 	}
804 	ioctl(FD, TCSETSF, (char *)&rmtty);
805 }
806 
807 /*
808  * Turn interrupts from local tty on or off.
809  */
810 intr(option)
811 	char *option;
812 {
813 
814 	if (equal(option, "on"))
815 		arg.c_lflag |= ISIG;
816 	else
817 		arg.c_lflag &= ~ISIG;
818 	ioctl(0, TCSETSF, (char *)&arg);
819 }
820 
821 /*
822  * Send a break.
823  */
824 genbrk()
825 {
826 
827 	ioctl(FD, TCSBRK, 0);
828 }
829 
830 /*
831  * Suspend tip
832  */
833 suspend(c)
834 	char c;
835 {
836 
837 	unraw();
838 	kill(c == _CTRL('y') ? getpid() : 0, SIGTSTP);
839 	raw();
840 }
841 
842 /*
843  *	expand a file name if it includes shell meta characters
844  */
845 
846 char *
847 expand(name)
848 	char name[];
849 {
850 	static char xname[BUFSIZ];
851 	char cmdbuf[BUFSIZ];
852 	register int pid, l, rc;
853 	register char *cp, *Shell;
854 	int s, pivec[2];
855 	void (*sigint)();
856 
857 	if (!anyof(name, "~{[*?$`'\"\\"))
858 		return (name);
859 	/* sigint = signal(SIGINT, SIG_IGN); */
860 	if (pipe(pivec) < 0) {
861 		perror("pipe");
862 		/* signal(SIGINT, sigint) */
863 		return (name);
864 	}
865 	sprintf(cmdbuf, "echo %s", name);
866 	if ((pid = vfork()) == 0) {
867 		userperm();
868 		Shell = value(SHELL);
869 		if (Shell == NOSTR)
870 			Shell = "/bin/sh";
871 		close(pivec[0]);
872 		close(1);
873 		dup(pivec[1]);
874 		close(pivec[1]);
875 		close(2);
876 		execl(Shell, Shell, "-c", cmdbuf, 0);
877 		_exit(1);
878 	}
879 	if (pid == -1) {
880 		perror("fork");
881 		close(pivec[0]);
882 		close(pivec[1]);
883 		return (NOSTR);
884 	}
885 	close(pivec[1]);
886 	l = read(pivec[0], xname, BUFSIZ);
887 	close(pivec[0]);
888 	while (wait(&s) != pid);
889 		;
890 	s &= 0377;
891 	if (s != 0 && s != SIGPIPE) {
892 		fprintf(stderr, "\"Echo\" failed\n");
893 		return (NOSTR);
894 	}
895 	if (l < 0) {
896 		perror("read");
897 		return (NOSTR);
898 	}
899 	if (l == 0) {
900 		fprintf(stderr, "\"%s\": No match\n", name);
901 		return (NOSTR);
902 	}
903 	if (l == BUFSIZ) {
904 		fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
905 		return (NOSTR);
906 	}
907 	xname[l] = 0;
908 	for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
909 		;
910 	*++cp = '\0';
911 	return (xname);
912 }
913 
914 /*
915  * Are any of the characters in the two strings the same?
916  */
917 
918 anyof(s1, s2)
919 	register char *s1, *s2;
920 {
921 	register int c;
922 
923 	while (c = *s1++)
924 		if (any(c, s2))
925 			return (1);
926 	return (0);
927 }
928