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