]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/tip/tip/cmds.c
Remove spurious newline
[FreeBSD/FreeBSD.git] / usr.bin / tip / tip / cmds.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
690 intcopy(int signo)
691 {
692         raw();
693         quit = 1;
694         longjmp(intbuf, 1);
695 }
696
697 static void
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
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
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
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
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
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
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
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
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
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 *
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
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 }