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