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