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. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * @(#)cmds.c 8.1 (Berkeley) 6/6/93
34 * $FreeBSD: src/usr.bin/tip/tip/cmds.c,v 1.11.2.2 2000/07/01 12:24:23 ps Exp $
39 #include "pathnames.h"
41 #include <sys/types.h>
51 * miscellaneous commands
54 int quant[] = { 60, 60, 24 };
57 char *sep[] = { "second", "minute", "hour" };
58 static char *argv[10]; /* argument vector for take and put */
60 void timeout(int); /* timeout function called on alarm */
61 static void stopsnd(int); /* SIGINT handler during file transfers */
62 static void intcopy(); /* interrupt routine for file transfers */
68 void tipabort(char *);
69 void chdirectory(void);
77 static int anyof(char *, char *);
78 static void tandem(char *);
79 static void prtime(char *, time_t);
80 static int args(char *, char **, int);
81 static void execute(char *);
82 static void send(char);
83 static void transmit(FILE *, char *, char *);
84 static void transfer(char *, int, char *);
85 static void xfer(char *, int, char *);
92 struct termios ttermios;
94 for (cnt = 0; cnt < NCCS; cnt++)
95 ttermios.c_cc [cnt] = otermios.c_cc [cnt];
96 tcsetattr (0, TCSANOW, &ttermios);
98 ioctl(0, TIOCSETC, &defchars);
106 tcsetattr (0, TCSANOW, &ctermios);
108 ioctl(0, TIOCSETC, &tchars);
117 ioctl (FD, TIOCFLUSH, &cmd);
120 ioctl (FD, TIOCGETP, &buf); /* this does a */
121 ioctl (FD, TIOCSETP, &buf); /* wflushtty */
126 * FTP - remote ==> local
127 * get a file from the remote host
132 char buf[256], *cp, *expand();
136 * get the UNIX receiving file's name
138 if (prompt("Local file name? ", copyname, sizeof(copyname)))
140 cp = expand(copyname);
141 if ((sfd = creat(cp, 0666)) < 0) {
142 printf("\r\n%s: cannot creat\r\n", copyname);
149 if (prompt("List command for remote system? ", buf, sizeof(buf))) {
153 transfer(buf, sfd, value(EOFREAD));
157 * Cu-like take command
163 char line[BUFSIZ], *expand(), *cp;
165 if (prompt("[take] ", copyname, sizeof(copyname)))
167 if ((argc = args(copyname, argv, sizeof(argv)/sizeof(argv[0]))) < 1 || argc > 2) {
168 printf("usage: <take> from [to]\r\n");
173 cp = expand(argv[1]);
174 if ((fd = creat(cp, 0666)) < 0) {
175 printf("\r\n%s: cannot create\r\n", argv[1]);
178 (void)snprintf(line, sizeof(line), "cat %s ; echo \"\" ; echo ___tip_end_of_file_marker___", argv[0]);
179 xfer(line, fd, "\n___tip_end_of_file_marker___\n");
182 static jmp_buf intbuf;
185 xfer(char *buf, int fd, char *eofchars)
195 v = boolean(value(VERBOSE));
197 if ((ff = fdopen (fd, "w")) == NULL) {
201 if ((cnt = number(value(FRAMESIZE))) != BUFSIZ)
202 if (setvbuf(ff, NULL, _IOFBF, cnt) != 0) {
203 warn("file allocation");
208 xpwrite(FD, buf, size(buf));
211 read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */
220 while ((c&0177) != '\n');
224 (void) setjmp(intbuf);
225 f = signal(SIGINT, intcopy);
228 for (ct = 0; !quit;) {
229 eof = read(FD, &c, 1) <= 0;
236 continue; /* ignore nulls */
239 if (c != *match && match > eofchars) {
243 (void)printf("\r%d", ++ct);
249 if (*++match == '\0')
253 (void)printf("\r%d", ++ct);
258 prtime(" lines transferred in ", time(0)-start);
260 write(fildes[1], (char *)&ccc, 1);
266 * Bulk transfer routine --
267 * used by getfl(), cu_take(), and pipefile()
270 transfer(char *buf, int fd, char *eofchars)
280 v = boolean(value(VERBOSE));
282 if ((ff = fdopen (fd, "w")) == NULL) {
286 if ((cnt = number(value(FRAMESIZE))) != BUFSIZ)
287 if (setvbuf(ff, NULL, _IOFBF, cnt) != 0) {
288 warn("file allocation");
293 xpwrite(FD, buf, size(buf));
296 read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */
305 while ((c&0177) != '\n');
307 (void) setjmp(intbuf);
308 f = signal(SIGINT, intcopy);
310 for (ct = 0; !quit;) {
311 eof = read(FD, &c, 1) <= 0;
315 if (eof || any(c, eofchars))
318 continue; /* ignore nulls */
322 printf("\r%d", ++ct);
326 prtime(" lines transferred in ", time(0)-start);
328 write(fildes[1], (char *)&ccc, 1);
334 * FTP - remote ==> local process
335 * send remote input to local process via pipe
344 if (prompt("Local command? ", buf, sizeof(buf)))
348 printf("can't establish pipe\r\n");
352 if ((cpid = fork()) < 0) {
353 printf("can't fork!\r\n");
356 if (prompt("List command for remote system? ", buf, sizeof(buf))) {
357 close(pdes[0]), close(pdes[1]);
358 kill (cpid, SIGKILL);
361 signal(SIGPIPE, intcopy);
362 transfer(buf, pdes[1], value(EOFREAD));
363 signal(SIGPIPE, SIG_DFL);
364 while ((p = wait(&status)) > 0 && p != cpid)
372 for (f = 3; f < 20; f++)
375 printf("can't execl!\r\n");
381 * Interrupt service routine for FTP
388 signal(SIGINT, SIG_IGN);
392 * FTP - local ==> remote
393 * send local file to remote host
394 * terminate transmission with pseudo EOF sequence
407 if (prompt("Local file name? ", fname, sizeof(fname)))
413 fnamex = expand(fname);
414 if ((fd = fopen(fnamex, "r")) == NULL) {
415 printf("%s: cannot open\r\n", fname);
418 transmit(fd, value(EOFWRITE), NULL);
419 if (!boolean(value(ECHOCHECK))) {
425 * Bulk transfer routine to remote host --
426 * used by sendfile() and cu_put()
429 transmit(FILE *fd, char *eofchars, char *command)
432 int c, ccount, lcount;
433 time_t start_t, stop_t;
436 kill(pid, SIGIOT); /* put TIPOUT into a wait state */
438 f = signal(SIGINT, stopsnd);
440 read(repdes[0], (char *)&ccc, 1);
441 if (command != NULL) {
442 for (pc = command; *pc; pc++)
444 if (boolean(value(ECHOCHECK)))
445 read(FD, (char *)&c, 1); /* trailing \n */
448 sleep(5); /* wait for remote stty to take effect */
462 if (c == 0177 && !boolean(value(RAWFTP)))
467 if (!boolean(value(RAWFTP)))
470 else if (c == '\t') {
471 if (!boolean(value(RAWFTP))) {
472 if (boolean(value(TABEXPAND))) {
474 while ((++ccount % 8) != 0)
480 if (!boolean(value(RAWFTP)))
484 } while (c != '\r' && !boolean(value(RAWFTP)));
485 if (boolean(value(VERBOSE)))
486 printf("\r%d", ++lcount);
487 if (boolean(value(ECHOCHECK))) {
489 alarm(number(value(ETIMEOUT)));
490 do { /* wait for prompt */
491 read(FD, (char *)&c, 1);
492 if (timedout || stop) {
494 printf("\r\ntimed out at eol\r\n");
498 } while ((c&0177) != character(value(PROMPT)));
503 if (lastc != '\n' && !boolean(value(RAWFTP)))
505 for (pc = eofchars; pc && *pc; pc++)
510 if (boolean(value(VERBOSE)))
511 if (boolean(value(RAWFTP)))
512 prtime(" chars transferred in ", stop_t-start_t);
514 prtime(" lines transferred in ", stop_t-start_t);
515 write(fildes[1], (char *)&ccc, 1);
520 * Cu-like put command
531 if (prompt("[put] ", copyname, sizeof(copyname)))
533 if ((argc = args(copyname, argv, sizeof(argv)/sizeof(argv[0]))) < 1 || argc > 2) {
534 printf("usage: <put> from [to]\r\n");
539 copynamex = expand(argv[0]);
540 if ((fd = fopen(copynamex, "r")) == NULL) {
541 printf("%s: cannot open\r\n", copynamex);
544 if (boolean(value(ECHOCHECK)))
545 snprintf(line, sizeof(line), "cat>%s\r", argv[1]);
547 snprintf(line, sizeof(line), "stty -echo;cat>%s;stty echo\r", argv[1]);
548 transmit(fd, "\04", line);
555 if (usleep(msec*1000) != 0) {
556 fprintf ( stderr, "warning: ldelay or cdelay interrupted, "
557 "delay time cut short: %s\n",
566 * FTP - send single character
567 * wait for echo & handle timeout
577 if (number(value(CDELAY)) > 0 && c != '\r')
578 nap(number(value(CDELAY)));
579 if (!boolean(value(ECHOCHECK))) {
580 if (number(value(LDELAY)) > 0 && c == '\r')
581 nap(number(value(LDELAY)));
586 alarm(number(value(ETIMEOUT)));
590 printf("\r\ntimeout error (%s)\r\n", ctrl(c));
593 xpwrite(FD, &null, 1); /* poke it */
601 signal(SIGALRM, timeout);
606 * Stolen from consh() -- puts a remote file on the output of a local command.
607 * Identical to consh() except for where stdout goes.
617 if (prompt("Local command? ", buf, sizeof(buf)))
619 kill(pid, SIGIOT); /* put TIPOUT into a wait state */
620 signal(SIGINT, SIG_IGN);
621 signal(SIGQUIT, SIG_IGN);
623 read(repdes[0], (char *)&ccc, 1);
625 * Set up file descriptors in the child and
628 if ((cpid = fork()) < 0)
629 printf("can't fork!\r\n");
632 while ((p = wait(&status)) > 0 && p != cpid)
638 for (i = 3; i < 20; i++)
640 signal(SIGINT, SIG_DFL);
641 signal(SIGQUIT, SIG_DFL);
643 printf("can't find `%s'\r\n", buf);
646 if (boolean(value(VERBOSE)))
647 prtime("away for ", time(0)-start);
648 write(fildes[1], (char *)&ccc, 1);
650 signal(SIGINT, SIG_DFL);
651 signal(SIGQUIT, SIG_DFL);
657 tiplink (char *cmd, unsigned int flags)
662 if (flags & TL_SIGNAL_TIPOUT) {
663 kill(pid, SIGIOT); /* put TIPOUT into a wait state */
664 signal(SIGINT, SIG_IGN);
665 signal(SIGQUIT, SIG_IGN);
667 read(repdes[0], (char *)&ccc, 1);
671 * Set up file descriptors in the child and
674 if ((cpid = fork()) < 0)
675 printf("can't fork!\r\n");
678 while ((p = wait(&status)) > 0 && p != cpid)
685 for (fd = 3; fd < 20; fd++)
687 signal(SIGINT, SIG_DFL);
688 signal(SIGQUIT, SIG_DFL);
690 printf("can't find `%s'\r\n", cmd);
694 if (flags & TL_VERBOSE && boolean(value(VERBOSE)))
695 prtime("away for ", time(0)-start);
697 if (flags & TL_SIGNAL_TIPOUT) {
698 write(fildes[1], (char *)&ccc, 1);
700 signal(SIGINT, SIG_DFL);
701 signal(SIGQUIT, SIG_DFL);
708 * Fork a program with:
709 * 0 <-> remote tty in
710 * 1 <-> remote tty out
711 * 2 <-> local tty out
718 if (prompt("Local command? ", buf, sizeof(buf)))
720 tiplink (buf, TL_SIGNAL_TIPOUT | TL_VERBOSE);
726 * Escape to local shell
735 signal(SIGINT, SIG_IGN);
736 signal(SIGQUIT, SIG_IGN);
738 if ((shpid = fork())) {
739 while (shpid != wait(&status));
742 signal(SIGINT, SIG_DFL);
743 signal(SIGQUIT, SIG_DFL);
746 signal(SIGQUIT, SIG_DFL);
747 signal(SIGINT, SIG_DFL);
748 if ((cp = rindex(value(SHELL), '/')) == NULL)
753 execl(value(SHELL), cp, NULL);
754 printf("\r\ncan't execl!\r\n");
760 * TIPIN portion of scripting
761 * initiate the conversation with TIPOUT
768 * enable TIPOUT side for dialogue
771 if (boolean(value(SCRIPT)))
772 write(fildes[1], value(RECORD), size(value(RECORD)));
773 write(fildes[1], "\n", 1);
775 * wait for TIPOUT to finish
777 read(repdes[0], &c, 1);
779 printf("can't create %s\r\n", value(RECORD));
783 * Change current working directory of
784 * local portion of tip
789 char dirname[PATH_MAX];
792 if (prompt("[cd] ", dirname, sizeof(dirname))) {
798 printf("%s: bad directory\r\n", cp);
809 printf("\r\n%s", msg);
810 printf("\r\n[EOT]\r\n");
812 (void)uu_unlock(uucplock);
820 char *abortmsg = NULL, *dismsg;
822 if (LO != NULL && tiplink (LO, TL_SIGNAL_TIPOUT) != 0) {
823 abortmsg = "logout failed";
826 if ((dismsg = value(DISCONNECT)) != NULL) {
827 write(FD, dismsg, strlen(dismsg));
846 if ((cp = rindex(value(SHELL), '/')) == NULL)
851 execl(value(SHELL), cp, "-c", s, NULL);
855 args(char *buf, char **a, int num)
857 char *p = buf, *start;
861 while (*p && n < num) {
862 while (*p && (*p == ' ' || *p == '\t'))
867 while (*p && (*p != ' ' && *p != '\t'))
878 prtime(char *s, time_t a)
883 for (i = 0; i < 3; i++) {
884 nums[i] = (int)(a % quant[i]);
889 if (nums[i] || (i == 0 && nums[1] == 0 && nums[2] == 0))
890 printf("%d %s%c ", nums[i], sep[i],
891 nums[i] == 1 ? '\0' : 's');
900 if (prompt("[set] ", buf, sizeof(buf)))
903 if (vtable[BEAUTIFY].v_access&CHANGED) {
904 vtable[BEAUTIFY].v_access &= ~CHANGED;
907 if (vtable[SCRIPT].v_access&CHANGED) {
908 vtable[SCRIPT].v_access &= ~CHANGED;
911 * So that "set record=blah script" doesn't
912 * cause two transactions to occur.
914 if (vtable[RECORD].v_access&CHANGED)
915 vtable[RECORD].v_access &= ~CHANGED;
917 if (vtable[RECORD].v_access&CHANGED) {
918 vtable[RECORD].v_access &= ~CHANGED;
919 if (boolean(value(SCRIPT)))
922 if (vtable[TAND].v_access&CHANGED) {
923 vtable[TAND].v_access &= ~CHANGED;
924 if (boolean(value(TAND)))
929 if (vtable[LECHO].v_access&CHANGED) {
930 vtable[LECHO].v_access &= ~CHANGED;
931 HD = boolean(value(LECHO));
933 if (vtable[PARITY].v_access&CHANGED) {
934 vtable[PARITY].v_access &= ~CHANGED;
935 setparity(value(PARITY));
940 * Turn tandem mode on or off for remote tty.
946 struct termios ttermios;
947 tcgetattr (FD, &ttermios);
948 if (strcmp(option,"on") == 0) {
949 ttermios.c_iflag |= IXOFF;
950 ctermios.c_iflag |= IXOFF;
953 ttermios.c_iflag &= ~IXOFF;
954 ctermios.c_iflag &= ~IXOFF;
956 tcsetattr (FD, TCSANOW, &ttermios);
957 tcsetattr (0, TCSANOW, &ctermios);
958 #else /* HAVE_TERMIOS */
961 ioctl(FD, TIOCGETP, &rmtty);
962 if (strcmp(option,"on") == 0) {
963 rmtty.sg_flags |= TANDEM;
964 arg.sg_flags |= TANDEM;
966 rmtty.sg_flags &= ~TANDEM;
967 arg.sg_flags &= ~TANDEM;
969 ioctl(FD, TIOCSETP, &rmtty);
970 ioctl(0, TIOCSETP, &arg);
971 #endif /* HAVE_TERMIOS */
981 ioctl(FD, TIOCSBRK, NULL);
983 ioctl(FD, TIOCCBRK, NULL);
994 kill(c == CTRL('y') ? getpid() : 0, SIGTSTP);
999 * expand a file name if it includes shell meta characters
1005 static char xname[BUFSIZ];
1006 char cmdbuf[BUFSIZ];
1009 int s, pivec[2] /*, (*sigint)()*/;
1011 if (!anyof(name, "~{[*?$`'\"\\"))
1013 /* sigint = signal(SIGINT, SIG_IGN); */
1014 if (pipe(pivec) < 0) {
1016 /* signal(SIGINT, sigint) */
1019 snprintf(cmdbuf, sizeof(cmdbuf), "echo %s", name);
1020 if ((pid = vfork()) == 0) {
1021 Shell = value(SHELL);
1023 Shell = _PATH_BSHELL;
1030 execl(Shell, Shell, "-c", cmdbuf, NULL);
1040 l = read(pivec[0], xname, BUFSIZ);
1042 while (wait(&s) != pid);
1045 if (s != 0 && s != SIGPIPE) {
1046 fprintf(stderr, "\"Echo\" failed\n");
1054 fprintf(stderr, "\"%s\": No match\n", name);
1058 fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
1062 for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
1069 * Are any of the characters in the two strings the same?
1073 anyof(char *s1, char *s2)