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