1*6afb7d51Smlelstv /* $NetBSD: cmds.c,v 1.37 2014/07/12 05:28:07 mlelstv Exp $ */
239801cccSjtc
361f28255Scgd /*
439801cccSjtc * Copyright (c) 1983, 1993
539801cccSjtc * The Regents of the University of California. All rights reserved.
661f28255Scgd *
761f28255Scgd * Redistribution and use in source and binary forms, with or without
861f28255Scgd * modification, are permitted provided that the following conditions
961f28255Scgd * are met:
1061f28255Scgd * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd * notice, this list of conditions and the following disclaimer.
1261f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd * notice, this list of conditions and the following disclaimer in the
1461f28255Scgd * documentation and/or other materials provided with the distribution.
1589aaa1bbSagc * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd * may be used to endorse or promote products derived from this software
1761f28255Scgd * without specific prior written permission.
1861f28255Scgd *
1961f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd * SUCH DAMAGE.
3061f28255Scgd */
3161f28255Scgd
32e37283e1Slukem #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
3439801cccSjtc #if 0
3539801cccSjtc static char sccsid[] = "@(#)cmds.c 8.1 (Berkeley) 6/6/93";
3639801cccSjtc #endif
37*6afb7d51Smlelstv __RCSID("$NetBSD: cmds.c,v 1.37 2014/07/12 05:28:07 mlelstv Exp $");
3861f28255Scgd #endif /* not lint */
3961f28255Scgd
4061f28255Scgd #include "tip.h"
4161f28255Scgd #include "pathnames.h"
4261f28255Scgd
4361f28255Scgd /*
4461f28255Scgd * tip
4561f28255Scgd *
4661f28255Scgd * miscellaneous commands
4761f28255Scgd */
4861f28255Scgd
4961f28255Scgd int quant[] = { 60, 60, 24 };
5061f28255Scgd
5161f28255Scgd char null = '\0';
524f6045fcSchristos const char *sep[] = { "second", "minute", "hour" };
5361f28255Scgd static char *argv[10]; /* argument vector for take and put */
5461f28255Scgd
5558c2151fSperry int args(char *, char **);
5658c2151fSperry int anyof(char *, const char *);
5758c2151fSperry void execute(char *);
58f20d1d23Sjoerg __dead static void intcopy(int);
5958c2151fSperry void prtime(const char *, time_t);
6058c2151fSperry void stopsnd(int);
6158c2151fSperry void transfer(char *, int, const char *);
6258c2151fSperry void transmit(FILE *, const char *, char *);
6361f28255Scgd
6461f28255Scgd /*
6561f28255Scgd * FTP - remote ==> local
6661f28255Scgd * get a file from the remote host
6761f28255Scgd */
68e37283e1Slukem void
getfl(char c)6958c2151fSperry getfl(char c)
7061f28255Scgd {
71e37283e1Slukem char buf[256], *cp;
7261f28255Scgd
73ffe34450Schristos (void)putchar(c);
7461f28255Scgd /*
7561f28255Scgd * get the UNIX receiving file's name
7661f28255Scgd */
77923d7551Smrg if (prompt("Local file name? ", copyname, sizeof copyname))
7861f28255Scgd return;
7961f28255Scgd cp = expand(copyname);
809d002ba5Suebayasi if ((sfd = open(cp, O_RDWR|O_CREAT, 0666)) < 0) {
81ffe34450Schristos (void)printf("\r\n%s: cannot create\r\n", copyname);
8261f28255Scgd return;
8361f28255Scgd }
8461f28255Scgd
8561f28255Scgd /*
8661f28255Scgd * collect parameters
8761f28255Scgd */
88923d7551Smrg if (prompt("List command for remote system? ", buf,
89923d7551Smrg sizeof buf)) {
90ffe34450Schristos (void)unlink(copyname);
9161f28255Scgd return;
9261f28255Scgd }
9361f28255Scgd transfer(buf, sfd, value(EOFREAD));
9461f28255Scgd }
9561f28255Scgd
9661f28255Scgd /*
9761f28255Scgd * Cu-like take command
9861f28255Scgd */
9929dc02e5Sperry /* ARGSUSED */
100e37283e1Slukem void
cu_take(char dummy __unused)101ffe34450Schristos cu_take(char dummy __unused)
10261f28255Scgd {
10361f28255Scgd int fd, argc;
104e37283e1Slukem char line[BUFSIZ], *cp;
10561f28255Scgd
106923d7551Smrg if (prompt("[take] ", copyname, sizeof copyname))
10761f28255Scgd return;
10861f28255Scgd if ((argc = args(copyname, argv)) < 1 || argc > 2) {
109ffe34450Schristos (void)printf("usage: <take> from [to]\r\n");
11061f28255Scgd return;
11161f28255Scgd }
11261f28255Scgd if (argc == 1)
11361f28255Scgd argv[1] = argv[0];
11461f28255Scgd cp = expand(argv[1]);
1159d002ba5Suebayasi if ((fd = open(cp, O_RDWR|O_CREAT, 0666)) < 0) {
116ffe34450Schristos (void)printf("\r\n%s: cannot create\r\n", argv[1]);
11761f28255Scgd return;
11861f28255Scgd }
11953fddda6Smrg (void)snprintf(line, sizeof line, "cat %s;echo \01", argv[0]);
12061f28255Scgd transfer(line, fd, "\01");
12161f28255Scgd }
12261f28255Scgd
12361f28255Scgd static jmp_buf intbuf;
12461f28255Scgd /*
12561f28255Scgd * Bulk transfer routine --
12661f28255Scgd * used by getfl(), cu_take(), and pipefile()
12761f28255Scgd */
128e37283e1Slukem void
transfer(char * buf,int fd,const char * eofchars)12958c2151fSperry transfer(char *buf, int fd, const char *eofchars)
13061f28255Scgd {
131e37283e1Slukem int ct;
13261f28255Scgd char c, buffer[BUFSIZ];
133239d1ed1Schristos char * volatile p;
134e37283e1Slukem int cnt, eof;
13561f28255Scgd time_t start;
13661f28255Scgd sig_t f;
13739801cccSjtc char r;
13861f28255Scgd
139239d1ed1Schristos p = buffer;
140d48673ceSthorpej xpwrite(FD, buf, strlen(buf));
14161f28255Scgd quit = 0;
142ffe34450Schristos (void)write(attndes[1], "W", 1); /* Put TIPOUT into a wait state */
143ffe34450Schristos (void)read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */
14461f28255Scgd
14561f28255Scgd /*
14661f28255Scgd * finish command
14761f28255Scgd */
14839801cccSjtc r = '\r';
149d48673ceSthorpej xpwrite(FD, &r, 1);
15061f28255Scgd do
151ffe34450Schristos (void)read(FD, &c, 1);
152258108ceSpk while ((c&STRIP_PAR) != '\n');
153ffe34450Schristos (void)tcsetattr(0, TCSAFLUSH, &defchars);
15461f28255Scgd
15561f28255Scgd (void) setjmp(intbuf);
15661f28255Scgd f = signal(SIGINT, intcopy);
15761f28255Scgd start = time(0);
15861f28255Scgd for (ct = 0; !quit;) {
15961f28255Scgd eof = read(FD, &c, 1) <= 0;
160258108ceSpk c &= STRIP_PAR;
16161f28255Scgd if (quit)
16261f28255Scgd continue;
16361f28255Scgd if (eof || any(c, eofchars))
16461f28255Scgd break;
16561f28255Scgd if (c == 0)
16661f28255Scgd continue; /* ignore nulls */
16761f28255Scgd if (c == '\r')
16861f28255Scgd continue;
16961f28255Scgd *p++ = c;
17061f28255Scgd
17161f28255Scgd if (c == '\n' && boolean(value(VERBOSE)))
172ffe34450Schristos (void)printf("\r%d", ++ct);
17361f28255Scgd if ((cnt = (p-buffer)) == number(value(FRAMESIZE))) {
174c4341bc3Schristos if (write(fd, buffer, (size_t)cnt) != cnt) {
175ffe34450Schristos (void)printf("\r\nwrite error\r\n");
17661f28255Scgd quit = 1;
17761f28255Scgd }
17861f28255Scgd p = buffer;
17961f28255Scgd }
18061f28255Scgd }
181e37283e1Slukem if ((cnt = (p-buffer)) != 0)
182c4341bc3Schristos if (write(fd, buffer, (size_t)cnt) != cnt)
183ffe34450Schristos (void)printf("\r\nwrite error\r\n");
18461f28255Scgd
18561f28255Scgd if (boolean(value(VERBOSE)))
18661f28255Scgd prtime(" lines transferred in ", time(0)-start);
187c4341bc3Schristos (void)tcsetattr(0, TCSAFLUSH, &term);
188c4341bc3Schristos (void)write(fildes[1], (char *)&ccc, 1);
189c4341bc3Schristos (void)signal(SIGINT, f);
190c4341bc3Schristos (void)close(fd);
19161f28255Scgd }
19261f28255Scgd
19361f28255Scgd /*
19461f28255Scgd * FTP - remote ==> local process
19561f28255Scgd * send remote input to local process via pipe
19661f28255Scgd */
19729dc02e5Sperry /* ARGSUSED */
198e37283e1Slukem void
pipefile(char dummy __unused)199ffe34450Schristos pipefile(char dummy __unused)
20061f28255Scgd {
20161f28255Scgd int cpid, pdes[2];
20261f28255Scgd char buf[256];
20361f28255Scgd int status, p;
20461f28255Scgd
205923d7551Smrg if (prompt("Local command? ", buf, sizeof buf))
20661f28255Scgd return;
20761f28255Scgd
20861f28255Scgd if (pipe(pdes)) {
209ffe34450Schristos (void)printf("can't establish pipe\r\n");
21061f28255Scgd return;
21161f28255Scgd }
21261f28255Scgd
21361f28255Scgd if ((cpid = fork()) < 0) {
214ffe34450Schristos (void)printf("can't fork!\r\n");
21561f28255Scgd return;
21661f28255Scgd } else if (cpid) {
217923d7551Smrg if (prompt("List command for remote system? ", buf,
218923d7551Smrg sizeof buf)) {
219ffe34450Schristos (void)close(pdes[0]);
220ffe34450Schristos (void)close(pdes[1]);
221ffe34450Schristos (void)kill(cpid, SIGKILL);
22261f28255Scgd } else {
223ffe34450Schristos (void)close(pdes[0]);
224ffe34450Schristos (void)signal(SIGPIPE, intcopy);
22561f28255Scgd transfer(buf, pdes[1], value(EOFREAD));
226ffe34450Schristos (void)signal(SIGPIPE, SIG_DFL);
22761f28255Scgd while ((p = wait(&status)) > 0 && p != cpid)
22861f28255Scgd ;
22961f28255Scgd }
23061f28255Scgd } else {
231ffe34450Schristos (void)dup2(pdes[0], 0);
232ffe34450Schristos (void)close(pdes[0]);
233ffe34450Schristos (void)closefrom(3);
23461f28255Scgd execute(buf);
235ffe34450Schristos (void)printf("can't execl!\r\n");
23661f28255Scgd exit(0);
23761f28255Scgd }
23861f28255Scgd }
23961f28255Scgd
24061f28255Scgd /*
24161f28255Scgd * Interrupt service routine for FTP
24261f28255Scgd */
24329dc02e5Sperry /* ARGSUSED */
24461f28255Scgd void
stopsnd(int dummy __unused)245ffe34450Schristos stopsnd(int dummy __unused)
24661f28255Scgd {
24761f28255Scgd
24861f28255Scgd stop = 1;
249ffe34450Schristos (void)signal(SIGINT, SIG_IGN);
25061f28255Scgd }
25161f28255Scgd
25261f28255Scgd /*
25361f28255Scgd * FTP - local ==> remote
25461f28255Scgd * send local file to remote host
25561f28255Scgd * terminate transmission with pseudo EOF sequence
25661f28255Scgd */
257e37283e1Slukem void
sendfile(char cc)25858c2151fSperry sendfile(char cc)
25961f28255Scgd {
26061f28255Scgd FILE *fd;
26161f28255Scgd char *fnamex;
26261f28255Scgd
263ffe34450Schristos (void)putchar(cc);
26461f28255Scgd /*
26561f28255Scgd * get file name
26661f28255Scgd */
267923d7551Smrg if (prompt("Local file name? ", fname, sizeof fname))
26861f28255Scgd return;
26961f28255Scgd
27061f28255Scgd /*
27161f28255Scgd * look up file
27261f28255Scgd */
27361f28255Scgd fnamex = expand(fname);
27461f28255Scgd if ((fd = fopen(fnamex, "r")) == NULL) {
275ffe34450Schristos (void)printf("%s: cannot open\r\n", fname);
27661f28255Scgd return;
27761f28255Scgd }
27861f28255Scgd transmit(fd, value(EOFWRITE), NULL);
279258108ceSpk if (!boolean(value(ECHOCHECK)))
280ffe34450Schristos (void)tcdrain(FD);
28161f28255Scgd }
28261f28255Scgd
28361f28255Scgd /*
28461f28255Scgd * Bulk transfer routine to remote host --
28561f28255Scgd * used by sendfile() and cu_put()
28661f28255Scgd */
287e37283e1Slukem void
transmit(FILE * fd,const char * eofchars,char * command)28858c2151fSperry transmit(FILE *fd, const char *eofchars, char *command)
28961f28255Scgd {
2904f6045fcSchristos const char *pc;
2914f6045fcSchristos char lastc;
292c4341bc3Schristos int c;
293c4341bc3Schristos int ccount, lcount;
29461f28255Scgd time_t start_t, stop_t;
29561f28255Scgd sig_t f;
29661f28255Scgd
297ffe34450Schristos (void)write(attndes[1], "W", 1); /* put TIPOUT into a wait state */
29861f28255Scgd stop = 0;
29961f28255Scgd f = signal(SIGINT, stopsnd);
300ffe34450Schristos (void)tcsetattr(0, TCSAFLUSH, &defchars);
301ffe34450Schristos (void)read(repdes[0], (char *)&ccc, 1);
30261f28255Scgd if (command != NULL) {
30361f28255Scgd for (pc = command; *pc; pc++)
304c4341bc3Schristos sendchar(*pc);
30561f28255Scgd if (boolean(value(ECHOCHECK)))
306c4341bc3Schristos (void)read(FD, &c, (size_t)1); /* trailing \n */
30761f28255Scgd else {
308ffe34450Schristos (void)tcdrain(FD);
309ffe34450Schristos (void)sleep(5); /* wait for remote stty to take effect */
31061f28255Scgd }
31161f28255Scgd }
31261f28255Scgd lcount = 0;
31361f28255Scgd lastc = '\0';
31461f28255Scgd start_t = time(0);
31529dc02e5Sperry /* CONSTCOND */
31661f28255Scgd while (1) {
31761f28255Scgd ccount = 0;
31861f28255Scgd do {
31961f28255Scgd c = getc(fd);
32061f28255Scgd if (stop)
32161f28255Scgd goto out;
32261f28255Scgd if (c == EOF)
32361f28255Scgd goto out;
32461f28255Scgd if (c == 0177 && !boolean(value(RAWFTP)))
32561f28255Scgd continue;
32661f28255Scgd lastc = c;
32761f28255Scgd if (c < 040) {
32861f28255Scgd if (c == '\n') {
32961f28255Scgd if (!boolean(value(RAWFTP)))
33061f28255Scgd c = '\r';
33161f28255Scgd }
33261f28255Scgd else if (c == '\t') {
33361f28255Scgd if (!boolean(value(RAWFTP))) {
33461f28255Scgd if (boolean(value(TABEXPAND))) {
335c4341bc3Schristos sendchar(' ');
33661f28255Scgd while ((++ccount % 8) != 0)
337c4341bc3Schristos sendchar(' ');
33861f28255Scgd continue;
33961f28255Scgd }
34061f28255Scgd }
34161f28255Scgd } else
34261f28255Scgd if (!boolean(value(RAWFTP)))
34361f28255Scgd continue;
34461f28255Scgd }
345c4341bc3Schristos sendchar(c);
34661f28255Scgd } while (c != '\r' && !boolean(value(RAWFTP)));
34761f28255Scgd if (boolean(value(VERBOSE)))
348ffe34450Schristos (void)printf("\r%d", ++lcount);
34961f28255Scgd if (boolean(value(ECHOCHECK))) {
35061f28255Scgd timedout = 0;
351ffe34450Schristos (void)alarm((unsigned int)number(value(ETIMEOUT)));
35261f28255Scgd do { /* wait for prompt */
353ffe34450Schristos (void)read(FD, &c, (size_t)1);
35461f28255Scgd if (timedout || stop) {
35561f28255Scgd if (timedout)
356ffe34450Schristos (void)printf(
357e37283e1Slukem "\r\ntimed out at eol\r\n");
358ffe34450Schristos (void)alarm(0);
35961f28255Scgd goto out;
36061f28255Scgd }
361258108ceSpk } while ((c&STRIP_PAR) != character(value(PROMPT)));
362ffe34450Schristos (void)alarm(0);
36361f28255Scgd }
36461f28255Scgd }
36561f28255Scgd out:
36661f28255Scgd if (lastc != '\n' && !boolean(value(RAWFTP)))
367c4341bc3Schristos sendchar('\r');
3680b470f4fSjtc if (eofchars) {
36961f28255Scgd for (pc = eofchars; *pc; pc++)
370c4341bc3Schristos sendchar(*pc);
3710b470f4fSjtc }
37261f28255Scgd stop_t = time(0);
373ffe34450Schristos (void)fclose(fd);
374ffe34450Schristos (void)signal(SIGINT, f);
375f670fa10Sross if (boolean(value(VERBOSE))) {
37661f28255Scgd if (boolean(value(RAWFTP)))
37761f28255Scgd prtime(" chars transferred in ", stop_t-start_t);
37861f28255Scgd else
37961f28255Scgd prtime(" lines transferred in ", stop_t-start_t);
380f670fa10Sross }
381ffe34450Schristos (void)write(fildes[1], (char *)&ccc, 1);
382ffe34450Schristos (void)tcsetattr(0, TCSAFLUSH, &term);
38361f28255Scgd }
38461f28255Scgd
38561f28255Scgd /*
38661f28255Scgd * Cu-like put command
38761f28255Scgd */
38829dc02e5Sperry /* ARGSUSED */
389e37283e1Slukem void
cu_put(char dummy __unused)390ffe34450Schristos cu_put(char dummy __unused)
39161f28255Scgd {
39261f28255Scgd FILE *fd;
39361f28255Scgd char line[BUFSIZ];
39461f28255Scgd int argc;
39561f28255Scgd char *copynamex;
39661f28255Scgd
397923d7551Smrg if (prompt("[put] ", copyname, sizeof copyname))
39861f28255Scgd return;
39961f28255Scgd if ((argc = args(copyname, argv)) < 1 || argc > 2) {
400ffe34450Schristos (void)printf("usage: <put> from [to]\r\n");
40161f28255Scgd return;
40261f28255Scgd }
40361f28255Scgd if (argc == 1)
40461f28255Scgd argv[1] = argv[0];
40561f28255Scgd copynamex = expand(argv[0]);
40661f28255Scgd if ((fd = fopen(copynamex, "r")) == NULL) {
407ffe34450Schristos (void)printf("%s: cannot open\r\n", copynamex);
40861f28255Scgd return;
40961f28255Scgd }
41061f28255Scgd if (boolean(value(ECHOCHECK)))
41153fddda6Smrg (void)snprintf(line, sizeof line, "cat>%s\r", argv[1]);
41261f28255Scgd else
41353fddda6Smrg (void)snprintf(line, sizeof line, "stty -echo;cat>%s;stty echo\r", argv[1]);
41461f28255Scgd transmit(fd, "\04", line);
41561f28255Scgd }
41661f28255Scgd
41761f28255Scgd /*
41861f28255Scgd * FTP - send single character
41961f28255Scgd * wait for echo & handle timeout
42061f28255Scgd */
421e37283e1Slukem void
sendchar(char c)422c4341bc3Schristos sendchar(char c)
42361f28255Scgd {
42461f28255Scgd char cc;
42561f28255Scgd int retry = 0;
42661f28255Scgd
42761f28255Scgd cc = c;
428d48673ceSthorpej xpwrite(FD, &cc, 1);
42961f28255Scgd #ifdef notdef
43061f28255Scgd if (number(value(CDELAY)) > 0 && c != '\r')
43161f28255Scgd nap(number(value(CDELAY)));
43261f28255Scgd #endif
43361f28255Scgd if (!boolean(value(ECHOCHECK))) {
43461f28255Scgd #ifdef notdef
43561f28255Scgd if (number(value(LDELAY)) > 0 && c == '\r')
43661f28255Scgd nap(number(value(LDELAY)));
43761f28255Scgd #endif
43861f28255Scgd return;
43961f28255Scgd }
44061f28255Scgd tryagain:
44161f28255Scgd timedout = 0;
442ffe34450Schristos (void)alarm((unsigned int)number(value(ETIMEOUT)));
443ffe34450Schristos (void)read(FD, &cc, 1);
444ffe34450Schristos (void)alarm(0);
44561f28255Scgd if (timedout) {
446ffe34450Schristos (void)printf("\r\ntimeout error (%s)\r\n", ctrl(c));
44761f28255Scgd if (retry++ > 3)
44861f28255Scgd return;
449d48673ceSthorpej xpwrite(FD, &null, 1); /* poke it */
45061f28255Scgd goto tryagain;
45161f28255Scgd }
45261f28255Scgd }
45361f28255Scgd
45429dc02e5Sperry /* ARGSUSED */
45561f28255Scgd void
alrmtimeout(int dummy __unused)456ffe34450Schristos alrmtimeout(int dummy __unused)
45761f28255Scgd {
458923d7551Smrg
459ffe34450Schristos (void)signal(SIGALRM, alrmtimeout);
46061f28255Scgd timedout = 1;
46161f28255Scgd }
46261f28255Scgd
46361f28255Scgd /*
46461f28255Scgd * Stolen from consh() -- puts a remote file on the output of a local command.
46561f28255Scgd * Identical to consh() except for where stdout goes.
46661f28255Scgd */
467e37283e1Slukem void
pipeout(char c)46858c2151fSperry pipeout(char c)
46961f28255Scgd {
47061f28255Scgd char buf[256];
47161f28255Scgd int cpid, status, p;
472e37283e1Slukem time_t start = 0;
47361f28255Scgd
474ffe34450Schristos (void)putchar(c);
475923d7551Smrg if (prompt("Local command? ", buf, sizeof buf))
47661f28255Scgd return;
477ffe34450Schristos (void)write(attndes[1], "W", 1); /* put TIPOUT into a wait state */
478ffe34450Schristos (void)signal(SIGINT, SIG_IGN);
479ffe34450Schristos (void)signal(SIGQUIT, SIG_IGN);
480ffe34450Schristos (void)tcsetattr(0, TCSAFLUSH, &defchars);
481ffe34450Schristos (void)read(repdes[0], (char *)&ccc, 1);
48261f28255Scgd /*
48361f28255Scgd * Set up file descriptors in the child and
48461f28255Scgd * let it go...
48561f28255Scgd */
48661f28255Scgd if ((cpid = fork()) < 0)
487ffe34450Schristos (void)printf("can't fork!\r\n");
48861f28255Scgd else if (cpid) {
48961f28255Scgd start = time(0);
49061f28255Scgd while ((p = wait(&status)) > 0 && p != cpid)
49161f28255Scgd ;
49261f28255Scgd } else {
493ffe34450Schristos (void)dup2(FD, 1);
494ffe34450Schristos (void)closefrom(3);
495ffe34450Schristos (void)signal(SIGINT, SIG_DFL);
496ffe34450Schristos (void)signal(SIGQUIT, SIG_DFL);
49761f28255Scgd execute(buf);
498ffe34450Schristos (void)printf("can't find `%s'\r\n", buf);
49961f28255Scgd exit(0);
50061f28255Scgd }
50161f28255Scgd if (boolean(value(VERBOSE)))
50261f28255Scgd prtime("away for ", time(0)-start);
503ffe34450Schristos (void)write(fildes[1], (char *)&ccc, 1);
504ffe34450Schristos (void)tcsetattr(0, TCSAFLUSH, &term);
505ffe34450Schristos (void)signal(SIGINT, SIG_DFL);
506ffe34450Schristos (void)signal(SIGQUIT, SIG_DFL);
50761f28255Scgd }
50861f28255Scgd
50961f28255Scgd /*
51061f28255Scgd * Fork a program with:
51161f28255Scgd * 0 <-> remote tty in
51261f28255Scgd * 1 <-> remote tty out
51361f28255Scgd * 2 <-> local tty out
51461f28255Scgd */
515e37283e1Slukem void
consh(char c)51658c2151fSperry consh(char c)
51761f28255Scgd {
51861f28255Scgd char buf[256];
51961f28255Scgd int cpid, status, p;
520e37283e1Slukem time_t start = 0;
52161f28255Scgd
522ffe34450Schristos (void)putchar(c);
523923d7551Smrg if (prompt("Local command? ", buf, sizeof buf))
52461f28255Scgd return;
525ffe34450Schristos (void)write(attndes[1], "W", 1); /* put TIPOUT into a wait state */
526ffe34450Schristos (void)signal(SIGINT, SIG_IGN);
527ffe34450Schristos (void)signal(SIGQUIT, SIG_IGN);
528ffe34450Schristos (void)tcsetattr(0, TCSAFLUSH, &defchars);
529ffe34450Schristos (void)read(repdes[0], (char *)&ccc, 1);
53061f28255Scgd /*
53161f28255Scgd * Set up file descriptors in the child and
53261f28255Scgd * let it go...
53361f28255Scgd */
53461f28255Scgd if ((cpid = fork()) < 0)
535ffe34450Schristos (void)printf("can't fork!\r\n");
53661f28255Scgd else if (cpid) {
53761f28255Scgd start = time(0);
53861f28255Scgd while ((p = wait(&status)) > 0 && p != cpid)
53961f28255Scgd ;
54061f28255Scgd } else {
541ffe34450Schristos (void)dup2(FD, 0);
542ffe34450Schristos (void)dup2(FD, 1);
543ffe34450Schristos (void)closefrom(3);
544ffe34450Schristos (void)signal(SIGINT, SIG_DFL);
545ffe34450Schristos (void)signal(SIGQUIT, SIG_DFL);
54661f28255Scgd execute(buf);
547ffe34450Schristos (void)printf("can't find `%s'\r\n", buf);
54861f28255Scgd exit(0);
54961f28255Scgd }
55061f28255Scgd if (boolean(value(VERBOSE)))
55161f28255Scgd prtime("away for ", time(0)-start);
552ffe34450Schristos (void)write(fildes[1], (char *)&ccc, 1);
553ffe34450Schristos (void)tcsetattr(0, TCSAFLUSH, &term);
554ffe34450Schristos (void)signal(SIGINT, SIG_DFL);
555ffe34450Schristos (void)signal(SIGQUIT, SIG_DFL);
55661f28255Scgd }
55761f28255Scgd
55861f28255Scgd /*
55961f28255Scgd * Escape to local shell
56061f28255Scgd */
56129dc02e5Sperry /* ARGSUSED */
562e37283e1Slukem void
shell(char dummy __unused)563ffe34450Schristos shell(char dummy __unused)
56461f28255Scgd {
56561f28255Scgd int shpid, status;
5664f6045fcSchristos const char *cp;
56761f28255Scgd
568ffe34450Schristos (void)printf("[sh]\r\n");
569ffe34450Schristos (void)signal(SIGINT, SIG_IGN);
570ffe34450Schristos (void)signal(SIGQUIT, SIG_IGN);
57161f28255Scgd unraw();
572e37283e1Slukem switch (shpid = fork()) {
573e37283e1Slukem default:
57461f28255Scgd while (shpid != wait(&status));
57561f28255Scgd raw();
576ffe34450Schristos (void)printf("\r\n!\r\n");
577ffe34450Schristos (void)signal(SIGINT, SIG_DFL);
578ffe34450Schristos (void)signal(SIGQUIT, SIG_DFL);
579e37283e1Slukem break;
580e37283e1Slukem case 0:
581ffe34450Schristos (void)signal(SIGQUIT, SIG_DFL);
582ffe34450Schristos (void)signal(SIGINT, SIG_DFL);
583e37283e1Slukem if ((cp = strrchr(value(SHELL), '/')) == NULL)
58461f28255Scgd cp = value(SHELL);
58561f28255Scgd else
58661f28255Scgd cp++;
587ffe34450Schristos (void)execl(value(SHELL), cp, NULL);
588ffe34450Schristos (void)fprintf(stderr, "\r\n");
589e37283e1Slukem err(1, "can't execl");
590e37283e1Slukem /* NOTREACHED */
591e37283e1Slukem case -1:
592ffe34450Schristos (void)fprintf(stderr, "\r\n");
593e37283e1Slukem err(1, "can't fork");
594e37283e1Slukem /* NOTREACHED */
59561f28255Scgd }
59661f28255Scgd }
59761f28255Scgd
59861f28255Scgd /*
59961f28255Scgd * TIPIN portion of scripting
60061f28255Scgd * initiate the conversation with TIPOUT
60161f28255Scgd */
602e37283e1Slukem void
setscript(void)60358c2151fSperry setscript(void)
60461f28255Scgd {
60561f28255Scgd char c;
60661f28255Scgd /*
60761f28255Scgd * enable TIPOUT side for dialogue
60861f28255Scgd */
609ffe34450Schristos (void)write(attndes[1], "S", 1);
6106b9d2f6aSlukem if (boolean(value(SCRIPT)) && strlen(value(RECORD)))
611ffe34450Schristos (void)write(fildes[1], value(RECORD), strlen(value(RECORD)));
612ffe34450Schristos (void)write(fildes[1], "\n", 1);
61361f28255Scgd /*
61461f28255Scgd * wait for TIPOUT to finish
61561f28255Scgd */
616ffe34450Schristos (void)read(repdes[0], &c, 1);
61761f28255Scgd if (c == 'n')
618ffe34450Schristos (void)printf("can't create %s\r\n", (char *)value(RECORD));
61961f28255Scgd }
62061f28255Scgd
62161f28255Scgd /*
62261f28255Scgd * Change current working directory of
62361f28255Scgd * local portion of tip
62461f28255Scgd */
62529dc02e5Sperry /* ARGSUSED */
626e37283e1Slukem void
chdirectory(char dummy __unused)627ffe34450Schristos chdirectory(char dummy __unused)
62861f28255Scgd {
6294f6045fcSchristos char dirnam[80];
6304f6045fcSchristos const char *cp = dirnam;
63161f28255Scgd
6324f6045fcSchristos if (prompt("[cd] ", dirnam, sizeof dirnam)) {
63361f28255Scgd if (stoprompt)
63461f28255Scgd return;
63561f28255Scgd cp = value(HOME);
63661f28255Scgd }
63761f28255Scgd if (chdir(cp) < 0)
638ffe34450Schristos (void)printf("%s: bad directory\r\n", cp);
639ffe34450Schristos (void)printf("!\r\n");
64061f28255Scgd }
64161f28255Scgd
642e37283e1Slukem void
tipabort(const char * msg)64358c2151fSperry tipabort(const char *msg)
64461f28255Scgd {
64561f28255Scgd
646ffe34450Schristos (void)kill(pid, SIGTERM);
64761f28255Scgd disconnect(msg);
648e37283e1Slukem if (msg != NULL)
649ffe34450Schristos (void)printf("\r\n%s", msg);
650ffe34450Schristos (void)printf("\r\n[EOT]\r\n");
65161f28255Scgd unraw();
65261f28255Scgd exit(0);
65361f28255Scgd }
65461f28255Scgd
65529dc02e5Sperry /* ARGSUSED */
656e37283e1Slukem void
finish(char dummy __unused)657ffe34450Schristos finish(char dummy __unused)
65861f28255Scgd {
6594f6045fcSchristos const char *dismsg;
66061f28255Scgd
6616b9d2f6aSlukem dismsg = value(DISCONNECT);
6626b9d2f6aSlukem if (dismsg != NULL && dismsg[0] != '\0') {
663ffe34450Schristos (void)write(FD, dismsg, strlen(dismsg));
664ffe34450Schristos (void)sleep(5);
66561f28255Scgd }
666e37283e1Slukem tipabort(NULL);
66761f28255Scgd }
66861f28255Scgd
66929dc02e5Sperry /* ARGSUSED */
67061f28255Scgd void
intcopy(int dummy __unused)671ffe34450Schristos intcopy(int dummy __unused)
67261f28255Scgd {
673923d7551Smrg
67461f28255Scgd raw();
67561f28255Scgd quit = 1;
67661f28255Scgd longjmp(intbuf, 1);
67761f28255Scgd }
67861f28255Scgd
679e37283e1Slukem void
execute(char * s)68058c2151fSperry execute(char *s)
68161f28255Scgd {
6824f6045fcSchristos const char *cp;
68361f28255Scgd
684e37283e1Slukem if ((cp = strrchr(value(SHELL), '/')) == NULL)
68561f28255Scgd cp = value(SHELL);
68661f28255Scgd else
68761f28255Scgd cp++;
688ffe34450Schristos (void)execl(value(SHELL), cp, "-c", s, NULL);
68961f28255Scgd }
69061f28255Scgd
691e37283e1Slukem int
args(char * buf,char * a[])69258c2151fSperry args(char *buf, char *a[])
69361f28255Scgd {
694e37283e1Slukem char *p = buf, *start;
695e37283e1Slukem char **parg = a;
696e37283e1Slukem int n = 0;
69761f28255Scgd
69861f28255Scgd do {
69961f28255Scgd while (*p && (*p == ' ' || *p == '\t'))
70061f28255Scgd p++;
70161f28255Scgd start = p;
70261f28255Scgd if (*p)
70361f28255Scgd *parg = p;
70461f28255Scgd while (*p && (*p != ' ' && *p != '\t'))
70561f28255Scgd p++;
70661f28255Scgd if (p != start)
70761f28255Scgd parg++, n++;
70861f28255Scgd if (*p)
70961f28255Scgd *p++ = '\0';
71061f28255Scgd } while (*p);
71161f28255Scgd
71261f28255Scgd return(n);
71361f28255Scgd }
71461f28255Scgd
715e37283e1Slukem void
prtime(const char * s,time_t a)71658c2151fSperry prtime(const char *s, time_t a)
71761f28255Scgd {
718e37283e1Slukem int i;
71961f28255Scgd int nums[3];
72061f28255Scgd
72161f28255Scgd for (i = 0; i < 3; i++) {
72261f28255Scgd nums[i] = (int)(a % quant[i]);
72361f28255Scgd a /= quant[i];
72461f28255Scgd }
725ffe34450Schristos (void)printf("%s", s);
72661f28255Scgd while (--i >= 0)
727e37283e1Slukem if (nums[i] || (i == 0 && nums[1] == 0 && nums[2] == 0))
728ffe34450Schristos (void)printf("%d %s%c ", nums[i], sep[i],
72961f28255Scgd nums[i] == 1 ? '\0' : 's');
730ffe34450Schristos (void)printf("\r\n!\r\n");
73161f28255Scgd }
73261f28255Scgd
73329dc02e5Sperry /* ARGSUSED */
734e37283e1Slukem void
variable(char dummy __unused)735ffe34450Schristos variable(char dummy __unused)
73661f28255Scgd {
73761f28255Scgd char buf[256];
73861f28255Scgd
739923d7551Smrg if (prompt("[set] ", buf, sizeof buf))
74061f28255Scgd return;
74161f28255Scgd vlex(buf);
74261f28255Scgd if (vtable[BEAUTIFY].v_access&CHANGED) {
74361f28255Scgd vtable[BEAUTIFY].v_access &= ~CHANGED;
744ffe34450Schristos (void)write(attndes[1], "B", 1); /* Tell TIPOUT to toggle */
74561f28255Scgd }
74661f28255Scgd if (vtable[SCRIPT].v_access&CHANGED) {
74761f28255Scgd vtable[SCRIPT].v_access &= ~CHANGED;
74861f28255Scgd setscript();
74961f28255Scgd /*
75061f28255Scgd * So that "set record=blah script" doesn't
75161f28255Scgd * cause two transactions to occur.
75261f28255Scgd */
75361f28255Scgd if (vtable[RECORD].v_access&CHANGED)
75461f28255Scgd vtable[RECORD].v_access &= ~CHANGED;
75561f28255Scgd }
75661f28255Scgd if (vtable[RECORD].v_access&CHANGED) {
75761f28255Scgd vtable[RECORD].v_access &= ~CHANGED;
75861f28255Scgd if (boolean(value(SCRIPT)))
75961f28255Scgd setscript();
76061f28255Scgd }
76161f28255Scgd if (vtable[TAND].v_access&CHANGED) {
76261f28255Scgd vtable[TAND].v_access &= ~CHANGED;
76361f28255Scgd if (boolean(value(TAND)))
76461f28255Scgd tandem("on");
76561f28255Scgd else
76661f28255Scgd tandem("off");
76761f28255Scgd }
76861f28255Scgd if (vtable[LECHO].v_access&CHANGED) {
76961f28255Scgd vtable[LECHO].v_access &= ~CHANGED;
77061f28255Scgd HD = boolean(value(LECHO));
77161f28255Scgd }
77261f28255Scgd if (vtable[PARITY].v_access&CHANGED) {
77361f28255Scgd vtable[PARITY].v_access &= ~CHANGED;
774e37283e1Slukem setparity(NULL); /* XXX what is the correct arg? */
77561f28255Scgd }
77601ef0244Syamt if (vtable[HARDWAREFLOW].v_access&CHANGED) {
77701ef0244Syamt vtable[HARDWAREFLOW].v_access &= ~CHANGED;
77801ef0244Syamt if (boolean(value(HARDWAREFLOW)))
77901ef0244Syamt hardwareflow("on");
78001ef0244Syamt else
78101ef0244Syamt hardwareflow("off");
78201ef0244Syamt }
78361f28255Scgd }
78461f28255Scgd
78561f28255Scgd /*
78661f28255Scgd * Turn tandem mode on or off for remote tty.
78761f28255Scgd */
788e37283e1Slukem void
tandem(const char * option)78958c2151fSperry tandem(const char *option)
79061f28255Scgd {
791258108ceSpk struct termios rmtty;
79261f28255Scgd
793ffe34450Schristos (void)tcgetattr(FD, &rmtty);
79461f28255Scgd if (strcmp(option, "on") == 0) {
795*6afb7d51Smlelstv rmtty.c_iflag |= IXON|IXOFF;
796*6afb7d51Smlelstv term.c_iflag |= IXON|IXOFF;
79761f28255Scgd } else {
798*6afb7d51Smlelstv rmtty.c_iflag &= ~(IXON|IXOFF);
799*6afb7d51Smlelstv term.c_iflag &= ~(IXON|IXOFF);
80061f28255Scgd }
801ffe34450Schristos (void)tcsetattr(FD, TCSADRAIN, &rmtty);
802ffe34450Schristos (void)tcsetattr(0, TCSADRAIN, &term);
80361f28255Scgd }
80461f28255Scgd
80561f28255Scgd /*
80601ef0244Syamt * Turn hardware flow control on or off for remote tty.
80701ef0244Syamt */
80801ef0244Syamt void
hardwareflow(const char * option)80958c2151fSperry hardwareflow(const char *option)
81001ef0244Syamt {
81101ef0244Syamt struct termios rmtty;
81201ef0244Syamt
813ffe34450Schristos (void)tcgetattr(FD, &rmtty);
81401ef0244Syamt if (strcmp(option, "on") == 0)
815da6a898cStls rmtty.c_cflag |= CRTSCTS;
81601ef0244Syamt else
817da6a898cStls rmtty.c_cflag &= ~CRTSCTS;
818ffe34450Schristos (void)tcsetattr(FD, TCSADRAIN, &rmtty);
81901ef0244Syamt }
82001ef0244Syamt
82101ef0244Syamt /*
82261f28255Scgd * Send a break.
82361f28255Scgd */
82429dc02e5Sperry /* ARGSUSED */
825e37283e1Slukem void
genbrk(char dummy __unused)826ffe34450Schristos genbrk(char dummy __unused)
82761f28255Scgd {
82861f28255Scgd
829ffe34450Schristos (void)ioctl(FD, TIOCSBRK, NULL);
830ffe34450Schristos (void)sleep(1);
831ffe34450Schristos (void)ioctl(FD, TIOCCBRK, NULL);
83261f28255Scgd }
83361f28255Scgd
83461f28255Scgd /*
83561f28255Scgd * Suspend tip
83661f28255Scgd */
837e37283e1Slukem void
suspend(char c)83858c2151fSperry suspend(char c)
83961f28255Scgd {
84061f28255Scgd
84161f28255Scgd unraw();
842ffe34450Schristos (void)kill(c == CTRL('y') ? getpid() : 0, SIGTSTP);
84361f28255Scgd raw();
84461f28255Scgd }
84561f28255Scgd
84661f28255Scgd /*
84761f28255Scgd * expand a file name if it includes shell meta characters
84861f28255Scgd */
84961f28255Scgd
85061f28255Scgd char *
expand(char aname[])851528614c1Schristos expand(char aname[])
85261f28255Scgd {
85361f28255Scgd static char xname[BUFSIZ];
854239d1ed1Schristos char * volatile name;
85561f28255Scgd char cmdbuf[BUFSIZ];
8564f6045fcSchristos int mypid, l;
8574f6045fcSchristos char *cp;
8584f6045fcSchristos const char *Shell;
859e37283e1Slukem int s, pivec[2];
86061f28255Scgd
861239d1ed1Schristos name = aname;
86261f28255Scgd if (!anyof(name, "~{[*?$`'\"\\"))
86361f28255Scgd return(name);
86461f28255Scgd if (pipe(pivec) < 0) {
865b8dc57b8Stls warn("pipe");
86661f28255Scgd return(name);
86761f28255Scgd }
86853fddda6Smrg (void)snprintf(cmdbuf, sizeof cmdbuf, "echo %s", name);
8694f6045fcSchristos if ((mypid = vfork()) == 0) {
87061f28255Scgd Shell = value(SHELL);
871e37283e1Slukem if (Shell == NULL)
87261f28255Scgd Shell = _PATH_BSHELL;
873ffe34450Schristos (void)close(pivec[0]);
874ffe34450Schristos (void)close(1);
875ffe34450Schristos (void)dup(pivec[1]);
876ffe34450Schristos (void)close(pivec[1]);
877ffe34450Schristos (void)close(2);
878ffe34450Schristos (void)execl(Shell, Shell, "-c", cmdbuf, NULL);
87961f28255Scgd _exit(1);
88061f28255Scgd }
8814f6045fcSchristos if (mypid == -1) {
882b8dc57b8Stls warn("fork");
883ffe34450Schristos (void)close(pivec[0]);
884ffe34450Schristos (void)close(pivec[1]);
885e37283e1Slukem return(NULL);
88661f28255Scgd }
887ffe34450Schristos (void)close(pivec[1]);
88861f28255Scgd l = read(pivec[0], xname, BUFSIZ);
889ffe34450Schristos (void)close(pivec[0]);
890a625573bSjoerg while (wait(&s) != mypid)
8917a5b80beSjoerg continue;
89261f28255Scgd s &= 0377;
89361f28255Scgd if (s != 0 && s != SIGPIPE) {
894ffe34450Schristos (void)fprintf(stderr, "\"Echo\" failed\n");
895e37283e1Slukem return(NULL);
89661f28255Scgd }
89761f28255Scgd if (l < 0) {
898b8dc57b8Stls warn("read");
899e37283e1Slukem return(NULL);
90061f28255Scgd }
90161f28255Scgd if (l == 0) {
902ffe34450Schristos (void)fprintf(stderr, "\"%s\": No match\n", name);
903e37283e1Slukem return(NULL);
90461f28255Scgd }
90561f28255Scgd if (l == BUFSIZ) {
906ffe34450Schristos (void)fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
907e37283e1Slukem return(NULL);
90861f28255Scgd }
90961f28255Scgd xname[l] = 0;
91061f28255Scgd for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
91161f28255Scgd ;
91261f28255Scgd *++cp = '\0';
91361f28255Scgd return(xname);
91461f28255Scgd }
91561f28255Scgd
91661f28255Scgd /*
91761f28255Scgd * Are any of the characters in the two strings the same?
91861f28255Scgd */
91961f28255Scgd
920e37283e1Slukem int
anyof(char * s1,const char * s2)92158c2151fSperry anyof(char *s1, const char *s2)
92261f28255Scgd {
923e37283e1Slukem int c;
92461f28255Scgd
925c4341bc3Schristos while ((c = *s1++) != '\0')
92661f28255Scgd if (any(c, s2))
92761f28255Scgd return(1);
92861f28255Scgd return(0);
92961f28255Scgd }
930