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