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