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