2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * @(#)cmds.c 8.1 (Berkeley) 6/6/93
30 * $FreeBSD: src/usr.bin/tip/tip/cmds.c,v 1.11.2.2 2000/07/01 12:24:23 ps Exp $
34 #include "pathnames.h"
36 #include <sys/types.h>
46 * miscellaneous commands
49 int quant[] = { 60, 60, 24 };
52 char *sep[] = { "second", "minute", "hour" };
53 static char *argv[10]; /* argument vector for take and put */
55 static void stopsnd(int); /* SIGINT handler during file transfers */
56 static void intcopy(int); /* interrupt routine for file transfers */
58 static int anyof(char *, char *);
59 static void tandem(char *);
60 static void prtime(char *, time_t);
61 static int args(char *, char **, int);
62 static void execute(char *);
63 static void send(char);
64 static void transmit(FILE *, char *, char *);
65 static void transfer(char *, int, char *);
66 static void xfer(char *, int, char *);
72 struct termios ttermios;
74 for (cnt = 0; cnt < NCCS; cnt++)
75 ttermios.c_cc [cnt] = otermios.c_cc [cnt];
76 tcsetattr (0, TCSANOW, &ttermios);
82 tcsetattr (0, TCSANOW, &ctermios);
89 ioctl (FD, TIOCFLUSH, &cmd);
93 * FTP - remote ==> local
94 * get a file from the remote host
103 * get the UNIX receiving file's name
105 if (prompt("Local file name? ", copyname, sizeof(copyname)))
107 cp = expand(copyname);
108 if ((sfd = creat(cp, 0666)) < 0) {
109 printf("\r\n%s: cannot creat\r\n", copyname);
116 if (prompt("List command for remote system? ", buf, sizeof(buf))) {
120 transfer(buf, sfd, value(EOFREAD));
124 * Cu-like take command
130 char line[BUFSIZ], *cp;
132 if (prompt("[take] ", copyname, sizeof(copyname)))
134 if ((argc = args(copyname, argv, sizeof(argv)/sizeof(argv[0]))) < 1 || argc > 2) {
135 printf("usage: <take> from [to]\r\n");
140 cp = expand(argv[1]);
141 if ((fd = creat(cp, 0666)) < 0) {
142 printf("\r\n%s: cannot create\r\n", argv[1]);
145 (void)snprintf(line, sizeof(line), "cat %s ; echo \"\" ; echo ___tip_end_of_file_marker___", argv[0]);
146 xfer(line, fd, "\n___tip_end_of_file_marker___\n");
149 static jmp_buf intbuf;
152 xfer(char *buf, int fd, char *eofchars)
162 v = boolean(value(VERBOSE));
164 if ((ff = fdopen (fd, "w")) == NULL) {
168 if ((cnt = number(value(FRAMESIZE))) != BUFSIZ)
169 if (setvbuf(ff, NULL, _IOFBF, cnt) != 0) {
170 warn("file allocation");
175 xpwrite(FD, buf, size(buf));
178 read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */
187 while ((c&0177) != '\n');
191 (void) setjmp(intbuf);
192 f = signal(SIGINT, intcopy);
195 for (ct = 0; !quit;) {
196 eof = read(FD, &c, 1) <= 0;
203 continue; /* ignore nulls */
206 if (c != *match && match > eofchars) {
210 (void)printf("\r%d", ++ct);
216 if (*++match == '\0')
220 (void)printf("\r%d", ++ct);
225 prtime(" lines transferred in ", time(0)-start);
227 write(fildes[1], (char *)&ccc, 1);
233 * Bulk transfer routine --
234 * used by getfl(), cu_take(), and pipefile()
237 transfer(char *buf, int fd, char *eofchars)
247 v = boolean(value(VERBOSE));
249 if ((ff = fdopen (fd, "w")) == NULL) {
253 if ((cnt = number(value(FRAMESIZE))) != BUFSIZ)
254 if (setvbuf(ff, NULL, _IOFBF, cnt) != 0) {
255 warn("file allocation");
260 xpwrite(FD, buf, size(buf));
263 read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */
272 while ((c&0177) != '\n');
274 (void) setjmp(intbuf);
275 f = signal(SIGINT, intcopy);
277 for (ct = 0; !quit;) {
278 eof = read(FD, &c, 1) <= 0;
282 if (eof || any(c, eofchars))
285 continue; /* ignore nulls */
289 printf("\r%d", ++ct);
293 prtime(" lines transferred in ", time(0)-start);
295 write(fildes[1], (char *)&ccc, 1);
301 * FTP - remote ==> local process
302 * send remote input to local process via pipe
311 if (prompt("Local command? ", buf, sizeof(buf)))
315 printf("can't establish pipe\r\n");
319 if ((cpid = fork()) < 0) {
320 printf("can't fork!\r\n");
323 if (prompt("List command for remote system? ", buf, sizeof(buf))) {
324 close(pdes[0]), close(pdes[1]);
325 kill (cpid, SIGKILL);
328 signal(SIGPIPE, intcopy);
329 transfer(buf, pdes[1], value(EOFREAD));
330 signal(SIGPIPE, SIG_DFL);
331 while ((p = wait(&status)) > 0 && p != cpid)
339 for (f = 3; f < 20; f++)
342 printf("can't execl!\r\n");
348 * Interrupt service routine for FTP
355 signal(SIGINT, SIG_IGN);
359 * FTP - local ==> remote
360 * send local file to remote host
361 * terminate transmission with pseudo EOF sequence
373 if (prompt("Local file name? ", fname, sizeof(fname)))
379 fnamex = expand(fname);
380 if ((fd = fopen(fnamex, "r")) == NULL) {
381 printf("%s: cannot open\r\n", fname);
384 transmit(fd, value(EOFWRITE), NULL);
385 if (!boolean(value(ECHOCHECK))) {
391 * Bulk transfer routine to remote host --
392 * used by sendfile() and cu_put()
395 transmit(FILE *fd, char *eofchars, char *command)
398 int c, ccount, lcount;
399 time_t start_t, stop_t;
402 kill(pid, SIGIOT); /* put TIPOUT into a wait state */
404 f = signal(SIGINT, stopsnd);
406 read(repdes[0], (char *)&ccc, 1);
407 if (command != NULL) {
408 for (pc = command; *pc; pc++)
410 if (boolean(value(ECHOCHECK)))
411 read(FD, (char *)&c, 1); /* trailing \n */
414 sleep(5); /* wait for remote stty to take effect */
428 if (c == 0177 && !boolean(value(RAWFTP)))
433 if (!boolean(value(RAWFTP)))
436 else if (c == '\t') {
437 if (!boolean(value(RAWFTP))) {
438 if (boolean(value(TABEXPAND))) {
440 while ((++ccount % 8) != 0)
446 if (!boolean(value(RAWFTP)))
450 } while (c != '\r' && !boolean(value(RAWFTP)));
451 if (boolean(value(VERBOSE)))
452 printf("\r%d", ++lcount);
453 if (boolean(value(ECHOCHECK))) {
455 alarm(number(value(ETIMEOUT)));
456 do { /* wait for prompt */
457 read(FD, (char *)&c, 1);
458 if (timedout || stop) {
460 printf("\r\ntimed out at eol\r\n");
464 } while ((c&0177) != character(value(PROMPT)));
469 if (lastc != '\n' && !boolean(value(RAWFTP)))
471 for (pc = eofchars; pc && *pc; pc++)
476 if (boolean(value(VERBOSE))) {
477 if (boolean(value(RAWFTP)))
478 prtime(" chars transferred in ", stop_t-start_t);
480 prtime(" lines transferred in ", stop_t-start_t);
482 write(fildes[1], (char *)&ccc, 1);
487 * Cu-like put command
497 if (prompt("[put] ", copyname, sizeof(copyname)))
499 if ((argc = args(copyname, argv, sizeof(argv)/sizeof(argv[0]))) < 1 || argc > 2) {
500 printf("usage: <put> from [to]\r\n");
505 copynamex = expand(argv[0]);
506 if ((fd = fopen(copynamex, "r")) == NULL) {
507 printf("%s: cannot open\r\n", copynamex);
510 if (boolean(value(ECHOCHECK)))
511 snprintf(line, sizeof(line), "cat>%s\r", argv[1]);
513 snprintf(line, sizeof(line), "stty -echo;cat>%s;stty echo\r", argv[1]);
514 transmit(fd, "\04", line);
521 if (usleep(msec*1000) != 0) {
522 fprintf ( stderr, "warning: ldelay or cdelay interrupted, "
523 "delay time cut short: %s\n",
532 * FTP - send single character
533 * wait for echo & handle timeout
543 if (number(value(CDELAY)) > 0 && c != '\r')
544 nap(number(value(CDELAY)));
545 if (!boolean(value(ECHOCHECK))) {
546 if (number(value(LDELAY)) > 0 && c == '\r')
547 nap(number(value(LDELAY)));
552 alarm(number(value(ETIMEOUT)));
556 printf("\r\ntimeout error (%s)\r\n", ctrl(c));
559 xpwrite(FD, &null, 1); /* poke it */
565 timeoutfunc(int __dummy)
567 signal(SIGALRM, timeoutfunc);
572 * Stolen from consh() -- puts a remote file on the output of a local command.
573 * Identical to consh() except for where stdout goes.
583 if (prompt("Local command? ", buf, sizeof(buf)))
585 kill(pid, SIGIOT); /* put TIPOUT into a wait state */
586 signal(SIGINT, SIG_IGN);
587 signal(SIGQUIT, SIG_IGN);
589 read(repdes[0], (char *)&ccc, 1);
591 * Set up file descriptors in the child and
594 if ((cpid = fork()) < 0)
595 printf("can't fork!\r\n");
598 while ((p = wait(&status)) > 0 && p != cpid)
604 for (i = 3; i < 20; i++)
606 signal(SIGINT, SIG_DFL);
607 signal(SIGQUIT, SIG_DFL);
609 printf("can't find `%s'\r\n", buf);
612 if (boolean(value(VERBOSE)))
613 prtime("away for ", time(0)-start);
614 write(fildes[1], (char *)&ccc, 1);
616 signal(SIGINT, SIG_DFL);
617 signal(SIGQUIT, SIG_DFL);
621 tiplink (char *cmd, unsigned int flags)
626 if (flags & TL_SIGNAL_TIPOUT) {
627 kill(pid, SIGIOT); /* put TIPOUT into a wait state */
628 signal(SIGINT, SIG_IGN);
629 signal(SIGQUIT, SIG_IGN);
631 read(repdes[0], (char *)&ccc, 1);
635 * Set up file descriptors in the child and
638 if ((cpid = fork()) < 0)
639 printf("can't fork!\r\n");
642 while ((p = wait(&status)) > 0 && p != cpid)
649 for (fd = 3; fd < 20; fd++)
651 signal(SIGINT, SIG_DFL);
652 signal(SIGQUIT, SIG_DFL);
654 printf("can't find `%s'\r\n", cmd);
658 if (flags & TL_VERBOSE && boolean(value(VERBOSE)))
659 prtime("away for ", time(0)-start);
661 if (flags & TL_SIGNAL_TIPOUT) {
662 write(fildes[1], (char *)&ccc, 1);
664 signal(SIGINT, SIG_DFL);
665 signal(SIGQUIT, SIG_DFL);
672 * Fork a program with:
673 * 0 <-> remote tty in
674 * 1 <-> remote tty out
675 * 2 <-> local tty out
682 if (prompt("Local command? ", buf, sizeof(buf)))
684 tiplink (buf, TL_SIGNAL_TIPOUT | TL_VERBOSE);
688 * Escape to local shell
697 signal(SIGINT, SIG_IGN);
698 signal(SIGQUIT, SIG_IGN);
700 if ((shpid = fork())) {
701 while (shpid != wait(&status));
704 signal(SIGINT, SIG_DFL);
705 signal(SIGQUIT, SIG_DFL);
708 signal(SIGQUIT, SIG_DFL);
709 signal(SIGINT, SIG_DFL);
710 if ((cp = rindex(value(SHELL), '/')) == NULL)
715 execl(value(SHELL), cp, NULL);
716 printf("\r\ncan't execl!\r\n");
722 * TIPIN portion of scripting
723 * initiate the conversation with TIPOUT
730 * enable TIPOUT side for dialogue
733 if (boolean(value(SCRIPT)))
734 write(fildes[1], value(RECORD), size(value(RECORD)));
735 write(fildes[1], "\n", 1);
737 * wait for TIPOUT to finish
739 read(repdes[0], &c, 1);
741 printf("can't create %s\r\n", value(RECORD));
745 * Change current working directory of
746 * local portion of tip
751 char dirname[PATH_MAX];
754 if (prompt("[cd] ", dirname, sizeof(dirname))) {
760 printf("%s: bad directory\r\n", cp);
771 printf("\r\n%s", msg);
772 printf("\r\n[EOT]\r\n");
774 (void)uu_unlock(uucplock);
782 char *abortmsg = NULL, *dismsg;
784 if (LO != NULL && tiplink (LO, TL_SIGNAL_TIPOUT) != 0) {
785 abortmsg = "logout failed";
788 if ((dismsg = value(DISCONNECT)) != NULL) {
789 write(FD, dismsg, strlen(dismsg));
808 if ((cp = rindex(value(SHELL), '/')) == NULL)
813 execl(value(SHELL), cp, "-c", s, NULL);
817 args(char *buf, char **a, int num)
819 char *p = buf, *start;
823 while (*p && n < num) {
824 while (*p && (*p == ' ' || *p == '\t'))
829 while (*p && (*p != ' ' && *p != '\t'))
840 prtime(char *s, time_t a)
845 for (i = 0; i < 3; i++) {
846 nums[i] = (int)(a % quant[i]);
851 if (nums[i] || (i == 0 && nums[1] == 0 && nums[2] == 0))
852 printf("%d %s%c ", nums[i], sep[i],
853 nums[i] == 1 ? '\0' : 's');
862 if (prompt("[set] ", buf, sizeof(buf)))
865 if (vtable[BEAUTIFY].v_access&CHANGED) {
866 vtable[BEAUTIFY].v_access &= ~CHANGED;
869 if (vtable[SCRIPT].v_access&CHANGED) {
870 vtable[SCRIPT].v_access &= ~CHANGED;
873 * So that "set record=blah script" doesn't
874 * cause two transactions to occur.
876 if (vtable[RECORD].v_access&CHANGED)
877 vtable[RECORD].v_access &= ~CHANGED;
879 if (vtable[RECORD].v_access&CHANGED) {
880 vtable[RECORD].v_access &= ~CHANGED;
881 if (boolean(value(SCRIPT)))
884 if (vtable[TAND].v_access&CHANGED) {
885 vtable[TAND].v_access &= ~CHANGED;
886 if (boolean(value(TAND)))
891 if (vtable[LECHO].v_access&CHANGED) {
892 vtable[LECHO].v_access &= ~CHANGED;
893 HD = boolean(value(LECHO));
895 if (vtable[PARITY].v_access&CHANGED) {
896 vtable[PARITY].v_access &= ~CHANGED;
897 setparity(value(PARITY));
902 * Turn tandem mode on or off for remote tty.
907 struct termios ttermios;
908 tcgetattr (FD, &ttermios);
909 if (strcmp(option,"on") == 0) {
910 ttermios.c_iflag |= IXOFF;
911 ctermios.c_iflag |= IXOFF;
914 ttermios.c_iflag &= ~IXOFF;
915 ctermios.c_iflag &= ~IXOFF;
917 tcsetattr (FD, TCSANOW, &ttermios);
918 tcsetattr (0, TCSANOW, &ctermios);
928 ioctl(FD, TIOCSBRK, NULL);
930 ioctl(FD, TIOCCBRK, NULL);
941 kill(c == CTRL('y') ? getpid() : 0, SIGTSTP);
946 * expand a file name if it includes shell meta characters
952 static char xname[BUFSIZ];
956 int s, pivec[2] /*, (*sigint)()*/;
958 if (!anyof(name, "~{[*?$`'\"\\"))
960 /* sigint = signal(SIGINT, SIG_IGN); */
961 if (pipe(pivec) < 0) {
963 /* signal(SIGINT, sigint) */
966 snprintf(cmdbuf, sizeof(cmdbuf), "echo %s", name);
967 if ((pid = vfork()) == 0) {
968 Shell = value(SHELL);
970 Shell = _PATH_BSHELL;
977 execl(Shell, Shell, "-c", cmdbuf, NULL);
987 l = read(pivec[0], xname, BUFSIZ);
989 while (wait(&s) != pid)
992 if (s != 0 && s != SIGPIPE) {
993 fprintf(stderr, "\"Echo\" failed\n");
1001 fprintf(stderr, "\"%s\": No match\n", name);
1005 fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
1009 for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
1016 * Are any of the characters in the two strings the same?
1020 anyof(char *s1, char *s2)