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