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