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