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