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