xref: /csrg-svn/old/cu/cu.c (revision 8788)
1*8788Smckusick static	char *sccsid = "@(#)cu.c	4.7 (Berkeley) 82/10/21";
2*8788Smckusick 
3996Sbill #include <stdio.h>
4996Sbill #include <signal.h>
5996Sbill #include <sgtty.h>
62370Smark 
7996Sbill /*
82370Smark  * defs that come from uucp.h
92370Smark  */
102370Smark #define NAMESIZE 15
112370Smark #define FAIL -1
122370Smark #define SAME 0
132370Smark #define SLCKTIME 5400	/* system/device timeout (LCK.. files) in seconds */
142370Smark #define ASSERT(e, f, v) if (!(e)) {\
152370Smark 	fprintf(stderr, "AERROR - (%s) ", "e");\
162370Smark 	fprintf(stderr, f, v);\
172370Smark 	cleanup(FAIL);\
182370Smark }
192370Smark 
202370Smark /*
21*8788Smckusick  *	cu telno [-t] [-s speed] [-l line] [-a acu] [-p]
22996Sbill  *
23996Sbill  *	-t is for dial-out to terminal.
24*8788Smckusick  *	speeds are: 110, 134, 150, 300, 1200, 2400. 300 is default.
25996Sbill  *
26*8788Smckusick  *	-p says strip parity of characters transmitted.  (to compensate
27*8788Smckusick  *	for c100's)
28*8788Smckusick  *
29996Sbill  *	Escape with `~' at beginning of line.
30996Sbill  *	Ordinary diversions are ~<, ~> and ~>>.
31996Sbill  *	Silent output diversions are ~>: and ~>>:.
32996Sbill  *	Terminate output diversion with ~> alone.
33996Sbill  *	Quit is ~. and ~! gives local command or shell.
34996Sbill  *	Also ~$ for canned procedure pumping remote.
35996Sbill  *	~%put from [to]  and  ~%take from [to] invoke builtins
36996Sbill  */
37996Sbill 
38996Sbill #define CRLF "\r\n"
39996Sbill #define wrc(ds) write(ds,&c,1)
40996Sbill 
41996Sbill 
42996Sbill char	*devcul	= "/dev/cul0";
43996Sbill char	*devcua	= "/dev/cua0";
44996Sbill char	*lspeed	= "300";
45996Sbill 
46996Sbill int	ln;	/* fd for comm line */
47996Sbill char	tkill, terase;	/* current input kill & erase */
48996Sbill int	efk;		/* process of id of listener  */
49996Sbill char	c;
50996Sbill char	oc;
51996Sbill 
52996Sbill char	*connmsg[] = {
53996Sbill 	"",
54996Sbill 	"line busy",
55996Sbill 	"call dropped",
56996Sbill 	"no carrier",
57996Sbill 	"can't fork",
58996Sbill 	"acu access",
59996Sbill 	"tty access",
60996Sbill 	"tty hung",
612370Smark 	"usage: cu telno [-t] [-s speed] [-l line] [-a acu]",
622370Smark 	"lock failed: line busy"
63996Sbill };
64996Sbill 
rdc(ds)65996Sbill rdc(ds) {
66996Sbill 
67996Sbill 	ds=read(ds,&c,1);
68996Sbill 	oc = c;
69996Sbill 	c &= 0177;
70996Sbill 	return (ds);
71996Sbill }
72996Sbill 
73996Sbill int intr;
74996Sbill 
sig2()75996Sbill sig2()
76996Sbill {
77996Sbill 	signal(SIGINT, SIG_IGN);
78996Sbill 	intr = 1;
79996Sbill }
80996Sbill 
81996Sbill int set14;
82996Sbill 
xsleep(n)83996Sbill xsleep(n)
84996Sbill {
85996Sbill 	xalarm(n);
86996Sbill 	pause();
87996Sbill 	xalarm(0);
88996Sbill }
89996Sbill 
xalarm(n)90996Sbill xalarm(n)
91996Sbill {
92996Sbill 	set14=n;
93996Sbill 	alarm(n);
94996Sbill }
95996Sbill 
sig14()96996Sbill sig14()
97996Sbill {
98996Sbill 	signal(SIGALRM, sig14);
99996Sbill 	if (set14) alarm(1);
100996Sbill }
101996Sbill 
102996Sbill int	dout;
103996Sbill int	nhup;
104996Sbill int	dbflag;
105*8788Smckusick int	pflag;		/* strip parity on chars sent to remote */
1062370Smark int	nullbrk;	/* turn breaks (nulls) into dels */
107*8788Smckusick int	pipes[2] = { -1, -1 };
108996Sbill 
109996Sbill /*
110996Sbill  *	main: get connection, set speed for line.
111996Sbill  *	spawn child to invoke rd to read from line, output to fd 1
112996Sbill  *	main line invokes wr to read tty, write to line
113996Sbill  */
main(ac,av)114996Sbill main(ac,av)
115996Sbill char *av[];
116996Sbill {
117996Sbill 	int fk;
118996Sbill 	int speed;
119996Sbill 	char *telno;
120996Sbill 	struct sgttyb stbuf;
1212791Swnj 	int cleanup();
122996Sbill 
123996Sbill 	signal(SIGALRM, sig14);
1242791Swnj 	signal(SIGINT, cleanup);
1252791Swnj 	signal(SIGHUP, cleanup);
1262791Swnj 	signal(SIGQUIT, cleanup);
127996Sbill 	if (ac < 2) {
128996Sbill 		prf(connmsg[8]);
129996Sbill 		exit(8);
130996Sbill 	}
131996Sbill 	for (; ac > 1; av++,ac--) {
132996Sbill 		if (av[1][0] != '-')
133996Sbill 			telno = av[1];
134996Sbill 		else switch(av[1][1]) {
135996Sbill 		case 't':
136996Sbill 			dout = 1;
137996Sbill 			--ac;
138996Sbill 			continue;
1392370Smark 		case 'b':
1402370Smark 			nullbrk++;
1412370Smark 			continue;
142996Sbill 		case 'd':
143996Sbill 			dbflag++;
144996Sbill 			continue;
145*8788Smckusick 		case 'p':
146*8788Smckusick 			pflag++;
147*8788Smckusick 			continue;
148996Sbill 		case 's':
149996Sbill 			lspeed = av[2]; ++av; --ac;
150996Sbill 			break;
151996Sbill 		case 'l':
152996Sbill 			devcul = av[2]; ++av; --ac;
153996Sbill 			break;
154996Sbill 		case 'a':
155996Sbill 			devcua = av[2]; ++av; --ac;
156996Sbill 			break;
157996Sbill 		case '0': case '1': case '2': case '3': case '4':
158996Sbill 		case '5': case '6': case '7': case '8': case '9':
159996Sbill 			devcua[strlen(devcua)-1] = av[1][1];
160996Sbill 			devcul[strlen(devcul)-1] = av[1][1];
161996Sbill 			break;
162996Sbill 		default:
163996Sbill 			prf("Bad flag %s", av[1]);
164996Sbill 			break;
165996Sbill 		}
166996Sbill 	}
167996Sbill 	if (!exists(devcua) || !exists(devcul))
168996Sbill 		exit(9);
169996Sbill 	ln = conn(devcul, devcua, telno);
170996Sbill 	if (ln < 0) {
171996Sbill 		prf("Connect failed: %s",connmsg[-ln]);
1722370Smark 		cleanup(-ln);
173996Sbill 	}
174996Sbill 	switch(atoi(lspeed)) {
175996Sbill 	case 110:
176996Sbill 		speed = B110;break;
177996Sbill 	case 150:
178996Sbill 		speed = B150;break;
179996Sbill 	default:
180996Sbill 	case 300:
181996Sbill 		speed = B300;break;
182996Sbill 	case 1200:
183996Sbill 		speed = B1200;break;
184*8788Smckusick 	case 2400:
185*8788Smckusick 		speed = B2400;break;
186996Sbill 	}
187996Sbill 	stbuf.sg_ispeed = speed;
188996Sbill 	stbuf.sg_ospeed = speed;
189996Sbill 	stbuf.sg_flags = EVENP|ODDP;
190996Sbill 	if (!dout) {
191996Sbill 		stbuf.sg_flags |= RAW;
192996Sbill 		stbuf.sg_flags &= ~ECHO;
193996Sbill 	}
194996Sbill 	ioctl(ln, TIOCSETP, &stbuf);
195996Sbill 	ioctl(ln, TIOCEXCL, (struct sgttyb *)NULL);
196996Sbill 	ioctl(ln, TIOCHPCL, (struct sgttyb *)NULL);
197996Sbill 	prf("Connected");
198*8788Smckusick 	pipe(pipes);
199996Sbill 	if (dout)
2003926Sbugs 		fk = -1;
201996Sbill 	else
202996Sbill 		fk = fork();
203996Sbill 	nhup = (int)signal(SIGINT, SIG_IGN);
204996Sbill 	if (fk == 0) {
205996Sbill 		chwrsig();
206996Sbill 		rd();
207996Sbill 		prf("\007Lost carrier");
2082370Smark 		cleanup(3);
209996Sbill 	}
210996Sbill 	mode(1);
211996Sbill 	efk = fk;
212996Sbill 	wr();
213996Sbill 	mode(0);
2143924Sroot 	if (fk != -1) kill(fk, SIGKILL);
215996Sbill 	wait((int *)NULL);
216996Sbill 	stbuf.sg_ispeed = 0;
217996Sbill 	stbuf.sg_ospeed = 0;
218996Sbill 	ioctl(ln, TIOCSETP, &stbuf);
219996Sbill 	prf("Disconnected");
2202370Smark 	cleanup(0);
221996Sbill }
222996Sbill 
223996Sbill /*
224996Sbill  *	conn: establish dial-out connection.
225996Sbill  *	Example:  fd = conn("/dev/ttyh","/dev/dn1","4500");
226996Sbill  *	Returns descriptor open to tty for reading and writing.
227996Sbill  *	Negative values (-1...-7) denote errors in connmsg.
228996Sbill  *	Uses alarm and fork/wait; requires sig14 handler.
229996Sbill  *	Be sure to disconnect tty when done, via HUPCL or stty 0.
230996Sbill  */
231996Sbill 
conn(dev,acu,telno)232996Sbill conn(dev,acu,telno)
233996Sbill char *dev, *acu, *telno;
234996Sbill {
235996Sbill 	struct sgttyb stbuf;
236996Sbill 	extern errno;
237996Sbill 	char *p, *q, b[30];
2382370Smark 	char *ltail, *atail;
2392370Smark 	char *rindex();
240996Sbill 	int er, fk, dn, dh, t;
241996Sbill 	er=0;
242996Sbill 	fk=(-1);
2432370Smark 	atail = rindex(acu, '/')+1;
2442370Smark 	if (mlock(atail) == FAIL) {
2452370Smark 		er = 9;
2462370Smark 		goto X;
2472370Smark 	}
2482370Smark 	ltail = rindex(dev, '/')+1;
2492370Smark 	if (mlock(ltail) == FAIL) {
2502370Smark 		er = 9;
2512370Smark 		delock(atail);
2522370Smark 		goto X;
2532370Smark 	}
254996Sbill 	if ((dn=open(acu,1))<0) {
255996Sbill 		er=(errno == 6? 1:5);
256996Sbill 		goto X;
257996Sbill 	}
258996Sbill 	if ((fk=fork()) == (-1)) {
259996Sbill 		er=4;
260996Sbill 		goto X;
261996Sbill 	}
262996Sbill 	if (fk == 0) {
263996Sbill 		open(dev,2);
264996Sbill 		for (;;) pause();
265996Sbill 	}
266996Sbill 	xsleep(2);
267996Sbill 	/*
268996Sbill 	 *	copy phone #, assure EON
269996Sbill 	 */
270996Sbill 	p=b;
271996Sbill 	q=telno;
272996Sbill 	while (*p++=(*q++))
273996Sbill 		;
274996Sbill 	p--;
275996Sbill 	if (*(p-1)!='<') {
276996Sbill 		/*if (*(p-1)!='-') *p++='-';*/
277996Sbill 		*p++='<';
278996Sbill 	}
279996Sbill 	t=p-b;
280996Sbill 	xalarm(5*t);
281996Sbill 	t=write(dn,b,t);
282996Sbill 	xalarm(0);
283996Sbill 	if (t<0) {
284996Sbill 		er=2;
285996Sbill 		goto X;
286996Sbill 	}
287996Sbill 	/* close(dn) */
288996Sbill 	xalarm(40);		/* was 5; sometimes missed carrier */
289996Sbill 	dh = open(dev,2);
290996Sbill 	xalarm(0);
291996Sbill 	if (dh<0) {
292996Sbill 		er=(errno == 4? 3:6);
293996Sbill 		goto X;
294996Sbill 	}
2952370Smark 	ioctl(dh, TIOCGETP, &stbuf);
296996Sbill 	stbuf.sg_flags &= ~ECHO;
297996Sbill 	xalarm(10);
298996Sbill 	ioctl(dh, TIOCSETP, &stbuf);
299996Sbill 	ioctl(dh, TIOCHPCL, (struct sgttyb *)NULL);
300996Sbill 	xalarm(0);
301996Sbill X:
302996Sbill 	if (er) close(dn);
3032370Smark 	delock(atail);
304996Sbill 	if (fk!=(-1)) {
305996Sbill 		kill(fk, SIGKILL);
306996Sbill 		xalarm(10);
307996Sbill 		while ((t=wait((int *)NULL))!=(-1) && t!=fk);
308996Sbill 		xalarm(0);
309996Sbill 	}
310996Sbill 	return (er? -er:dh);
311996Sbill }
312996Sbill 
313996Sbill /*
314996Sbill  *	wr: write to remote: 0 -> line.
315996Sbill  *	~.	terminate
316996Sbill  *	~<file	send file
317996Sbill  *	~!	local login-style shell
318996Sbill  *	~!cmd	execute cmd locally
319996Sbill  *	~$proc	execute proc locally, send output to line
320996Sbill  *	~%cmd	execute builtin cmd (put and take)
321996Sbill  *	~#	send 1-sec break
3222370Smark  *	~^Z	suspend cu process.
323996Sbill  */
324996Sbill 
wr()325996Sbill wr()
326996Sbill {
327996Sbill 	int ds,fk,lcl,x;
328996Sbill 	char *p,b[600];
329996Sbill 	for (;;) {
330996Sbill 		p=b;
331996Sbill 		while (rdc(0) == 1) {
332996Sbill 			if (p == b) lcl=(c == '~');
333996Sbill 			if (p == b+1 && b[0] == '~') lcl=(c!='~');
3342370Smark 			if (nullbrk && c == 0) oc=c=0177; /* fake break kludge */
335996Sbill 			if (!lcl) {
336*8788Smckusick 				if(!pflag)c = oc;
337996Sbill 				if (wrc(ln) == 0) {
338996Sbill 					prf("line gone"); return;
339996Sbill 				}
340996Sbill 				c &= 0177;
341996Sbill 			}
342996Sbill 			if (lcl) {
343996Sbill 				if (c == 0177) c=tkill;
344996Sbill 				if (c == '\r' || c == '\n') goto A;
345996Sbill 				if (!dout) wrc(0);
346996Sbill 			}
347996Sbill 			*p++=c;
348996Sbill 			if (c == terase) {
349996Sbill 				p=p-2;
350996Sbill 				if (p<b) p=b;
351996Sbill 			}
352996Sbill 			if (c == tkill || c == 0177 || c == '\4' || c == '\r' || c == '\n') p=b;
353996Sbill 		}
354996Sbill 		return;
355996Sbill A:
356996Sbill 		if (!dout) echo("");
357996Sbill 		*p=0;
358996Sbill 		switch (b[1]) {
359996Sbill 		case '.':
360996Sbill 		case '\004':
361996Sbill 			return;
362996Sbill 		case '#':
363996Sbill 			ioctl(ln, TIOCSBRK, 0);
364996Sbill 			sleep(1);
365996Sbill 			ioctl(ln, TIOCCBRK, 0);
366996Sbill 			continue;
367996Sbill 		case '!':
368996Sbill 		case '$':
369996Sbill 			fk = fork();
370996Sbill 			if (fk == 0) {
371996Sbill 				char *getenv();
372996Sbill 				char *shell = getenv("SHELL");
373996Sbill 				if (shell == 0) shell = "/bin/sh";
374996Sbill 				close(1);
375996Sbill 				dup(b[1] == '$'? ln:2);
376996Sbill 				close(ln);
377996Sbill 				mode(0);
378996Sbill 				if (!nhup) signal(SIGINT, SIG_DFL);
379996Sbill 				if (b[2] == 0) execl(shell,shell,0);
380996Sbill 				/* if (b[2] == 0) execl(shell,"-",0); */
381996Sbill 				else execl(shell,"sh","-c",b+2,0);
382996Sbill 				prf("Can't execute shell");
383996Sbill 				exit(~0);
384996Sbill 			}
385996Sbill 			if (fk!=(-1)) {
386996Sbill 				while (wait(&x)!=fk);
387996Sbill 			}
388996Sbill 			mode(1);
389996Sbill 			if (b[1] == '!') echo("!");
390996Sbill 			else {
391996Sbill 				if (dout) echo("$");
392996Sbill 			}
393996Sbill 			break;
394996Sbill 		case '<':
395996Sbill 			if (b[2] == 0) break;
396996Sbill 			if ((ds=open(b+2,0))<0) {
397996Sbill 				prf("Can't divert %s",b+1);
398996Sbill 				break;
399996Sbill 			}
400996Sbill 			intr=x=0;
401996Sbill 			mode(2);
402996Sbill 			if (!nhup) signal(SIGINT, sig2);
403996Sbill 			while (!intr && rdc(ds) == 1) {
404996Sbill 				if (wrc(ln) == 0) {
405996Sbill 					x=1;
406996Sbill 					break;
407996Sbill 				}
408996Sbill 			}
409996Sbill 			signal(SIGINT, SIG_IGN);
410996Sbill 			close(ds);
411996Sbill 			mode(1);
412996Sbill 			if (x) return;
413996Sbill 			if (dout) echo("<");
414996Sbill 			break;
415996Sbill 		case '>':
416996Sbill 		case ':':
417996Sbill 			{
418*8788Smckusick 			register char *q;
419*8788Smckusick 
420*8788Smckusick 			if(pipes[1]==-1) {
421996Sbill 				prf("Can't tell other demon to divert");
422996Sbill 				break;
423996Sbill 			}
424*8788Smckusick 			q = b+1;
425*8788Smckusick 			if(*q=='>') q++;
426*8788Smckusick 			write(pipes[1],q,strlen(q)+1);
427*8788Smckusick 			if(dbflag) prf("msg to be delivered:"),prf(q);
4283924Sroot 			if (efk != -1) kill(efk,SIGEMT);
429996Sbill 			}
430996Sbill 			break;
431996Sbill #ifdef SIGTSTP
432996Sbill #define CTRLZ	26
433996Sbill 		case CTRLZ:
434996Sbill 			mode(0);
435996Sbill 			kill(getpid(), SIGTSTP);
436996Sbill 			mode(1);
437996Sbill 			break;
438996Sbill #endif
439996Sbill 		case '%':
440996Sbill 			dopercen(&b[2]);
441996Sbill 			break;
442996Sbill 		default:
443996Sbill 			prf("Use `~~' to start line with `~'");
444996Sbill 		}
445996Sbill 		continue;
446996Sbill 	}
447996Sbill }
448996Sbill 
dopercen(line)449996Sbill dopercen(line)
450996Sbill register char *line;
451996Sbill {
452996Sbill 	char *args[10];
453996Sbill 	register narg, f;
454996Sbill 	int rcount;
455996Sbill 	for (narg = 0; narg < 10;) {
456996Sbill 		while(*line == ' ' || *line == '\t')
457996Sbill 			line++;
458996Sbill 		if (*line == '\0')
459996Sbill 			break;
460996Sbill 		args[narg++] = line;
461996Sbill 		while(*line != '\0' && *line != ' ' && *line != '\t')
462996Sbill 			line++;
463996Sbill 		if (*line == '\0')
464996Sbill 			break;
465996Sbill 		*line++ = '\0';
466996Sbill 	}
467996Sbill 	if (equal(args[0], "take")) {
468996Sbill 		if (narg < 2) {
469996Sbill 			prf("usage: ~%%take from [to]");
470996Sbill 			return;
471996Sbill 		}
472996Sbill 		if (narg < 3)
473996Sbill 			args[2] = args[1];
474*8788Smckusick 		write(pipes[1], ">:/dev/null",sizeof(">:/dev/null"));
475*8788Smckusick 		if(dbflag) prf("sending take message");
476*8788Smckusick 		if (efk != -1) kill(efk,SIGEMT);
477*8788Smckusick 		xsleep(5);
478*8788Smckusick 		wrln("echo '~>");
479996Sbill 		wrln(args[2]);
480*8788Smckusick 		wrln("'; tee /dev/null <");
481996Sbill 		wrln(args[1]);
482996Sbill 		wrln(";echo '~>'\n");
483996Sbill 		return;
484996Sbill 	} else if (equal(args[0], "put")) {
485996Sbill 		if (narg < 2) {
486996Sbill 			prf("usage: ~%%put from [to]");
487996Sbill 			return;
488996Sbill 		}
489996Sbill 		if (narg < 3)
490996Sbill 			args[2] = args[1];
491996Sbill 		if ((f = open(args[1], 0)) < 0) {
492996Sbill 			prf("cannot open: %s", args[1]);
493996Sbill 			return;
494996Sbill 		}
495996Sbill 		wrln("stty -echo;cat >");
496996Sbill 		wrln(args[2]);
497996Sbill 		wrln(";stty echo\n");
498996Sbill 		xsleep(5);
499996Sbill 		intr = 0;
500996Sbill 		if (!nhup)
501996Sbill 			signal(SIGINT, sig2);
502996Sbill 		mode(2);
503996Sbill 		rcount = 0;
504996Sbill 		while(!intr && rdc(f) == 1) {
505996Sbill 			rcount++;
506996Sbill 			if (c == tkill || c == terase)
507996Sbill 				wrln("\\");
508996Sbill 			if (wrc(ln) != 1) {
509996Sbill 				xsleep(2);
510996Sbill 				if (wrc(ln) != 1) {
511996Sbill 					prf("character missed");
512996Sbill 					intr = 1;
513996Sbill 					break;
514996Sbill 				}
515996Sbill 			}
516996Sbill 		}
517996Sbill 		signal(SIGINT, SIG_IGN);
518996Sbill 		close(f);
519996Sbill 		if (intr) {
520996Sbill 			wrln("\n");
521996Sbill 			prf("stopped after %d bytes", rcount);
522996Sbill 		}
523996Sbill 		wrln("\004");
524996Sbill 		xsleep(5);
525996Sbill 		mode(1);
526996Sbill 		return;
527996Sbill 	}
528996Sbill 	prf("~%%%s unknown\n", args[0]);
529996Sbill }
530996Sbill 
equal(s1,s2)531996Sbill equal(s1, s2)
532996Sbill register char *s1, *s2;
533996Sbill {
534996Sbill 	while (*s1++ == *s2)
535996Sbill 		if (*s2++ == '\0')
536996Sbill 			return(1);
537996Sbill 	return(0);
538996Sbill }
539996Sbill 
wrln(s)540996Sbill wrln(s)
541996Sbill register char *s;
542996Sbill {
543996Sbill 	while (*s)
544996Sbill 		write(ln, s++, 1);
545996Sbill }
546996Sbill /*	chwrsig:  Catch orders from wr process
547996Sbill  *	to instigate diversion
548996Sbill  */
549996Sbill int whoami;
chwrsig()550996Sbill chwrsig(){
551*8788Smckusick 	int readmsg();
552996Sbill 	whoami = getpid();
553*8788Smckusick 	signal(SIGEMT,readmsg);
554996Sbill }
555*8788Smckusick int ds,slnt,taking;
556996Sbill int justrung;
readmsg()557*8788Smckusick readmsg(){
558*8788Smckusick 	static char dobuff[128], morejunk[256];
559*8788Smckusick 	int n;
560996Sbill 	justrung = 1;
561*8788Smckusick 	signal(SIGEMT,readmsg);
562996Sbill 	if(dbflag) {
563*8788Smckusick 		prf("About to read from pipe");
564996Sbill 	}
565*8788Smckusick 	n = read(pipes[0],morejunk,256);
566996Sbill 	if(dbflag) {
567*8788Smckusick 		prf("diversion mesg recieved is");
568*8788Smckusick 		prf(morejunk);
569*8788Smckusick 		prf(CRLF);
570996Sbill 	}
571*8788Smckusick 	dodiver(morejunk);
572*8788Smckusick }
dodiver(msg)573*8788Smckusick dodiver(msg)
574*8788Smckusick char *msg;
575*8788Smckusick {
576*8788Smckusick 	register char *cp = msg;
577*8788Smckusick 
578996Sbill 	if (*cp=='>') cp++;
579996Sbill 	if (*cp==':') {
580996Sbill 		cp++;
581996Sbill 		if(*cp==0) {
582996Sbill 			slnt ^= 1;
583996Sbill 			return;
584996Sbill 		} else  {
585996Sbill 			slnt = 1;
586996Sbill 		}
587996Sbill 	}
588996Sbill 	if (ds >= 0) close(ds);
589996Sbill 	if (*cp==0) {
590996Sbill 		slnt = 0;
591996Sbill 		ds = -1;
592996Sbill 		return;
593996Sbill 	}
594*8788Smckusick 	if (*msg!='>' || (ds=open(cp,1))<0) ds=creat(cp,0644);
595996Sbill 	lseek(ds, (long)0, 2);
596996Sbill 	if(ds < 0) prf("Creat failed:"), prf(cp);
597996Sbill 	if (ds<0) prf("Can't divert %s",cp+1);
598996Sbill }
599996Sbill 
600996Sbill 
601996Sbill /*
602996Sbill  *	rd: read from remote: line -> 1
603*8788Smckusick  *	catch: diversion caught by interrupt routine
604996Sbill  */
605996Sbill 
606*8788Smckusick #define ORDIN 0
607*8788Smckusick #define SAWCR 1
608*8788Smckusick #define EOL   2
609*8788Smckusick #define SAWTL 3
610*8788Smckusick #define DIVER 4
611*8788Smckusick 
rd()612996Sbill rd()
613996Sbill {
614996Sbill 	extern int ds,slnt;
615*8788Smckusick 	char rb[600], lb[600], *rlim, *llim, c;
616*8788Smckusick 	register char *p,*q;
617*8788Smckusick 	int cnt, state = 0, mustecho, oldslnt;
618*8788Smckusick 
619996Sbill 	ds=(-1);
620*8788Smckusick 	p = lb; llim = lb+600;
621996Sbill agin:
622*8788Smckusick 	while((cnt = read(ln,rb,600)) > 0) {
623*8788Smckusick 		if(!slnt) write(1,rb,cnt);
624*8788Smckusick 		if(ds < 0) continue;
625*8788Smckusick 		oldslnt = slnt;
626*8788Smckusick 		for( q=rb, rlim = rb + cnt - 1; q <= rlim; ) {
627*8788Smckusick 			c = *q++ & 0177;
628*8788Smckusick 			if(p < llim) *p++ = c;
629*8788Smckusick 			switch(state) {
630*8788Smckusick 			case ORDIN:
631*8788Smckusick 				if(c=='\r') state = SAWCR;
632*8788Smckusick 				break;
633*8788Smckusick 			case SAWCR:
634*8788Smckusick 				if(c=='\n') {
635*8788Smckusick 					state = EOL;
636*8788Smckusick 					p--;
637*8788Smckusick 					p[-1] = '\n';
638*8788Smckusick 				} else state = ORDIN;
639*8788Smckusick 				break;
640*8788Smckusick 			case EOL:
641*8788Smckusick 				state = (c=='~' ? SAWTL :
642*8788Smckusick 					 (c=='\r' ? SAWCR : ORDIN));
643*8788Smckusick 				break;
644*8788Smckusick 			case SAWTL:
645*8788Smckusick 				state = (c=='>' ? DIVER :
646*8788Smckusick 					 (c=='\r' ? SAWCR : ORDIN));
647*8788Smckusick 				break;
648*8788Smckusick 			case DIVER:
649*8788Smckusick 				if(c=='\r') {
650*8788Smckusick 					p--;
651*8788Smckusick 				} else if (c=='\n') {
652*8788Smckusick 					state = ORDIN;
653*8788Smckusick 					p[-1] = 0;
654*8788Smckusick 					dodiver(lb+2);
655*8788Smckusick 					c = 0; p = lb;
656*8788Smckusick 				}
657996Sbill 			}
658*8788Smckusick 			if(slnt==0 && oldslnt) {
659*8788Smckusick 				if(c=='\n') {
660*8788Smckusick 					write(ln,lb,p-lb-1);
661*8788Smckusick 					write(ln,CRLF,sizeof(CRLF));
662*8788Smckusick 				} else if(q==rlim) {
663*8788Smckusick 					write(ln,lb,p-lb);
664*8788Smckusick 					c = '\n';  /*force flush to file*/
665*8788Smckusick 				}
666*8788Smckusick 			}
667*8788Smckusick 			if(c=='\n') {
668*8788Smckusick 				if(ds >= 0)
669*8788Smckusick 					write(ds,lb,p-lb);
670*8788Smckusick 				p = lb;
671*8788Smckusick 			}
672996Sbill 		}
673996Sbill 	}
674996Sbill 	if(justrung) {
675996Sbill 		justrung = 0;
676996Sbill 		goto agin;
677996Sbill 	}
678996Sbill }
679996Sbill 
680996Sbill struct {char lobyte; char hibyte;};
mode(f)681996Sbill mode(f)
682996Sbill {
683996Sbill 	struct sgttyb stbuf;
684996Sbill 	if (dout) return;
685996Sbill 	ioctl(0, TIOCGETP, &stbuf);
686996Sbill 	tkill = stbuf.sg_kill;
687996Sbill 	terase = stbuf.sg_erase;
688996Sbill 	if (f == 0) {
689996Sbill 		stbuf.sg_flags &= ~RAW;
690996Sbill 		stbuf.sg_flags |= ECHO|CRMOD;
691996Sbill 	}
692996Sbill 	if (f == 1) {
693996Sbill 		stbuf.sg_flags |= RAW;
694996Sbill 		stbuf.sg_flags &= ~(ECHO|CRMOD);
695996Sbill 	}
696996Sbill 	if (f == 2) {
697996Sbill 		stbuf.sg_flags &= ~RAW;
698996Sbill 		stbuf.sg_flags &= ~(ECHO|CRMOD);
699996Sbill 	}
700996Sbill 	ioctl(0, TIOCSETP, &stbuf);
701996Sbill }
702996Sbill 
echo(s)703996Sbill echo(s)
704996Sbill char *s;
705996Sbill {
706996Sbill 	char *p;
707996Sbill 	for (p=s;*p;p++);
708996Sbill 	if (p>s) write(0,s,p-s);
709996Sbill 	write(0,CRLF, sizeof(CRLF));
710996Sbill }
711996Sbill 
prf(f,s)712996Sbill prf(f, s)
713996Sbill char *f;
714996Sbill char *s;
715996Sbill {
716996Sbill 	fprintf(stderr, f, s);
717996Sbill 	fprintf(stderr, CRLF);
718996Sbill }
719996Sbill 
exists(devname)720996Sbill exists(devname)
721996Sbill char *devname;
722996Sbill {
723996Sbill 	if (access(devname, 0)==0)
724996Sbill 		return(1);
725996Sbill 	prf("%s does not exist", devname);
726996Sbill 	return(0);
727996Sbill }
7282370Smark 
cleanup(code)7292370Smark cleanup(code)
7302370Smark {
7312370Smark 	rmlock(NULL);
7322370Smark 	exit(code);
7332370Smark }
7342370Smark 
7352370Smark /*
7362370Smark  * This code is taken directly from uucp and follows the same
7372370Smark  * conventions.  This is important since uucp and cu should
7382370Smark  * respect each others locks.
7392370Smark  */
7402370Smark 
7412370Smark 	/*  ulockf 3.2  10/26/79  11:40:29  */
7422370Smark /* #include "uucp.h" */
7432370Smark #include <sys/types.h>
7442370Smark #include <sys/stat.h>
7452370Smark 
7462370Smark 
7472370Smark 
7482370Smark /*******
7492370Smark  *	ulockf(file, atime)
7502370Smark  *	char *file;
7512370Smark  *	time_t atime;
7522370Smark  *
7532370Smark  *	ulockf  -  this routine will create a lock file (file).
7542370Smark  *	If one already exists, the create time is checked for
7552370Smark  *	older than the age time (atime).
7562370Smark  *	If it is older, an attempt will be made to unlink it
7572370Smark  *	and create a new one.
7582370Smark  *
7592370Smark  *	return codes:  0  |  FAIL
7602370Smark  */
7612370Smark 
ulockf(file,atime)7622370Smark ulockf(file, atime)
7632370Smark char *file;
7642370Smark time_t atime;
7652370Smark {
7662370Smark 	struct stat stbuf;
7672370Smark 	time_t ptime;
7682370Smark 	int ret;
7692370Smark 	static int pid = -1;
7702370Smark 	static char tempfile[NAMESIZE];
7712370Smark 
7722370Smark 	if (pid < 0) {
7732370Smark 		pid = getpid();
7742370Smark 		sprintf(tempfile, "/usr/spool/uucp/LTMP.%d", pid);
7752370Smark 	}
7762370Smark 	if (onelock(pid, tempfile, file) == -1) {
7772370Smark 		/* lock file exists */
7782370Smark 		/* get status to check age of the lock file */
7792370Smark 		ret = stat(file, &stbuf);
7802370Smark 		if (ret != -1) {
7812370Smark 			time(&ptime);
7822370Smark 			if ((ptime - stbuf.st_ctime) < atime) {
7832370Smark 				/* file not old enough to delete */
7842370Smark 				return(FAIL);
7852370Smark 			}
7862370Smark 		}
7872370Smark 		ret = unlink(file);
7882370Smark 		ret = onelock(pid, tempfile, file);
7892370Smark 		if (ret != 0)
7902370Smark 			return(FAIL);
7912370Smark 	}
7922370Smark 	stlock(file);
7932370Smark 	return(0);
7942370Smark }
7952370Smark 
7962370Smark 
7972370Smark #define MAXLOCKS 10	/* maximum number of lock files */
7982370Smark char *Lockfile[MAXLOCKS];
7992370Smark int Nlocks = 0;
8002370Smark 
8012370Smark /***
8022370Smark  *	stlock(name)	put name in list of lock files
8032370Smark  *	char *name;
8042370Smark  *
8052370Smark  *	return codes:  none
8062370Smark  */
8072370Smark 
stlock(name)8082370Smark stlock(name)
8092370Smark char *name;
8102370Smark {
8112370Smark 	char *p;
8122370Smark 	extern char *calloc();
8132370Smark 	int i;
8142370Smark 
8152370Smark 	for (i = 0; i < Nlocks; i++) {
8162370Smark 		if (Lockfile[i] == NULL)
8172370Smark 			break;
8182370Smark 	}
8192370Smark 	ASSERT(i < MAXLOCKS, "TOO MANY LOCKS %d", i);
8202370Smark 	if (i >= Nlocks)
8212370Smark 		i = Nlocks++;
8222370Smark 	p = calloc(strlen(name) + 1, sizeof (char));
8232370Smark 	ASSERT(p != NULL, "CAN NOT ALLOCATE FOR %s", name);
8242370Smark 	strcpy(p, name);
8252370Smark 	Lockfile[i] = p;
8262370Smark 	return;
8272370Smark }
8282370Smark 
8292370Smark 
8302370Smark /***
8312370Smark  *	rmlock(name)	remove all lock files in list
8322370Smark  *	char *name;	or name
8332370Smark  *
8342370Smark  *	return codes: none
8352370Smark  */
8362370Smark 
rmlock(name)8372370Smark rmlock(name)
8382370Smark char *name;
8392370Smark {
8402370Smark 	int i;
8412370Smark 
8422370Smark 	for (i = 0; i < Nlocks; i++) {
8432370Smark 		if (Lockfile[i] == NULL)
8442370Smark 			continue;
8452370Smark 		if (name == NULL
8462370Smark 		|| strcmp(name, Lockfile[i]) == SAME) {
8472370Smark 			unlink(Lockfile[i]);
8482370Smark 			free(Lockfile[i]);
8492370Smark 			Lockfile[i] = NULL;
8502370Smark 		}
8512370Smark 	}
8522370Smark 	return;
8532370Smark }
8542370Smark 
8552370Smark 
8562370Smark /*  this stuff from pjw  */
8572370Smark /*  /usr/pjw/bin/recover - check pids to remove unnecessary locks */
8582370Smark /*	isalock(name) returns 0 if the name is a lock */
8592370Smark /*	unlock(name)  unlocks name if it is a lock*/
8602370Smark /*	onelock(pid,tempfile,name) makes lock a name
8612370Smark 	on behalf of pid.  Tempfile must be in the same
8622370Smark 	file system as name. */
8632370Smark /*	lock(pid,tempfile,names) either locks all the
8642370Smark 	names or none of them */
isalock(name)8652370Smark isalock(name) char *name;
8662370Smark {
8672370Smark 	struct stat xstat;
8682370Smark 	if(stat(name,&xstat)<0) return(0);
8692370Smark 	if(xstat.st_size!=sizeof(int)) return(0);
8702370Smark 	return(1);
8712370Smark }
unlock(name)8722370Smark unlock(name) char *name;
8732370Smark {
8742370Smark 	if(isalock(name)) return(unlink(name));
8752370Smark 	else return(-1);
8762370Smark }
onelock(pid,tempfile,name)8772370Smark onelock(pid,tempfile,name) char *tempfile,*name;
8782370Smark {	int fd;
8792370Smark 	fd=creat(tempfile,0444);
8802370Smark 	if(fd<0) return(-1);
8812370Smark 	write(fd,(char *) &pid,sizeof(int));
8822370Smark 	close(fd);
8832370Smark 	if(link(tempfile,name)<0)
8842370Smark 	{	unlink(tempfile);
8852370Smark 		return(-1);
8862370Smark 	}
8872370Smark 	unlink(tempfile);
8882370Smark 	return(0);
8892370Smark }
lock(pid,tempfile,names)8902370Smark lock(pid,tempfile,names) char *tempfile,**names;
8912370Smark {	int i,j;
8922370Smark 	for(i=0;names[i]!=0;i++)
8932370Smark 	{	if(onelock(pid,tempfile,names[i])==0) continue;
8942370Smark 		for(j=0;j<i;j++) unlink(names[j]);
8952370Smark 		return(-1);
8962370Smark 	}
8972370Smark 	return(0);
8982370Smark }
8992370Smark 
9002370Smark #define LOCKPRE "/usr/spool/uucp/LCK."
9012370Smark 
9022370Smark /***
9032370Smark  *	delock(s)	remove a lock file
9042370Smark  *	char *s;
9052370Smark  *
9062370Smark  *	return codes:  0  |  FAIL
9072370Smark  */
9082370Smark 
delock(s)9092370Smark delock(s)
9102370Smark char *s;
9112370Smark {
9122370Smark 	char ln[30];
9132370Smark 
9142370Smark 	sprintf(ln, "%s.%s", LOCKPRE, s);
9152370Smark 	rmlock(ln);
9162370Smark }
9172370Smark 
9182370Smark 
9192370Smark /***
9202370Smark  *	mlock(sys)	create system lock
9212370Smark  *	char *sys;
9222370Smark  *
9232370Smark  *	return codes:  0  |  FAIL
9242370Smark  */
9252370Smark 
mlock(sys)9262370Smark mlock(sys)
9272370Smark char *sys;
9282370Smark {
9292370Smark 	char lname[30];
9302370Smark 	sprintf(lname, "%s.%s", LOCKPRE, sys);
9312370Smark 	return(ulockf(lname, (time_t) SLCKTIME ) < 0 ? FAIL : 0);
9322370Smark }
9332370Smark 
9342370Smark 
9352370Smark 
9362370Smark /***
9372370Smark  *	ultouch()	update access and modify times for lock files
9382370Smark  *
9392370Smark  *	return code - none
9402370Smark  */
9412370Smark 
ultouch()9422370Smark ultouch()
9432370Smark {
9442370Smark 	time_t time();
9452370Smark 	int i;
9462370Smark 	struct ut {
9472370Smark 		time_t actime;
9482370Smark 		time_t modtime;
9492370Smark 	} ut;
9502370Smark 
9512370Smark 	ut.actime = time(&ut.modtime);
9522370Smark 	for (i = 0; i < Nlocks; i++) {
9532370Smark 		if (Lockfile[i] == NULL)
9542370Smark 			continue;
9552370Smark 		utime(Lockfile[i], &ut);
9562370Smark 	}
9572370Smark 	return;
9582370Smark }
959