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