1 /* $NetBSD: cmds.c,v 1.30 2006/10/22 16:46:49 christos Exp $ */
4 * Copyright (c) 1983, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
35 static char sccsid
[] = "@(#)cmds.c 8.1 (Berkeley) 6/6/93";
37 __RCSID("$NetBSD: cmds.c,v 1.30 2006/10/22 16:46:49 christos Exp $");
41 #include "pathnames.h"
46 * miscellaneous commands
49 int quant
[] = { 60, 60, 24 };
52 const char *sep
[] = { "second", "minute", "hour" };
53 static char *argv
[10]; /* argument vector for take and put */
55 int args(char *, char **);
56 int anyof(char *, const char *);
59 void prtime(const char *, time_t);
61 void transfer(char *, int, const char *);
62 void transmit(FILE *, const char *, char *);
65 * FTP - remote ==> local
66 * get a file from the remote host
75 * get the UNIX receiving file's name
77 if (prompt("Local file name? ", copyname
, sizeof copyname
))
79 cp
= expand(copyname
);
80 if ((sfd
= open(cp
, O_RDWR
|O_CREAT
, 0666)) < 0) {
81 (void)printf("\r\n%s: cannot create\r\n", copyname
);
88 if (prompt("List command for remote system? ", buf
,
90 (void)unlink(copyname
);
93 transfer(buf
, sfd
, value(EOFREAD
));
97 * Cu-like take command
101 cu_take(char dummy __unused
)
104 char line
[BUFSIZ
], *cp
;
106 if (prompt("[take] ", copyname
, sizeof copyname
))
108 if ((argc
= args(copyname
, argv
)) < 1 || argc
> 2) {
109 (void)printf("usage: <take> from [to]\r\n");
114 cp
= expand(argv
[1]);
115 if ((fd
= open(cp
, O_RDWR
|O_CREAT
, 0666)) < 0) {
116 (void)printf("\r\n%s: cannot create\r\n", argv
[1]);
119 (void)snprintf(line
, sizeof line
, "cat %s;echo \01", argv
[0]);
120 transfer(line
, fd
, "\01");
123 static jmp_buf intbuf
;
125 * Bulk transfer routine --
126 * used by getfl(), cu_take(), and pipefile()
129 transfer(char *buf
, int fd
, const char *eofchars
)
132 char c
, buffer
[BUFSIZ
];
140 xpwrite(FD
, buf
, strlen(buf
));
142 (void)write(attndes
[1], "W", 1); /* Put TIPOUT into a wait state */
143 (void)read(repdes
[0], (char *)&ccc
, 1); /* Wait until read process stops */
151 (void)read(FD
, &c
, 1);
152 while ((c
&STRIP_PAR
) != '\n');
153 (void)tcsetattr(0, TCSAFLUSH
, &defchars
);
155 (void) setjmp(intbuf
);
156 f
= signal(SIGINT
, intcopy
);
158 for (ct
= 0; !quit
;) {
159 eof
= read(FD
, &c
, 1) <= 0;
163 if (eof
|| any(c
, eofchars
))
166 continue; /* ignore nulls */
171 if (c
== '\n' && boolean(value(VERBOSE
)))
172 (void)printf("\r%d", ++ct
);
173 if ((cnt
= (p
-buffer
)) == number(value(FRAMESIZE
))) {
174 if (write(fd
, buffer
, (size_t)cnt
) != cnt
) {
175 (void)printf("\r\nwrite error\r\n");
181 if ((cnt
= (p
-buffer
)) != 0)
182 if (write(fd
, buffer
, (size_t)cnt
) != cnt
)
183 (void)printf("\r\nwrite error\r\n");
185 if (boolean(value(VERBOSE
)))
186 prtime(" lines transferred in ", time(0)-start
);
187 (void)tcsetattr(0, TCSAFLUSH
, &term
);
188 (void)write(fildes
[1], (char *)&ccc
, 1);
189 (void)signal(SIGINT
, f
);
194 * FTP - remote ==> local process
195 * send remote input to local process via pipe
199 pipefile(char dummy __unused
)
205 if (prompt("Local command? ", buf
, sizeof buf
))
209 (void)printf("can't establish pipe\r\n");
213 if ((cpid
= fork()) < 0) {
214 (void)printf("can't fork!\r\n");
217 if (prompt("List command for remote system? ", buf
,
219 (void)close(pdes
[0]);
220 (void)close(pdes
[1]);
221 (void)kill(cpid
, SIGKILL
);
223 (void)close(pdes
[0]);
224 (void)signal(SIGPIPE
, intcopy
);
225 transfer(buf
, pdes
[1], value(EOFREAD
));
226 (void)signal(SIGPIPE
, SIG_DFL
);
227 while ((p
= wait(&status
)) > 0 && p
!= cpid
)
231 (void)dup2(pdes
[0], 0);
232 (void)close(pdes
[0]);
235 (void)printf("can't execl!\r\n");
241 * Interrupt service routine for FTP
245 stopsnd(int dummy __unused
)
249 (void)signal(SIGINT
, SIG_IGN
);
253 * FTP - local ==> remote
254 * send local file to remote host
255 * terminate transmission with pseudo EOF sequence
267 if (prompt("Local file name? ", fname
, sizeof fname
))
273 fnamex
= expand(fname
);
274 if ((fd
= fopen(fnamex
, "r")) == NULL
) {
275 (void)printf("%s: cannot open\r\n", fname
);
278 transmit(fd
, value(EOFWRITE
), NULL
);
279 if (!boolean(value(ECHOCHECK
)))
284 * Bulk transfer routine to remote host --
285 * used by sendfile() and cu_put()
288 transmit(FILE *fd
, const char *eofchars
, char *command
)
294 time_t start_t
, stop_t
;
297 (void)write(attndes
[1], "W", 1); /* put TIPOUT into a wait state */
299 f
= signal(SIGINT
, stopsnd
);
300 (void)tcsetattr(0, TCSAFLUSH
, &defchars
);
301 (void)read(repdes
[0], (char *)&ccc
, 1);
302 if (command
!= NULL
) {
303 for (pc
= command
; *pc
; pc
++)
305 if (boolean(value(ECHOCHECK
)))
306 (void)read(FD
, &c
, (size_t)1); /* trailing \n */
309 (void)sleep(5); /* wait for remote stty to take effect */
324 if (c
== 0177 && !boolean(value(RAWFTP
)))
329 if (!boolean(value(RAWFTP
)))
332 else if (c
== '\t') {
333 if (!boolean(value(RAWFTP
))) {
334 if (boolean(value(TABEXPAND
))) {
336 while ((++ccount
% 8) != 0)
342 if (!boolean(value(RAWFTP
)))
346 } while (c
!= '\r' && !boolean(value(RAWFTP
)));
347 if (boolean(value(VERBOSE
)))
348 (void)printf("\r%d", ++lcount
);
349 if (boolean(value(ECHOCHECK
))) {
351 (void)alarm((unsigned int)number(value(ETIMEOUT
)));
352 do { /* wait for prompt */
353 (void)read(FD
, &c
, (size_t)1);
354 if (timedout
|| stop
) {
357 "\r\ntimed out at eol\r\n");
361 } while ((c
&STRIP_PAR
) != character(value(PROMPT
)));
366 if (lastc
!= '\n' && !boolean(value(RAWFTP
)))
369 for (pc
= eofchars
; *pc
; pc
++)
374 (void)signal(SIGINT
, f
);
375 if (boolean(value(VERBOSE
))) {
376 if (boolean(value(RAWFTP
)))
377 prtime(" chars transferred in ", stop_t
-start_t
);
379 prtime(" lines transferred in ", stop_t
-start_t
);
381 (void)write(fildes
[1], (char *)&ccc
, 1);
382 (void)tcsetattr(0, TCSAFLUSH
, &term
);
386 * Cu-like put command
390 cu_put(char dummy __unused
)
397 if (prompt("[put] ", copyname
, sizeof copyname
))
399 if ((argc
= args(copyname
, argv
)) < 1 || argc
> 2) {
400 (void)printf("usage: <put> from [to]\r\n");
405 copynamex
= expand(argv
[0]);
406 if ((fd
= fopen(copynamex
, "r")) == NULL
) {
407 (void)printf("%s: cannot open\r\n", copynamex
);
410 if (boolean(value(ECHOCHECK
)))
411 (void)snprintf(line
, sizeof line
, "cat>%s\r", argv
[1]);
413 (void)snprintf(line
, sizeof line
, "stty -echo;cat>%s;stty echo\r", argv
[1]);
414 transmit(fd
, "\04", line
);
418 * FTP - send single character
419 * wait for echo & handle timeout
430 if (number(value(CDELAY
)) > 0 && c
!= '\r')
431 nap(number(value(CDELAY
)));
433 if (!boolean(value(ECHOCHECK
))) {
435 if (number(value(LDELAY
)) > 0 && c
== '\r')
436 nap(number(value(LDELAY
)));
442 (void)alarm((unsigned int)number(value(ETIMEOUT
)));
443 (void)read(FD
, &cc
, 1);
446 (void)printf("\r\ntimeout error (%s)\r\n", ctrl(c
));
449 xpwrite(FD
, &null
, 1); /* poke it */
456 alrmtimeout(int dummy __unused
)
459 (void)signal(SIGALRM
, alrmtimeout
);
464 * Stolen from consh() -- puts a remote file on the output of a local command.
465 * Identical to consh() except for where stdout goes.
475 if (prompt("Local command? ", buf
, sizeof buf
))
477 (void)write(attndes
[1], "W", 1); /* put TIPOUT into a wait state */
478 (void)signal(SIGINT
, SIG_IGN
);
479 (void)signal(SIGQUIT
, SIG_IGN
);
480 (void)tcsetattr(0, TCSAFLUSH
, &defchars
);
481 (void)read(repdes
[0], (char *)&ccc
, 1);
483 * Set up file descriptors in the child and
486 if ((cpid
= fork()) < 0)
487 (void)printf("can't fork!\r\n");
490 while ((p
= wait(&status
)) > 0 && p
!= cpid
)
495 (void)signal(SIGINT
, SIG_DFL
);
496 (void)signal(SIGQUIT
, SIG_DFL
);
498 (void)printf("can't find `%s'\r\n", buf
);
501 if (boolean(value(VERBOSE
)))
502 prtime("away for ", time(0)-start
);
503 (void)write(fildes
[1], (char *)&ccc
, 1);
504 (void)tcsetattr(0, TCSAFLUSH
, &term
);
505 (void)signal(SIGINT
, SIG_DFL
);
506 (void)signal(SIGQUIT
, SIG_DFL
);
510 * Fork a program with:
511 * 0 <-> remote tty in
512 * 1 <-> remote tty out
513 * 2 <-> local tty out
523 if (prompt("Local command? ", buf
, sizeof buf
))
525 (void)write(attndes
[1], "W", 1); /* put TIPOUT into a wait state */
526 (void)signal(SIGINT
, SIG_IGN
);
527 (void)signal(SIGQUIT
, SIG_IGN
);
528 (void)tcsetattr(0, TCSAFLUSH
, &defchars
);
529 (void)read(repdes
[0], (char *)&ccc
, 1);
531 * Set up file descriptors in the child and
534 if ((cpid
= fork()) < 0)
535 (void)printf("can't fork!\r\n");
538 while ((p
= wait(&status
)) > 0 && p
!= cpid
)
544 (void)signal(SIGINT
, SIG_DFL
);
545 (void)signal(SIGQUIT
, SIG_DFL
);
547 (void)printf("can't find `%s'\r\n", buf
);
550 if (boolean(value(VERBOSE
)))
551 prtime("away for ", time(0)-start
);
552 (void)write(fildes
[1], (char *)&ccc
, 1);
553 (void)tcsetattr(0, TCSAFLUSH
, &term
);
554 (void)signal(SIGINT
, SIG_DFL
);
555 (void)signal(SIGQUIT
, SIG_DFL
);
559 * Escape to local shell
563 shell(char dummy __unused
)
568 (void)printf("[sh]\r\n");
569 (void)signal(SIGINT
, SIG_IGN
);
570 (void)signal(SIGQUIT
, SIG_IGN
);
572 switch (shpid
= fork()) {
574 while (shpid
!= wait(&status
));
576 (void)printf("\r\n!\r\n");
577 (void)signal(SIGINT
, SIG_DFL
);
578 (void)signal(SIGQUIT
, SIG_DFL
);
581 (void)signal(SIGQUIT
, SIG_DFL
);
582 (void)signal(SIGINT
, SIG_DFL
);
583 if ((cp
= strrchr(value(SHELL
), '/')) == NULL
)
587 (void)execl(value(SHELL
), cp
, NULL
);
588 (void)fprintf(stderr
, "\r\n");
589 err(1, "can't execl");
592 (void)fprintf(stderr
, "\r\n");
593 err(1, "can't fork");
599 * TIPIN portion of scripting
600 * initiate the conversation with TIPOUT
607 * enable TIPOUT side for dialogue
609 (void)write(attndes
[1], "S", 1);
610 if (boolean(value(SCRIPT
)) && strlen(value(RECORD
)))
611 (void)write(fildes
[1], value(RECORD
), strlen(value(RECORD
)));
612 (void)write(fildes
[1], "\n", 1);
614 * wait for TIPOUT to finish
616 (void)read(repdes
[0], &c
, 1);
618 (void)printf("can't create %s\r\n", (char *)value(RECORD
));
622 * Change current working directory of
623 * local portion of tip
627 chdirectory(char dummy __unused
)
630 const char *cp
= dirnam
;
632 if (prompt("[cd] ", dirnam
, sizeof dirnam
)) {
638 (void)printf("%s: bad directory\r\n", cp
);
639 (void)printf("!\r\n");
643 tipabort(const char *msg
)
646 (void)kill(pid
, SIGTERM
);
649 (void)printf("\r\n%s", msg
);
650 (void)printf("\r\n[EOT]\r\n");
657 finish(char dummy __unused
)
661 dismsg
= value(DISCONNECT
);
662 if (dismsg
!= NULL
&& dismsg
[0] != '\0') {
663 (void)write(FD
, dismsg
, strlen(dismsg
));
671 intcopy(int dummy __unused
)
684 if ((cp
= strrchr(value(SHELL
), '/')) == NULL
)
688 (void)execl(value(SHELL
), cp
, "-c", s
, NULL
);
692 args(char *buf
, char *a
[])
694 char *p
= buf
, *start
;
699 while (*p
&& (*p
== ' ' || *p
== '\t'))
704 while (*p
&& (*p
!= ' ' && *p
!= '\t'))
716 prtime(const char *s
, time_t a
)
721 for (i
= 0; i
< 3; i
++) {
722 nums
[i
] = (int)(a
% quant
[i
]);
725 (void)printf("%s", s
);
727 if (nums
[i
] || (i
== 0 && nums
[1] == 0 && nums
[2] == 0))
728 (void)printf("%d %s%c ", nums
[i
], sep
[i
],
729 nums
[i
] == 1 ? '\0' : 's');
730 (void)printf("\r\n!\r\n");
735 variable(char dummy __unused
)
739 if (prompt("[set] ", buf
, sizeof buf
))
742 if (vtable
[BEAUTIFY
].v_access
&CHANGED
) {
743 vtable
[BEAUTIFY
].v_access
&= ~CHANGED
;
744 (void)write(attndes
[1], "B", 1); /* Tell TIPOUT to toggle */
746 if (vtable
[SCRIPT
].v_access
&CHANGED
) {
747 vtable
[SCRIPT
].v_access
&= ~CHANGED
;
750 * So that "set record=blah script" doesn't
751 * cause two transactions to occur.
753 if (vtable
[RECORD
].v_access
&CHANGED
)
754 vtable
[RECORD
].v_access
&= ~CHANGED
;
756 if (vtable
[RECORD
].v_access
&CHANGED
) {
757 vtable
[RECORD
].v_access
&= ~CHANGED
;
758 if (boolean(value(SCRIPT
)))
761 if (vtable
[TAND
].v_access
&CHANGED
) {
762 vtable
[TAND
].v_access
&= ~CHANGED
;
763 if (boolean(value(TAND
)))
768 if (vtable
[LECHO
].v_access
&CHANGED
) {
769 vtable
[LECHO
].v_access
&= ~CHANGED
;
770 HD
= boolean(value(LECHO
));
772 if (vtable
[PARITY
].v_access
&CHANGED
) {
773 vtable
[PARITY
].v_access
&= ~CHANGED
;
774 setparity(NULL
); /* XXX what is the correct arg? */
776 if (vtable
[HARDWAREFLOW
].v_access
&CHANGED
) {
777 vtable
[HARDWAREFLOW
].v_access
&= ~CHANGED
;
778 if (boolean(value(HARDWAREFLOW
)))
786 * Turn tandem mode on or off for remote tty.
789 tandem(const char *option
)
791 struct termios rmtty
;
793 (void)tcgetattr(FD
, &rmtty
);
794 if (strcmp(option
, "on") == 0) {
795 rmtty
.c_iflag
|= IXOFF
;
796 term
.c_iflag
|= IXOFF
;
798 rmtty
.c_iflag
&= ~IXOFF
;
799 term
.c_iflag
&= ~IXOFF
;
801 (void)tcsetattr(FD
, TCSADRAIN
, &rmtty
);
802 (void)tcsetattr(0, TCSADRAIN
, &term
);
806 * Turn hardware flow control on or off for remote tty.
809 hardwareflow(const char *option
)
811 struct termios rmtty
;
813 (void)tcgetattr(FD
, &rmtty
);
814 if (strcmp(option
, "on") == 0)
815 rmtty
.c_cflag
|= CRTSCTS
;
817 rmtty
.c_cflag
&= ~CRTSCTS
;
818 (void)tcsetattr(FD
, TCSADRAIN
, &rmtty
);
826 genbrk(char dummy __unused
)
829 (void)ioctl(FD
, TIOCSBRK
, NULL
);
831 (void)ioctl(FD
, TIOCCBRK
, NULL
);
842 (void)kill(c
== CTRL('y') ? getpid() : 0, SIGTSTP
);
847 * expand a file name if it includes shell meta characters
853 static char xname
[BUFSIZ
];
854 char * volatile name
;
862 if (!anyof(name
, "~{[*?$`'\"\\"))
864 if (pipe(pivec
) < 0) {
868 (void)snprintf(cmdbuf
, sizeof cmdbuf
, "echo %s", name
);
869 if ((mypid
= vfork()) == 0) {
870 Shell
= value(SHELL
);
872 Shell
= _PATH_BSHELL
;
873 (void)close(pivec
[0]);
876 (void)close(pivec
[1]);
878 (void)execl(Shell
, Shell
, "-c", cmdbuf
, NULL
);
883 (void)close(pivec
[0]);
884 (void)close(pivec
[1]);
887 (void)close(pivec
[1]);
888 l
= read(pivec
[0], xname
, BUFSIZ
);
889 (void)close(pivec
[0]);
890 while (wait(&s
) != mypid
);
893 if (s
!= 0 && s
!= SIGPIPE
) {
894 (void)fprintf(stderr
, "\"Echo\" failed\n");
902 (void)fprintf(stderr
, "\"%s\": No match\n", name
);
906 (void)fprintf(stderr
, "Buffer overflow expanding \"%s\"\n", name
);
910 for (cp
= &xname
[l
-1]; *cp
== '\n' && cp
> xname
; cp
--)
917 * Are any of the characters in the two strings the same?
921 anyof(char *s1
, const char *s2
)
925 while ((c
= *s1
++) != '\0')