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 $
35 * $DragonFly: src/usr.bin/tip/tip/cmds.c,v 1.2 2003/06/17 04:29:32 dillon Exp $
40 #include "pathnames.h"
42 #include <sys/types.h>
52 * miscellaneous commands
55 int quant[] = { 60, 60, 24 };
58 char *sep[] = { "second", "minute", "hour" };
59 static char *argv[10]; /* argument vector for take and put */
61 void timeout(); /* timeout function called on alarm */
62 static void stopsnd(); /* SIGINT handler during file transfers */
63 static void intcopy(); /* interrupt routine for file transfers */
65 void suspend __P((char));
66 void genbrk __P((void));
67 void variable __P((void));
68 void finish __P((void));
69 void tipabort __P((char *));
70 void chdirectory __P((void));
71 void shell __P((void));
72 void cu_put __P((char));
73 void sendfile __P((char));
74 void pipefile __P((void));
75 void cu_take __P((char));
76 void getfl __P((char));
78 static int anyof __P((char *, char *));
79 static void tandem __P((char *));
80 static void prtime __P((char *, time_t));
81 static int args __P((char *, char **, int));
82 static void execute __P((char *));
83 static void send __P((char));
84 static void transmit __P((FILE *, char *, char *));
85 static void transfer __P((char *, int, char *));
86 static void xfer __P((char *, int, char *));
93 struct termios ttermios;
95 for (cnt = 0; cnt < NCCS; cnt++)
96 ttermios.c_cc [cnt] = otermios.c_cc [cnt];
97 tcsetattr (0, TCSANOW, &ttermios);
99 ioctl(0, TIOCSETC, &defchars);
107 tcsetattr (0, TCSANOW, &ctermios);
109 ioctl(0, TIOCSETC, &tchars);
118 ioctl (FD, TIOCFLUSH, &cmd);
121 ioctl (FD, TIOCGETP, &buf); /* this does a */
122 ioctl (FD, TIOCSETP, &buf); /* wflushtty */
127 * FTP - remote ==> local
128 * get a file from the remote host
134 char buf[256], *cp, *expand();
138 * get the UNIX receiving file's name
140 if (prompt("Local file name? ", copyname, sizeof(copyname)))
142 cp = expand(copyname);
143 if ((sfd = creat(cp, 0666)) < 0) {
144 printf("\r\n%s: cannot creat\r\n", copyname);
151 if (prompt("List command for remote system? ", buf, sizeof(buf))) {
155 transfer(buf, sfd, value(EOFREAD));
159 * Cu-like take command
166 char line[BUFSIZ], *expand(), *cp;
168 if (prompt("[take] ", copyname, sizeof(copyname)))
170 if ((argc = args(copyname, argv, sizeof(argv)/sizeof(argv[0]))) < 1 || argc > 2) {
171 printf("usage: <take> from [to]\r\n");
176 cp = expand(argv[1]);
177 if ((fd = creat(cp, 0666)) < 0) {
178 printf("\r\n%s: cannot create\r\n", argv[1]);
181 (void)snprintf(line, sizeof(line), "cat %s ; echo \"\" ; echo ___tip_end_of_file_marker___", argv[0]);
182 xfer(line, fd, "\n___tip_end_of_file_marker___\n");
185 static jmp_buf intbuf;
188 xfer(buf, fd, eofchars)
189 char *buf, *eofchars;
199 v = boolean(value(VERBOSE));
201 if ((ff = fdopen (fd, "w")) == NULL) {
205 if ((cnt = number(value(FRAMESIZE))) != BUFSIZ)
206 if (setvbuf(ff, NULL, _IOFBF, cnt) != 0) {
207 warn("file allocation");
212 xpwrite(FD, buf, size(buf));
215 read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */
224 while ((c&0177) != '\n');
228 (void) setjmp(intbuf);
229 f = signal(SIGINT, intcopy);
232 for (ct = 0; !quit;) {
233 eof = read(FD, &c, 1) <= 0;
240 continue; /* ignore nulls */
243 if (c != *match && match > eofchars) {
244 register char *p = eofchars;
247 (void)printf("\r%d", ++ct);
253 if (*++match == '\0')
257 (void)printf("\r%d", ++ct);
262 prtime(" lines transferred in ", time(0)-start);
264 write(fildes[1], (char *)&ccc, 1);
270 * Bulk transfer routine --
271 * used by getfl(), cu_take(), and pipefile()
274 transfer(buf, fd, eofchars)
275 char *buf, *eofchars;
279 register int cnt, eof, v;
285 v = boolean(value(VERBOSE));
287 if ((ff = fdopen (fd, "w")) == NULL) {
291 if ((cnt = number(value(FRAMESIZE))) != BUFSIZ)
292 if (setvbuf(ff, NULL, _IOFBF, cnt) != 0) {
293 warn("file allocation");
298 xpwrite(FD, buf, size(buf));
301 read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */
310 while ((c&0177) != '\n');
312 (void) setjmp(intbuf);
313 f = signal(SIGINT, intcopy);
315 for (ct = 0; !quit;) {
316 eof = read(FD, &c, 1) <= 0;
320 if (eof || any(c, eofchars))
323 continue; /* ignore nulls */
327 printf("\r%d", ++ct);
331 prtime(" lines transferred in ", time(0)-start);
333 write(fildes[1], (char *)&ccc, 1);
339 * FTP - remote ==> local process
340 * send remote input to local process via pipe
349 if (prompt("Local command? ", buf, sizeof(buf)))
353 printf("can't establish pipe\r\n");
357 if ((cpid = fork()) < 0) {
358 printf("can't fork!\r\n");
361 if (prompt("List command for remote system? ", buf, sizeof(buf))) {
362 close(pdes[0]), close(pdes[1]);
363 kill (cpid, SIGKILL);
366 signal(SIGPIPE, intcopy);
367 transfer(buf, pdes[1], value(EOFREAD));
368 signal(SIGPIPE, SIG_DFL);
369 while ((p = wait(&status)) > 0 && p != cpid)
377 for (f = 3; f < 20; f++)
380 printf("can't execl!\r\n");
386 * Interrupt service routine for FTP
393 signal(SIGINT, SIG_IGN);
397 * FTP - local ==> remote
398 * send local file to remote host
399 * terminate transmission with pseudo EOF sequence
413 if (prompt("Local file name? ", fname, sizeof(fname)))
419 fnamex = expand(fname);
420 if ((fd = fopen(fnamex, "r")) == NULL) {
421 printf("%s: cannot open\r\n", fname);
424 transmit(fd, value(EOFWRITE), NULL);
425 if (!boolean(value(ECHOCHECK))) {
431 * Bulk transfer routine to remote host --
432 * used by sendfile() and cu_put()
435 transmit(fd, eofchars, command)
437 char *eofchars, *command;
440 int c, ccount, lcount;
441 time_t start_t, stop_t;
444 kill(pid, SIGIOT); /* put TIPOUT into a wait state */
446 f = signal(SIGINT, stopsnd);
448 read(repdes[0], (char *)&ccc, 1);
449 if (command != NULL) {
450 for (pc = command; *pc; pc++)
452 if (boolean(value(ECHOCHECK)))
453 read(FD, (char *)&c, 1); /* trailing \n */
456 sleep(5); /* wait for remote stty to take effect */
470 if (c == 0177 && !boolean(value(RAWFTP)))
475 if (!boolean(value(RAWFTP)))
478 else if (c == '\t') {
479 if (!boolean(value(RAWFTP))) {
480 if (boolean(value(TABEXPAND))) {
482 while ((++ccount % 8) != 0)
488 if (!boolean(value(RAWFTP)))
492 } while (c != '\r' && !boolean(value(RAWFTP)));
493 if (boolean(value(VERBOSE)))
494 printf("\r%d", ++lcount);
495 if (boolean(value(ECHOCHECK))) {
497 alarm(number(value(ETIMEOUT)));
498 do { /* wait for prompt */
499 read(FD, (char *)&c, 1);
500 if (timedout || stop) {
502 printf("\r\ntimed out at eol\r\n");
506 } while ((c&0177) != character(value(PROMPT)));
511 if (lastc != '\n' && !boolean(value(RAWFTP)))
513 for (pc = eofchars; pc && *pc; pc++)
518 if (boolean(value(VERBOSE)))
519 if (boolean(value(RAWFTP)))
520 prtime(" chars transferred in ", stop_t-start_t);
522 prtime(" lines transferred in ", stop_t-start_t);
523 write(fildes[1], (char *)&ccc, 1);
528 * Cu-like put command
540 if (prompt("[put] ", copyname, sizeof(copyname)))
542 if ((argc = args(copyname, argv, sizeof(argv)/sizeof(argv[0]))) < 1 || argc > 2) {
543 printf("usage: <put> from [to]\r\n");
548 copynamex = expand(argv[0]);
549 if ((fd = fopen(copynamex, "r")) == NULL) {
550 printf("%s: cannot open\r\n", copynamex);
553 if (boolean(value(ECHOCHECK)))
554 snprintf(line, sizeof(line), "cat>%s\r", argv[1]);
556 snprintf(line, sizeof(line), "stty -echo;cat>%s;stty echo\r", argv[1]);
557 transmit(fd, "\04", line);
563 int msec; /* milliseconds */
565 if (usleep(msec*1000) != 0) {
566 fprintf ( stderr, "warning: ldelay or cdelay interrupted, "
567 "delay time cut short: %s\n",
576 * FTP - send single character
577 * wait for echo & handle timeout
588 if (number(value(CDELAY)) > 0 && c != '\r')
589 nap(number(value(CDELAY)));
590 if (!boolean(value(ECHOCHECK))) {
591 if (number(value(LDELAY)) > 0 && c == '\r')
592 nap(number(value(LDELAY)));
597 alarm(number(value(ETIMEOUT)));
601 printf("\r\ntimeout error (%s)\r\n", ctrl(c));
604 xpwrite(FD, &null, 1); /* poke it */
612 signal(SIGALRM, timeout);
617 * Stolen from consh() -- puts a remote file on the output of a local command.
618 * Identical to consh() except for where stdout goes.
628 if (prompt("Local command? ", buf, sizeof(buf)))
630 kill(pid, SIGIOT); /* put TIPOUT into a wait state */
631 signal(SIGINT, SIG_IGN);
632 signal(SIGQUIT, SIG_IGN);
634 read(repdes[0], (char *)&ccc, 1);
636 * Set up file descriptors in the child and
639 if ((cpid = fork()) < 0)
640 printf("can't fork!\r\n");
643 while ((p = wait(&status)) > 0 && p != cpid)
649 for (i = 3; i < 20; i++)
651 signal(SIGINT, SIG_DFL);
652 signal(SIGQUIT, SIG_DFL);
654 printf("can't find `%s'\r\n", buf);
657 if (boolean(value(VERBOSE)))
658 prtime("away for ", time(0)-start);
659 write(fildes[1], (char *)&ccc, 1);
661 signal(SIGINT, SIG_DFL);
662 signal(SIGQUIT, SIG_DFL);
668 tiplink (char *cmd, unsigned int flags)
673 if (flags & TL_SIGNAL_TIPOUT) {
674 kill(pid, SIGIOT); /* put TIPOUT into a wait state */
675 signal(SIGINT, SIG_IGN);
676 signal(SIGQUIT, SIG_IGN);
678 read(repdes[0], (char *)&ccc, 1);
682 * Set up file descriptors in the child and
685 if ((cpid = fork()) < 0)
686 printf("can't fork!\r\n");
689 while ((p = wait(&status)) > 0 && p != cpid)
696 for (fd = 3; fd < 20; fd++)
698 signal(SIGINT, SIG_DFL);
699 signal(SIGQUIT, SIG_DFL);
701 printf("can't find `%s'\r\n", cmd);
705 if (flags & TL_VERBOSE && boolean(value(VERBOSE)))
706 prtime("away for ", time(0)-start);
708 if (flags & TL_SIGNAL_TIPOUT) {
709 write(fildes[1], (char *)&ccc, 1);
711 signal(SIGINT, SIG_DFL);
712 signal(SIGQUIT, SIG_DFL);
719 * Fork a program with:
720 * 0 <-> remote tty in
721 * 1 <-> remote tty out
722 * 2 <-> local tty out
729 if (prompt("Local command? ", buf, sizeof(buf)))
731 tiplink (buf, TL_SIGNAL_TIPOUT | TL_VERBOSE);
737 * Escape to local shell
746 signal(SIGINT, SIG_IGN);
747 signal(SIGQUIT, SIG_IGN);
749 if ((shpid = fork())) {
750 while (shpid != wait(&status));
753 signal(SIGINT, SIG_DFL);
754 signal(SIGQUIT, SIG_DFL);
757 signal(SIGQUIT, SIG_DFL);
758 signal(SIGINT, SIG_DFL);
759 if ((cp = rindex(value(SHELL), '/')) == NULL)
764 execl(value(SHELL), cp, 0);
765 printf("\r\ncan't execl!\r\n");
771 * TIPIN portion of scripting
772 * initiate the conversation with TIPOUT
779 * enable TIPOUT side for dialogue
782 if (boolean(value(SCRIPT)))
783 write(fildes[1], value(RECORD), size(value(RECORD)));
784 write(fildes[1], "\n", 1);
786 * wait for TIPOUT to finish
788 read(repdes[0], &c, 1);
790 printf("can't create %s\r\n", value(RECORD));
794 * Change current working directory of
795 * local portion of tip
800 char dirname[PATH_MAX];
801 register char *cp = dirname;
803 if (prompt("[cd] ", dirname, sizeof(dirname))) {
809 printf("%s: bad directory\r\n", cp);
821 printf("\r\n%s", msg);
822 printf("\r\n[EOT]\r\n");
824 (void)uu_unlock(uucplock);
832 char *abortmsg = NOSTR, *dismsg;
834 if (LO != NOSTR && tiplink (LO, TL_SIGNAL_TIPOUT) != 0) {
835 abortmsg = "logout failed";
838 if ((dismsg = value(DISCONNECT)) != NOSTR) {
839 write(FD, dismsg, strlen(dismsg));
859 if ((cp = rindex(value(SHELL), '/')) == NULL)
864 execl(value(SHELL), cp, "-c", s, 0);
872 register char *p = buf, *start;
873 register char **parg = a;
876 while (*p && n < num) {
877 while (*p && (*p == ' ' || *p == '\t'))
882 while (*p && (*p != ' ' && *p != '\t'))
900 for (i = 0; i < 3; i++) {
901 nums[i] = (int)(a % quant[i]);
906 if (nums[i] || (i == 0 && nums[1] == 0 && nums[2] == 0))
907 printf("%d %s%c ", nums[i], sep[i],
908 nums[i] == 1 ? '\0' : 's');
917 if (prompt("[set] ", buf, sizeof(buf)))
920 if (vtable[BEAUTIFY].v_access&CHANGED) {
921 vtable[BEAUTIFY].v_access &= ~CHANGED;
924 if (vtable[SCRIPT].v_access&CHANGED) {
925 vtable[SCRIPT].v_access &= ~CHANGED;
928 * So that "set record=blah script" doesn't
929 * cause two transactions to occur.
931 if (vtable[RECORD].v_access&CHANGED)
932 vtable[RECORD].v_access &= ~CHANGED;
934 if (vtable[RECORD].v_access&CHANGED) {
935 vtable[RECORD].v_access &= ~CHANGED;
936 if (boolean(value(SCRIPT)))
939 if (vtable[TAND].v_access&CHANGED) {
940 vtable[TAND].v_access &= ~CHANGED;
941 if (boolean(value(TAND)))
946 if (vtable[LECHO].v_access&CHANGED) {
947 vtable[LECHO].v_access &= ~CHANGED;
948 HD = boolean(value(LECHO));
950 if (vtable[PARITY].v_access&CHANGED) {
951 vtable[PARITY].v_access &= ~CHANGED;
952 setparity(value(PARITY));
957 * Turn tandem mode on or off for remote tty.
964 struct termios ttermios;
965 tcgetattr (FD, &ttermios);
966 if (strcmp(option,"on") == 0) {
967 ttermios.c_iflag |= IXOFF;
968 ctermios.c_iflag |= IXOFF;
971 ttermios.c_iflag &= ~IXOFF;
972 ctermios.c_iflag &= ~IXOFF;
974 tcsetattr (FD, TCSANOW, &ttermios);
975 tcsetattr (0, TCSANOW, &ctermios);
976 #else /* HAVE_TERMIOS */
979 ioctl(FD, TIOCGETP, &rmtty);
980 if (strcmp(option,"on") == 0) {
981 rmtty.sg_flags |= TANDEM;
982 arg.sg_flags |= TANDEM;
984 rmtty.sg_flags &= ~TANDEM;
985 arg.sg_flags &= ~TANDEM;
987 ioctl(FD, TIOCSETP, &rmtty);
988 ioctl(0, TIOCSETP, &arg);
989 #endif /* HAVE_TERMIOS */
999 ioctl(FD, TIOCSBRK, NULL);
1001 ioctl(FD, TIOCCBRK, NULL);
1013 kill(c == CTRL('y') ? getpid() : 0, SIGTSTP);
1018 * expand a file name if it includes shell meta characters
1025 static char xname[BUFSIZ];
1026 char cmdbuf[BUFSIZ];
1027 register int pid, l;
1028 register char *cp, *Shell;
1029 int s, pivec[2] /*, (*sigint)()*/;
1031 if (!anyof(name, "~{[*?$`'\"\\"))
1033 /* sigint = signal(SIGINT, SIG_IGN); */
1034 if (pipe(pivec) < 0) {
1036 /* signal(SIGINT, sigint) */
1039 snprintf(cmdbuf, sizeof(cmdbuf), "echo %s", name);
1040 if ((pid = vfork()) == 0) {
1041 Shell = value(SHELL);
1043 Shell = _PATH_BSHELL;
1050 execl(Shell, Shell, "-c", cmdbuf, 0);
1060 l = read(pivec[0], xname, BUFSIZ);
1062 while (wait(&s) != pid);
1065 if (s != 0 && s != SIGPIPE) {
1066 fprintf(stderr, "\"Echo\" failed\n");
1074 fprintf(stderr, "\"%s\": No match\n", name);
1078 fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
1082 for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
1089 * Are any of the characters in the two strings the same?
1094 register char *s1, *s2;