1 /* $OpenBSD: cmds.c,v 1.26 2006/06/06 23:24:52 deraadt Exp $ */
2 /* $NetBSD: cmds.c,v 1.7 1997/02/11 09:24:03 mrg Exp $ */
5 * Copyright (c) 1983, 1993
6 * The Regents of the University of California. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
38 static char sccsid[] = "@(#)cmds.c 8.1 (Berkeley) 6/6/93";
39 static const char rcsid[] = "$OpenBSD: cmds.c,v 1.26 2006/06/06 23:24:52 deraadt Exp $";
44 #include "pathnames.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 static void transfer(char *, int, char *);
61 static void stopsnd(int); /* SIGINT handler during file transfers */
62 static void intcopy(int); /* interrupt routine for file transfers */
63 static void transmit(FILE *, char *, char *);
64 static void send(int);
65 static void execute(char *);
66 static int args(char *, char **, int);
67 static void prtime(char *, time_t);
68 static void tandem(char *);
69 static void hardwareflow(char *);
70 void linedisc(char *);
71 static int anyof(char *, char *);
74 * FTP - remote ==> local
75 * get a file from the remote host
84 * get the UNIX receiving file's name
86 if (prompt("Local file name? ", copyname, sizeof(copyname)))
88 cp = expand(copyname);
89 if ((sfd = creat(cp, 0666)) < 0) {
90 printf("\r\n%s: cannot creat\r\n", copyname);
97 if (prompt("List command for remote system? ", buf, sizeof(buf))) {
101 transfer(buf, sfd, value(EOFREAD));
105 * Cu-like take command
111 char line[BUFSIZ], *cp;
113 if (prompt("[take] ", copyname, sizeof(copyname)))
115 if ((argc = args(copyname, argv, sizeof(argv)/sizeof(argv[0]))) < 1 ||
117 printf("usage: <take> from [to]\r\n");
122 cp = expand(argv[1]);
123 if ((fd = creat(cp, 0666)) < 0) {
124 printf("\r\n%s: cannot create\r\n", argv[1]);
127 (void)snprintf(line, sizeof(line), "cat %s;echo ''|tr '\\012' '\\01'", argv[0]);
128 transfer(line, fd, "\01");
131 static jmp_buf intbuf;
134 * Bulk transfer routine --
135 * used by getfl(), cu_take(), and pipefile()
138 transfer(char *buf, int fd, char *eofchars)
141 char c, buffer[BUFSIZ];
148 if (number(value(FRAMESIZE)) > BUFSIZ || number(value(FRAMESIZE)) < 1) {
149 printf("framesize must be >= 1 and <= %d\r\n", BUFSIZ);
154 parwrite(FD, buf, size(buf));
156 kill(tipout_pid, SIGIOT);
157 read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */
166 while ((c&STRIP_PAR) != '\n');
167 tcsetattr(0, TCSAFLUSH, &defchars);
169 (void) setjmp(intbuf);
170 f = signal(SIGINT, intcopy);
172 for (ct = 0; !quit;) {
173 eof = read(FD, &c, 1) <= 0;
177 if (eof || any(c, eofchars))
180 continue; /* ignore nulls */
185 if (c == '\n' && boolean(value(VERBOSE)))
186 printf("\r%d", ++ct);
187 if ((cnt = (p-buffer)) == (size_t)number(value(FRAMESIZE))) {
188 if ((size_t)write(fd, buffer, cnt) != cnt) {
189 printf("\r\nwrite error\r\n");
195 if ((cnt = (p-buffer)))
196 if ((size_t)write(fd, buffer, cnt) != cnt)
197 printf("\r\nwrite error\r\n");
199 if (boolean(value(VERBOSE)))
200 prtime(" lines transferred in ", time(0)-start);
201 tcsetattr(0, TCSAFLUSH, &term);
202 write(fildes[1], (char *)&ccc, 1);
208 * FTP - remote ==> local process
209 * send remote input to local process via pipe
220 if (prompt("Local command? ", buf, sizeof(buf)))
224 printf("can't establish pipe\r\n");
228 if ((cpid = fork()) < 0) {
229 printf("can't fork!\r\n");
232 if (prompt("List command for remote system? ", buf, sizeof(buf))) {
233 close(pdes[0]), close(pdes[1]);
234 kill (cpid, SIGKILL);
237 signal(SIGPIPE, intcopy);
238 transfer(buf, pdes[1], value(EOFREAD));
239 signal(SIGPIPE, SIG_DFL);
240 while ((p = wait(&status)) > 0 && p != cpid)
248 for (f = 3; f < 20; f++)
251 printf("can't execl!\r\n");
257 * Interrupt service routine for FTP
264 signal(SIGINT, SIG_IGN);
268 * FTP - local ==> remote
269 * send local file to remote host
270 * terminate transmission with pseudo EOF sequence
282 if (prompt("Local file name? ", fname, sizeof(fname)))
288 fnamex = expand(fname);
289 if ((fp = fopen(fnamex, "r")) == NULL) {
290 printf("%s: cannot open\r\n", fname);
293 transmit(fp, value(EOFWRITE), NULL);
294 if (!boolean(value(ECHOCHECK)))
299 * Bulk transfer routine to remote host --
300 * used by sendfile() and cu_put()
303 transmit(FILE *fp, char *eofchars, char *command)
306 int c, ccount, lcount;
307 time_t start_t, stop_t;
310 kill(tipout_pid, SIGIOT); /* put TIPOUT into a wait state */
312 f = signal(SIGINT, stopsnd);
313 tcsetattr(0, TCSAFLUSH, &defchars);
314 read(repdes[0], (char *)&ccc, 1);
315 if (command != NULL) {
316 for (pc = command; *pc; pc++)
318 if (boolean(value(ECHOCHECK)))
319 read(FD, (char *)&c, 1); /* trailing \n */
322 sleep(5); /* wait for remote stty to take effect */
336 if (c == 0177 && !boolean(value(RAWFTP)))
341 if (!boolean(value(RAWFTP)))
343 } else if (c == '\t') {
344 if (!boolean(value(RAWFTP))) {
345 if (boolean(value(TABEXPAND))) {
347 while ((++ccount % 8) != 0)
353 if (!boolean(value(RAWFTP)))
357 } while (c != '\r' && !boolean(value(RAWFTP)));
358 if (boolean(value(VERBOSE)))
359 printf("\r%d", ++lcount);
360 if (boolean(value(ECHOCHECK))) {
362 alarm((unsigned int)lvalue(ETIMEOUT));
363 do { /* wait for prompt */
364 read(FD, (char *)&c, 1);
365 if (timedout || stop) {
367 printf("\r\ntimed out at eol\r\n");
371 } while ((c&STRIP_PAR) != character(value(PROMPT)));
376 if (lastc != '\n' && !boolean(value(RAWFTP)))
379 for (pc = eofchars; *pc; pc++)
385 if (boolean(value(VERBOSE))) {
386 if (boolean(value(RAWFTP)))
387 prtime(" chars transferred in ", stop_t-start_t);
389 prtime(" lines transferred in ", stop_t-start_t);
391 write(fildes[1], (char *)&ccc, 1);
392 tcsetattr(0, TCSAFLUSH, &term);
396 * Cu-like put command
407 if (prompt("[put] ", copyname, sizeof(copyname)))
409 if ((argc = args(copyname, argv, sizeof(argv)/sizeof(argv[0]))) < 1 ||
411 printf("usage: <put> from [to]\r\n");
416 copynamex = expand(argv[0]);
417 if ((fp = fopen(copynamex, "r")) == NULL) {
418 printf("%s: cannot open\r\n", copynamex);
421 if (boolean(value(ECHOCHECK)))
422 (void)snprintf(line, sizeof(line), "cat>%s\r", argv[1]);
424 (void)snprintf(line, sizeof(line),
425 "stty -echo;cat>%s;stty echo\r", argv[1]);
426 transmit(fp, "\04", line);
430 * FTP - send single character
431 * wait for echo & handle timeout
440 parwrite(FD, &cc, 1);
441 if (number(value(CDELAY)) > 0 && c != '\r')
442 usleep(number(value(CDELAY)));
443 if (!boolean(value(ECHOCHECK))) {
444 if (number(value(LDELAY)) > 0 && c == '\r')
445 usleep(number(value(LDELAY)));
450 alarm((unsigned int)lvalue(ETIMEOUT));
454 printf("\r\ntimeout error (%s)\r\n", ctrl(c));
457 parwrite(FD, &null, 1); /* poke it */
466 signal(SIGALRM, timeout);
471 * Stolen from consh() -- puts a remote file on the output of a local command.
472 * Identical to consh() except for where stdout goes.
480 time_t start = time(NULL);
483 if (prompt("Local command? ", buf, sizeof(buf)))
485 kill(tipout_pid, SIGIOT); /* put TIPOUT into a wait state */
486 signal(SIGINT, SIG_IGN);
487 signal(SIGQUIT, SIG_IGN);
488 tcsetattr(0, TCSAFLUSH, &defchars);
489 read(repdes[0], (char *)&ccc, 1);
491 * Set up file descriptors in the child and
494 if ((cpid = fork()) < 0)
495 printf("can't fork!\r\n");
498 while ((p = wait(&status)) > 0 && p != cpid)
504 for (i = 3; i < 20; i++)
506 signal(SIGINT, SIG_DFL);
507 signal(SIGQUIT, SIG_DFL);
509 printf("can't find `%s'\r\n", buf);
512 if (boolean(value(VERBOSE)))
513 prtime("away for ", time(0)-start);
514 write(fildes[1], (char *)&ccc, 1);
515 tcsetattr(0, TCSAFLUSH, &term);
516 signal(SIGINT, SIG_DFL);
517 signal(SIGQUIT, SIG_DFL);
522 * Fork a program with:
523 * 0 <-> remote tty in
524 * 1 <-> remote tty out
525 * 2 <-> local tty stderr
533 time_t start = time(NULL);
536 if (prompt("Local command? ", buf, sizeof(buf)))
538 kill(tipout_pid, SIGIOT); /* put TIPOUT into a wait state */
539 signal(SIGINT, SIG_IGN);
540 signal(SIGQUIT, SIG_IGN);
541 tcsetattr(0, TCSAFLUSH, &defchars);
542 read(repdes[0], (char *)&ccc, 1);
544 * Set up file descriptors in the child and
547 if ((cpid = fork()) < 0)
548 printf("can't fork!\r\n");
551 while ((p = wait(&status)) > 0 && p != cpid)
558 for (i = 3; i < 20; i++)
560 signal(SIGINT, SIG_DFL);
561 signal(SIGQUIT, SIG_DFL);
563 printf("can't find `%s'\r\n", buf);
566 if (boolean(value(VERBOSE)))
567 prtime("away for ", time(0)-start);
568 write(fildes[1], (char *)&ccc, 1);
569 tcsetattr(0, TCSAFLUSH, &term);
570 signal(SIGINT, SIG_DFL);
571 signal(SIGQUIT, SIG_DFL);
576 * Escape to local shell
587 signal(SIGINT, SIG_IGN);
588 signal(SIGQUIT, SIG_IGN);
590 if ((shpid = fork())) {
591 while (shpid != wait(&status));
594 signal(SIGINT, SIG_DFL);
595 signal(SIGQUIT, SIG_DFL);
598 signal(SIGQUIT, SIG_DFL);
599 signal(SIGINT, SIG_DFL);
600 if ((cp = strrchr(value(SHELL), '/')) == NULL)
605 execl(value(SHELL), cp, (char *)NULL);
606 printf("\r\ncan't execl!\r\n");
612 * TIPIN portion of scripting
613 * initiate the conversation with TIPOUT
621 * enable TIPOUT side for dialogue
623 kill(tipout_pid, SIGEMT);
624 if (boolean(value(SCRIPT)))
625 write(fildes[1], value(RECORD), size(value(RECORD)));
626 write(fildes[1], "\n", 1);
628 * wait for TIPOUT to finish
630 read(repdes[0], &c, 1);
632 printf("can't create %s\r\n", value(RECORD));
636 * Change current working directory of
637 * local portion of tip
643 char dirname[PATH_MAX];
646 if (prompt("[cd] ", dirname, sizeof(dirname))) {
652 printf("%s: bad directory\r\n", cp);
660 signal(SIGTERM, SIG_IGN);
661 kill(tipout_pid, SIGTERM);
664 printf("\r\n%s", msg);
665 printf("\r\n[EOT]\r\n");
667 (void)uu_unlock(uucplock);
679 if ((dismsg = value(DISCONNECT)) != NOSTR) {
680 write(FD, dismsg, strlen(dismsg));
700 if ((cp = strrchr(value(SHELL), '/')) == NULL)
705 execl(value(SHELL), cp, "-c", s, (char *)NULL);
709 args(char *buf, char *a[], int num)
711 char *p = buf, *start;
716 while (*p && (*p == ' ' || *p == '\t'))
721 while (*p && (*p != ' ' && *p != '\t'))
727 } while (*p && n < num);
733 prtime(char *s, time_t a)
738 for (i = 0; i < 3; i++) {
739 nums[i] = (int)(a % quant[i]);
744 if (nums[i] || (i == 0 && nums[1] == 0 && nums[2] == 0))
745 printf("%d %s%c ", nums[i], sep[i],
746 nums[i] == 1 ? '\0' : 's');
756 if (prompt("[set] ", buf, sizeof(buf)))
759 if (vtable[BEAUTIFY].v_access&CHANGED) {
760 vtable[BEAUTIFY].v_access &= ~CHANGED;
761 kill(tipout_pid, SIGSYS);
763 if (vtable[SCRIPT].v_access&CHANGED) {
764 vtable[SCRIPT].v_access &= ~CHANGED;
767 * So that "set record=blah script" doesn't
768 * cause two transactions to occur.
770 if (vtable[RECORD].v_access&CHANGED)
771 vtable[RECORD].v_access &= ~CHANGED;
773 if (vtable[RECORD].v_access&CHANGED) {
774 vtable[RECORD].v_access &= ~CHANGED;
775 if (boolean(value(SCRIPT)))
778 if (vtable[TAND].v_access&CHANGED) {
779 vtable[TAND].v_access &= ~CHANGED;
780 if (boolean(value(TAND)))
785 if (vtable[LECHO].v_access&CHANGED) {
786 vtable[LECHO].v_access &= ~CHANGED;
787 HD = boolean(value(LECHO));
789 if (vtable[PARITY].v_access&CHANGED) {
790 vtable[PARITY].v_access &= ~CHANGED;
793 if (vtable[HARDWAREFLOW].v_access&CHANGED) {
794 vtable[HARDWAREFLOW].v_access &= ~CHANGED;
795 if (boolean(value(HARDWAREFLOW)))
800 if (vtable[LINEDISC].v_access&CHANGED) {
801 vtable[LINEDISC].v_access &= ~CHANGED;
812 char charbuf[5]; /* for vis(3), 4 chars for encoding, plus nul */
815 for (p = vtable; p->v_name; p++) {
816 fputs(p->v_name, stdout);
817 switch (p->v_type&TMASK) {
820 buf = malloc(4*strlen(p->v_value) + 1);
822 fprintf(stderr, "Unable to malloc()\n");
825 strvis(buf, p->v_value, VIS_WHITE);
833 printf(" %ld\r\n", number(p->v_value));
837 !boolean(p->v_value) ? "false" : "true");
840 vis(charbuf, character(p->v_value), VIS_WHITE, 0);
841 printf(" %s\r\n", charbuf);
848 * Turn tandem mode on or off for remote tty.
853 struct termios rmtty;
855 tcgetattr(FD, &rmtty);
856 if (strcmp(option, "on") == 0) {
857 rmtty.c_iflag |= IXOFF;
858 term.c_iflag |= IXOFF;
860 rmtty.c_iflag &= ~IXOFF;
861 term.c_iflag &= ~IXOFF;
863 tcsetattr(FD, TCSADRAIN, &rmtty);
864 tcsetattr(0, TCSADRAIN, &term);
868 * Turn hardware flow control on or off for remote tty.
871 hardwareflow(char *option)
873 struct termios rmtty;
875 tcgetattr(FD, &rmtty);
876 if (strcmp(option, "on") == 0)
877 rmtty.c_iflag |= CRTSCTS;
879 rmtty.c_iflag &= ~CRTSCTS;
880 tcsetattr(FD, TCSADRAIN, &rmtty);
884 * Change line discipline to the specified one.
887 linedisc(char *option)
889 int ld = (int)(intptr_t)value(LINEDISC);
891 ioctl(FD, TIOCSETD, &ld);
901 ioctl(FD, TIOCSBRK, NULL);
903 ioctl(FD, TIOCCBRK, NULL);
913 kill(c == CTRL('y') ? getpid() : 0, SIGTSTP);
918 * expand a file name if it includes shell meta characters
923 static char xname[BUFSIZ];
930 if (!anyof(name, "~{[*?$`'\"\\"))
932 /* sigint = signal(SIGINT, SIG_IGN); */
933 if (pipe(pivec) < 0) {
935 /* signal(SIGINT, sigint) */
938 (void)snprintf(cmdbuf, sizeof(cmdbuf), "echo %s", name);
939 if ((pid = vfork()) == 0) {
940 Shell = value(SHELL);
942 Shell = _PATH_BSHELL;
949 execl(Shell, Shell, "-c", cmdbuf, (char *)NULL);
959 l = read(pivec[0], xname, BUFSIZ);
961 while (wait(&s) != pid);
964 if (s != 0 && s != SIGPIPE) {
965 fprintf(stderr, "\"Echo\" failed\n");
973 fprintf(stderr, "\"%s\": No match\n", name);
977 fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
981 for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
988 * Are any of the characters in the two strings the same?
991 anyof(char *s1, char *s2)