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