xref: /csrg-svn/old/cu/cu.c (revision 2370)
1*2370Smark static char *sccsid = "@(#)cu.c	4.2 (Berkeley) 02/07/81";
2996Sbill #include <stdio.h>
3996Sbill #include <signal.h>
4996Sbill #include <sgtty.h>
5*2370Smark 
6996Sbill /*
7*2370Smark  * defs that come from uucp.h
8*2370Smark  */
9*2370Smark #define NAMESIZE 15
10*2370Smark #define FAIL -1
11*2370Smark #define SAME 0
12*2370Smark #define SLCKTIME 5400	/* system/device timeout (LCK.. files) in seconds */
13*2370Smark #define ASSERT(e, f, v) if (!(e)) {\
14*2370Smark 	fprintf(stderr, "AERROR - (%s) ", "e");\
15*2370Smark 	fprintf(stderr, f, v);\
16*2370Smark 	cleanup(FAIL);\
17*2370Smark }
18*2370Smark 
19*2370Smark /*
20996Sbill  *	cu telno [-t] [-s speed] [-l line] [-a acu]
21996Sbill  *
22996Sbill  *	-t is for dial-out to terminal.
23996Sbill  *	speeds are: 110, 134, 150, 300, 1200. 300 is default.
24996Sbill  *
25996Sbill  *	Escape with `~' at beginning of line.
26996Sbill  *	Ordinary diversions are ~<, ~> and ~>>.
27996Sbill  *	Silent output diversions are ~>: and ~>>:.
28996Sbill  *	Terminate output diversion with ~> alone.
29996Sbill  *	Quit is ~. and ~! gives local command or shell.
30996Sbill  *	Also ~$ for canned procedure pumping remote.
31996Sbill  *	~%put from [to]  and  ~%take from [to] invoke builtins
32996Sbill  */
33996Sbill 
34996Sbill #define CRLF "\r\n"
35996Sbill #define wrc(ds) write(ds,&c,1)
36996Sbill 
37996Sbill 
38996Sbill char	*devcul	= "/dev/cul0";
39996Sbill char	*devcua	= "/dev/cua0";
40996Sbill char	*lspeed	= "300";
41996Sbill 
42996Sbill int	ln;	/* fd for comm line */
43996Sbill char	tkill, terase;	/* current input kill & erase */
44996Sbill int	efk;		/* process of id of listener  */
45996Sbill char	c;
46996Sbill char	oc;
47996Sbill 
48996Sbill char	*connmsg[] = {
49996Sbill 	"",
50996Sbill 	"line busy",
51996Sbill 	"call dropped",
52996Sbill 	"no carrier",
53996Sbill 	"can't fork",
54996Sbill 	"acu access",
55996Sbill 	"tty access",
56996Sbill 	"tty hung",
57*2370Smark 	"usage: cu telno [-t] [-s speed] [-l line] [-a acu]",
58*2370Smark 	"lock failed: line busy"
59996Sbill };
60996Sbill 
61996Sbill rdc(ds) {
62996Sbill 
63996Sbill 	ds=read(ds,&c,1);
64996Sbill 	oc = c;
65996Sbill 	c &= 0177;
66996Sbill 	return (ds);
67996Sbill }
68996Sbill 
69996Sbill int intr;
70996Sbill 
71996Sbill sig2()
72996Sbill {
73996Sbill 	signal(SIGINT, SIG_IGN);
74996Sbill 	intr = 1;
75996Sbill }
76996Sbill 
77996Sbill int set14;
78996Sbill 
79996Sbill xsleep(n)
80996Sbill {
81996Sbill 	xalarm(n);
82996Sbill 	pause();
83996Sbill 	xalarm(0);
84996Sbill }
85996Sbill 
86996Sbill xalarm(n)
87996Sbill {
88996Sbill 	set14=n;
89996Sbill 	alarm(n);
90996Sbill }
91996Sbill 
92996Sbill sig14()
93996Sbill {
94996Sbill 	signal(SIGALRM, sig14);
95996Sbill 	if (set14) alarm(1);
96996Sbill }
97996Sbill 
98996Sbill int	dout;
99996Sbill int	nhup;
100996Sbill int	dbflag;
101*2370Smark int	nullbrk;	/* turn breaks (nulls) into dels */
102996Sbill 
103996Sbill /*
104996Sbill  *	main: get connection, set speed for line.
105996Sbill  *	spawn child to invoke rd to read from line, output to fd 1
106996Sbill  *	main line invokes wr to read tty, write to line
107996Sbill  */
108996Sbill main(ac,av)
109996Sbill char *av[];
110996Sbill {
111996Sbill 	int fk;
112996Sbill 	int speed;
113996Sbill 	char *telno;
114996Sbill 	struct sgttyb stbuf;
115996Sbill 
116996Sbill 	signal(SIGALRM, sig14);
117996Sbill 	if (ac < 2) {
118996Sbill 		prf(connmsg[8]);
119996Sbill 		exit(8);
120996Sbill 	}
121996Sbill 	for (; ac > 1; av++,ac--) {
122996Sbill 		if (av[1][0] != '-')
123996Sbill 			telno = av[1];
124996Sbill 		else switch(av[1][1]) {
125996Sbill 		case 't':
126996Sbill 			dout = 1;
127996Sbill 			--ac;
128996Sbill 			continue;
129*2370Smark 		case 'b':
130*2370Smark 			nullbrk++;
131*2370Smark 			continue;
132996Sbill 		case 'd':
133996Sbill 			dbflag++;
134996Sbill 			continue;
135996Sbill 		case 's':
136996Sbill 			lspeed = av[2]; ++av; --ac;
137996Sbill 			break;
138996Sbill 		case 'l':
139996Sbill 			devcul = av[2]; ++av; --ac;
140996Sbill 			break;
141996Sbill 		case 'a':
142996Sbill 			devcua = av[2]; ++av; --ac;
143996Sbill 			break;
144996Sbill 		case '0': case '1': case '2': case '3': case '4':
145996Sbill 		case '5': case '6': case '7': case '8': case '9':
146996Sbill 			devcua[strlen(devcua)-1] = av[1][1];
147996Sbill 			devcul[strlen(devcul)-1] = av[1][1];
148996Sbill 			break;
149996Sbill 		default:
150996Sbill 			prf("Bad flag %s", av[1]);
151996Sbill 			break;
152996Sbill 		}
153996Sbill 	}
154996Sbill 	if (!exists(devcua) || !exists(devcul))
155996Sbill 		exit(9);
156996Sbill 	ln = conn(devcul, devcua, telno);
157996Sbill 	if (ln < 0) {
158996Sbill 		prf("Connect failed: %s",connmsg[-ln]);
159*2370Smark 		cleanup(-ln);
160996Sbill 	}
161996Sbill 	switch(atoi(lspeed)) {
162996Sbill 	case 110:
163996Sbill 		speed = B110;break;
164996Sbill 	case 150:
165996Sbill 		speed = B150;break;
166996Sbill 	default:
167996Sbill 	case 300:
168996Sbill 		speed = B300;break;
169996Sbill 	case 1200:
170996Sbill 		speed = B1200;break;
171996Sbill 	}
172996Sbill 	stbuf.sg_ispeed = speed;
173996Sbill 	stbuf.sg_ospeed = speed;
174996Sbill 	stbuf.sg_flags = EVENP|ODDP;
175996Sbill 	if (!dout) {
176996Sbill 		stbuf.sg_flags |= RAW;
177996Sbill 		stbuf.sg_flags &= ~ECHO;
178996Sbill 	}
179996Sbill 	ioctl(ln, TIOCSETP, &stbuf);
180996Sbill 	ioctl(ln, TIOCEXCL, (struct sgttyb *)NULL);
181996Sbill 	ioctl(ln, TIOCHPCL, (struct sgttyb *)NULL);
182996Sbill 	prf("Connected");
183996Sbill 	if (dout)
184996Sbill 		fk = -1;
185996Sbill 	else
186996Sbill 		fk = fork();
187996Sbill 	nhup = (int)signal(SIGINT, SIG_IGN);
188996Sbill 	if (fk == 0) {
189996Sbill 		chwrsig();
190996Sbill 		rd();
191996Sbill 		prf("\007Lost carrier");
192*2370Smark 		cleanup(3);
193996Sbill 	}
194996Sbill 	mode(1);
195996Sbill 	efk = fk;
196996Sbill 	wr();
197996Sbill 	mode(0);
198996Sbill 	kill(fk, SIGKILL);
199996Sbill 	wait((int *)NULL);
200996Sbill 	stbuf.sg_ispeed = 0;
201996Sbill 	stbuf.sg_ospeed = 0;
202996Sbill 	ioctl(ln, TIOCSETP, &stbuf);
203996Sbill 	prf("Disconnected");
204*2370Smark 	cleanup(0);
205996Sbill }
206996Sbill 
207996Sbill /*
208996Sbill  *	conn: establish dial-out connection.
209996Sbill  *	Example:  fd = conn("/dev/ttyh","/dev/dn1","4500");
210996Sbill  *	Returns descriptor open to tty for reading and writing.
211996Sbill  *	Negative values (-1...-7) denote errors in connmsg.
212996Sbill  *	Uses alarm and fork/wait; requires sig14 handler.
213996Sbill  *	Be sure to disconnect tty when done, via HUPCL or stty 0.
214996Sbill  */
215996Sbill 
216996Sbill conn(dev,acu,telno)
217996Sbill char *dev, *acu, *telno;
218996Sbill {
219996Sbill 	struct sgttyb stbuf;
220996Sbill 	extern errno;
221996Sbill 	char *p, *q, b[30];
222*2370Smark 	char *ltail, *atail;
223*2370Smark 	char *rindex();
224996Sbill 	int er, fk, dn, dh, t;
225996Sbill 	er=0;
226996Sbill 	fk=(-1);
227*2370Smark 	atail = rindex(acu, '/')+1;
228*2370Smark 	if (mlock(atail) == FAIL) {
229*2370Smark 		er = 9;
230*2370Smark 		goto X;
231*2370Smark 	}
232*2370Smark 	ltail = rindex(dev, '/')+1;
233*2370Smark 	if (mlock(ltail) == FAIL) {
234*2370Smark 		er = 9;
235*2370Smark 		delock(atail);
236*2370Smark 		goto X;
237*2370Smark 	}
238996Sbill 	if ((dn=open(acu,1))<0) {
239996Sbill 		er=(errno == 6? 1:5);
240996Sbill 		goto X;
241996Sbill 	}
242996Sbill 	if ((fk=fork()) == (-1)) {
243996Sbill 		er=4;
244996Sbill 		goto X;
245996Sbill 	}
246996Sbill 	if (fk == 0) {
247996Sbill 		open(dev,2);
248996Sbill 		for (;;) pause();
249996Sbill 	}
250996Sbill 	xsleep(2);
251996Sbill 	/*
252996Sbill 	 *	copy phone #, assure EON
253996Sbill 	 */
254996Sbill 	p=b;
255996Sbill 	q=telno;
256996Sbill 	while (*p++=(*q++))
257996Sbill 		;
258996Sbill 	p--;
259996Sbill 	if (*(p-1)!='<') {
260996Sbill 		/*if (*(p-1)!='-') *p++='-';*/
261996Sbill 		*p++='<';
262996Sbill 	}
263996Sbill 	t=p-b;
264996Sbill 	xalarm(5*t);
265996Sbill 	t=write(dn,b,t);
266996Sbill 	xalarm(0);
267996Sbill 	if (t<0) {
268996Sbill 		er=2;
269996Sbill 		goto X;
270996Sbill 	}
271996Sbill 	/* close(dn) */
272996Sbill 	xalarm(40);		/* was 5; sometimes missed carrier */
273996Sbill 	dh = open(dev,2);
274996Sbill 	xalarm(0);
275996Sbill 	if (dh<0) {
276996Sbill 		er=(errno == 4? 3:6);
277996Sbill 		goto X;
278996Sbill 	}
279*2370Smark 	ioctl(dh, TIOCGETP, &stbuf);
280996Sbill 	stbuf.sg_flags &= ~ECHO;
281996Sbill 	xalarm(10);
282996Sbill 	ioctl(dh, TIOCSETP, &stbuf);
283996Sbill 	ioctl(dh, TIOCHPCL, (struct sgttyb *)NULL);
284996Sbill 	xalarm(0);
285996Sbill X:
286996Sbill 	if (er) close(dn);
287*2370Smark 	delock(atail);
288996Sbill 	if (fk!=(-1)) {
289996Sbill 		kill(fk, SIGKILL);
290996Sbill 		xalarm(10);
291996Sbill 		while ((t=wait((int *)NULL))!=(-1) && t!=fk);
292996Sbill 		xalarm(0);
293996Sbill 	}
294996Sbill 	return (er? -er:dh);
295996Sbill }
296996Sbill 
297996Sbill /*
298996Sbill  *	wr: write to remote: 0 -> line.
299996Sbill  *	~.	terminate
300996Sbill  *	~<file	send file
301996Sbill  *	~!	local login-style shell
302996Sbill  *	~!cmd	execute cmd locally
303996Sbill  *	~$proc	execute proc locally, send output to line
304996Sbill  *	~%cmd	execute builtin cmd (put and take)
305996Sbill  *	~#	send 1-sec break
306*2370Smark  *	~^Z	suspend cu process.
307996Sbill  */
308996Sbill 
309996Sbill wr()
310996Sbill {
311996Sbill 	int ds,fk,lcl,x;
312996Sbill 	char *p,b[600];
313996Sbill 	for (;;) {
314996Sbill 		p=b;
315996Sbill 		while (rdc(0) == 1) {
316996Sbill 			if (p == b) lcl=(c == '~');
317996Sbill 			if (p == b+1 && b[0] == '~') lcl=(c!='~');
318*2370Smark 			if (nullbrk && c == 0) oc=c=0177; /* fake break kludge */
319996Sbill 			if (!lcl) {
320996Sbill 				c = oc;
321996Sbill 				if (wrc(ln) == 0) {
322996Sbill 					prf("line gone"); return;
323996Sbill 				}
324996Sbill 				c &= 0177;
325996Sbill 			}
326996Sbill 			if (lcl) {
327996Sbill 				if (c == 0177) c=tkill;
328996Sbill 				if (c == '\r' || c == '\n') goto A;
329996Sbill 				if (!dout) wrc(0);
330996Sbill 			}
331996Sbill 			*p++=c;
332996Sbill 			if (c == terase) {
333996Sbill 				p=p-2;
334996Sbill 				if (p<b) p=b;
335996Sbill 			}
336996Sbill 			if (c == tkill || c == 0177 || c == '\4' || c == '\r' || c == '\n') p=b;
337996Sbill 		}
338996Sbill 		return;
339996Sbill A:
340996Sbill 		if (!dout) echo("");
341996Sbill 		*p=0;
342996Sbill 		switch (b[1]) {
343996Sbill 		case '.':
344996Sbill 		case '\004':
345996Sbill 			return;
346996Sbill 		case '#':
347996Sbill 			ioctl(ln, TIOCSBRK, 0);
348996Sbill 			sleep(1);
349996Sbill 			ioctl(ln, TIOCCBRK, 0);
350996Sbill 			continue;
351996Sbill 		case '!':
352996Sbill 		case '$':
353996Sbill 			fk = fork();
354996Sbill 			if (fk == 0) {
355996Sbill 				char *getenv();
356996Sbill 				char *shell = getenv("SHELL");
357996Sbill 				if (shell == 0) shell = "/bin/sh";
358996Sbill 				close(1);
359996Sbill 				dup(b[1] == '$'? ln:2);
360996Sbill 				close(ln);
361996Sbill 				mode(0);
362996Sbill 				if (!nhup) signal(SIGINT, SIG_DFL);
363996Sbill 				if (b[2] == 0) execl(shell,shell,0);
364996Sbill 				/* if (b[2] == 0) execl(shell,"-",0); */
365996Sbill 				else execl(shell,"sh","-c",b+2,0);
366996Sbill 				prf("Can't execute shell");
367996Sbill 				exit(~0);
368996Sbill 			}
369996Sbill 			if (fk!=(-1)) {
370996Sbill 				while (wait(&x)!=fk);
371996Sbill 			}
372996Sbill 			mode(1);
373996Sbill 			if (b[1] == '!') echo("!");
374996Sbill 			else {
375996Sbill 				if (dout) echo("$");
376996Sbill 			}
377996Sbill 			break;
378996Sbill 		case '<':
379996Sbill 			if (b[2] == 0) break;
380996Sbill 			if ((ds=open(b+2,0))<0) {
381996Sbill 				prf("Can't divert %s",b+1);
382996Sbill 				break;
383996Sbill 			}
384996Sbill 			intr=x=0;
385996Sbill 			mode(2);
386996Sbill 			if (!nhup) signal(SIGINT, sig2);
387996Sbill 			while (!intr && rdc(ds) == 1) {
388996Sbill 				if (wrc(ln) == 0) {
389996Sbill 					x=1;
390996Sbill 					break;
391996Sbill 				}
392996Sbill 			}
393996Sbill 			signal(SIGINT, SIG_IGN);
394996Sbill 			close(ds);
395996Sbill 			mode(1);
396996Sbill 			if (x) return;
397996Sbill 			if (dout) echo("<");
398996Sbill 			break;
399996Sbill 		case '>':
400996Sbill 		case ':':
401996Sbill 			{
402996Sbill 			FILE *fp; char tbuff[128]; register char *q;
403996Sbill 			sprintf(tbuff,"/tmp/cu%d",efk);
404996Sbill 			if(NULL==(fp = fopen(tbuff,"w"))) {
405996Sbill 				prf("Can't tell other demon to divert");
406996Sbill 				break;
407996Sbill 			}
408996Sbill 			fprintf(fp,"%s\n",(b[1]=='>'?&b[2]: &b[1] ));
409996Sbill 			if(dbflag) prf("name to be written in temporary:"),prf(&b[2]);
410996Sbill 			fclose(fp);
411996Sbill 			kill(efk,SIGEMT);
412996Sbill 			}
413996Sbill 			break;
414996Sbill #ifdef SIGTSTP
415996Sbill #define CTRLZ	26
416996Sbill 		case CTRLZ:
417996Sbill 			mode(0);
418996Sbill 			kill(getpid(), SIGTSTP);
419996Sbill 			mode(1);
420996Sbill 			break;
421996Sbill #endif
422996Sbill 		case '%':
423996Sbill 			dopercen(&b[2]);
424996Sbill 			break;
425996Sbill 		default:
426996Sbill 			prf("Use `~~' to start line with `~'");
427996Sbill 		}
428996Sbill 		continue;
429996Sbill 	}
430996Sbill }
431996Sbill 
432996Sbill dopercen(line)
433996Sbill register char *line;
434996Sbill {
435996Sbill 	char *args[10];
436996Sbill 	register narg, f;
437996Sbill 	int rcount;
438996Sbill 	for (narg = 0; narg < 10;) {
439996Sbill 		while(*line == ' ' || *line == '\t')
440996Sbill 			line++;
441996Sbill 		if (*line == '\0')
442996Sbill 			break;
443996Sbill 		args[narg++] = line;
444996Sbill 		while(*line != '\0' && *line != ' ' && *line != '\t')
445996Sbill 			line++;
446996Sbill 		if (*line == '\0')
447996Sbill 			break;
448996Sbill 		*line++ = '\0';
449996Sbill 	}
450996Sbill 	if (equal(args[0], "take")) {
451996Sbill 		if (narg < 2) {
452996Sbill 			prf("usage: ~%%take from [to]");
453996Sbill 			return;
454996Sbill 		}
455996Sbill 		if (narg < 3)
456996Sbill 			args[2] = args[1];
457996Sbill 		wrln("echo '~>:'");
458996Sbill 		wrln(args[2]);
459996Sbill 		wrln(";tee /dev/null <");
460996Sbill 		wrln(args[1]);
461996Sbill 		wrln(";echo '~>'\n");
462996Sbill 		return;
463996Sbill 	} else if (equal(args[0], "put")) {
464996Sbill 		if (narg < 2) {
465996Sbill 			prf("usage: ~%%put from [to]");
466996Sbill 			return;
467996Sbill 		}
468996Sbill 		if (narg < 3)
469996Sbill 			args[2] = args[1];
470996Sbill 		if ((f = open(args[1], 0)) < 0) {
471996Sbill 			prf("cannot open: %s", args[1]);
472996Sbill 			return;
473996Sbill 		}
474996Sbill 		wrln("stty -echo;cat >");
475996Sbill 		wrln(args[2]);
476996Sbill 		wrln(";stty echo\n");
477996Sbill 		xsleep(5);
478996Sbill 		intr = 0;
479996Sbill 		if (!nhup)
480996Sbill 			signal(SIGINT, sig2);
481996Sbill 		mode(2);
482996Sbill 		rcount = 0;
483996Sbill 		while(!intr && rdc(f) == 1) {
484996Sbill 			rcount++;
485996Sbill 			if (c == tkill || c == terase)
486996Sbill 				wrln("\\");
487996Sbill 			if (wrc(ln) != 1) {
488996Sbill 				xsleep(2);
489996Sbill 				if (wrc(ln) != 1) {
490996Sbill 					prf("character missed");
491996Sbill 					intr = 1;
492996Sbill 					break;
493996Sbill 				}
494996Sbill 			}
495996Sbill 		}
496996Sbill 		signal(SIGINT, SIG_IGN);
497996Sbill 		close(f);
498996Sbill 		if (intr) {
499996Sbill 			wrln("\n");
500996Sbill 			prf("stopped after %d bytes", rcount);
501996Sbill 		}
502996Sbill 		wrln("\004");
503996Sbill 		xsleep(5);
504996Sbill 		mode(1);
505996Sbill 		return;
506996Sbill 	}
507996Sbill 	prf("~%%%s unknown\n", args[0]);
508996Sbill }
509996Sbill 
510996Sbill equal(s1, s2)
511996Sbill register char *s1, *s2;
512996Sbill {
513996Sbill 	while (*s1++ == *s2)
514996Sbill 		if (*s2++ == '\0')
515996Sbill 			return(1);
516996Sbill 	return(0);
517996Sbill }
518996Sbill 
519996Sbill wrln(s)
520996Sbill register char *s;
521996Sbill {
522996Sbill 	while (*s)
523996Sbill 		write(ln, s++, 1);
524996Sbill }
525996Sbill /*	chwrsig:  Catch orders from wr process
526996Sbill  *	to instigate diversion
527996Sbill  */
528996Sbill int whoami;
529996Sbill chwrsig(){
530996Sbill 	int dodiver();
531996Sbill 	whoami = getpid();
532996Sbill 	signal(SIGEMT,dodiver);
533996Sbill }
534996Sbill int ds,slnt;
535996Sbill int justrung;
536996Sbill dodiver(){
537996Sbill 	static char dobuff[128], morejunk[256]; register char *cp;
538996Sbill 	FILE *fp;
539996Sbill 	justrung = 1;
540996Sbill 	signal(SIGEMT,dodiver);
541996Sbill 	sprintf(dobuff,"/tmp/cu%d",whoami);
542996Sbill 	fp = fopen(dobuff,"r");
543996Sbill 	if(fp==NULL) prf("Couldn't open temporary");
544996Sbill 	unlink(dobuff);
545996Sbill 	if(dbflag) {
546996Sbill 		prf("Name of temporary:");
547996Sbill 		prf(dobuff);
548996Sbill 	}
549996Sbill 	fgets(dobuff,128,fp); fclose(fp);
550996Sbill 	if(dbflag) {
551996Sbill 		prf("Name of target file:");
552996Sbill 		prf(dobuff);
553996Sbill 	}
554996Sbill 	for(cp = dobuff-1; *++cp; ) /* squash newline */
555996Sbill 		if(*cp=='\n') *cp=0;
556996Sbill 	cp = dobuff;
557996Sbill 	if (*cp=='>') cp++;
558996Sbill 	if (*cp==':') {
559996Sbill 		cp++;
560996Sbill 		if(*cp==0) {
561996Sbill 			slnt ^= 1;
562996Sbill 			return;
563996Sbill 		} else  {
564996Sbill 			slnt = 1;
565996Sbill 		}
566996Sbill 	}
567996Sbill 	if (ds >= 0) close(ds);
568996Sbill 	if (*cp==0) {
569996Sbill 		slnt = 0;
570996Sbill 		ds = -1;
571996Sbill 		return;
572996Sbill 	}
573996Sbill 	if (*dobuff!='>' || (ds=open(cp,1))<0) ds=creat(cp,0644);
574996Sbill 	lseek(ds, (long)0, 2);
575996Sbill 	if(ds < 0) prf("Creat failed:"), prf(cp);
576996Sbill 	if (ds<0) prf("Can't divert %s",cp+1);
577996Sbill }
578996Sbill 
579996Sbill 
580996Sbill /*
581996Sbill  *	rd: read from remote: line -> 1
582996Sbill  *	catch:
583996Sbill  *	~>[>][:][file]
584996Sbill  *	stuff from file...
585996Sbill  *	~>	(ends diversion)
586996Sbill  */
587996Sbill 
588996Sbill rd()
589996Sbill {
590996Sbill 	extern int ds,slnt;
591996Sbill 	char *p,*q,b[600];
592996Sbill 	p=b;
593996Sbill 	ds=(-1);
594996Sbill agin:
595996Sbill 	while (rdc(ln) == 1) {
596996Sbill 		if (!slnt) wrc(1);
597996Sbill 		*p++=c;
598996Sbill 		if (c!='\n') continue;
599996Sbill 		q=p;
600996Sbill 		p=b;
601996Sbill 		if (b[0]!='~' || b[1]!='>') {
602996Sbill 			if (*(q-2) == '\r') {
603996Sbill 				q--;
604996Sbill 				*(q-1)=(*q);
605996Sbill 			}
606996Sbill 			if (ds>=0) write(ds,b,q-b);
607996Sbill 			continue;
608996Sbill 		}
609996Sbill 		if (ds>=0) close(ds);
610996Sbill 		if (slnt) {
611996Sbill 			write(1, b, q - b);
612996Sbill 			write(1, CRLF, sizeof(CRLF));
613996Sbill 		}
614996Sbill 		if (*(q-2) == '\r') q--;
615996Sbill 		*(q-1)=0;
616996Sbill 		slnt=0;
617996Sbill 		q=b+2;
618996Sbill 		if (*q == '>') q++;
619996Sbill 		if (*q == ':') {
620996Sbill 			slnt=1;
621996Sbill 			q++;
622996Sbill 		}
623996Sbill 		if (*q == 0) {
624996Sbill 			ds=(-1);
625996Sbill 			continue;
626996Sbill 		}
627996Sbill 		if (b[2]!='>' || (ds=open(q,1))<0) ds=creat(q,0644);
628996Sbill 		lseek(ds, (long)0, 2);
629996Sbill 		if (ds<0) prf("Can't divert %s",b+1);
630996Sbill 	}
631996Sbill 	if(justrung) {
632996Sbill 		justrung = 0;
633996Sbill 		goto agin;
634996Sbill 	}
635996Sbill }
636996Sbill 
637996Sbill struct {char lobyte; char hibyte;};
638996Sbill mode(f)
639996Sbill {
640996Sbill 	struct sgttyb stbuf;
641996Sbill 	if (dout) return;
642996Sbill 	ioctl(0, TIOCGETP, &stbuf);
643996Sbill 	tkill = stbuf.sg_kill;
644996Sbill 	terase = stbuf.sg_erase;
645996Sbill 	if (f == 0) {
646996Sbill 		stbuf.sg_flags &= ~RAW;
647996Sbill 		stbuf.sg_flags |= ECHO|CRMOD;
648996Sbill 	}
649996Sbill 	if (f == 1) {
650996Sbill 		stbuf.sg_flags |= RAW;
651996Sbill 		stbuf.sg_flags &= ~(ECHO|CRMOD);
652996Sbill 	}
653996Sbill 	if (f == 2) {
654996Sbill 		stbuf.sg_flags &= ~RAW;
655996Sbill 		stbuf.sg_flags &= ~(ECHO|CRMOD);
656996Sbill 	}
657996Sbill 	ioctl(0, TIOCSETP, &stbuf);
658996Sbill }
659996Sbill 
660996Sbill echo(s)
661996Sbill char *s;
662996Sbill {
663996Sbill 	char *p;
664996Sbill 	for (p=s;*p;p++);
665996Sbill 	if (p>s) write(0,s,p-s);
666996Sbill 	write(0,CRLF, sizeof(CRLF));
667996Sbill }
668996Sbill 
669996Sbill prf(f, s)
670996Sbill char *f;
671996Sbill char *s;
672996Sbill {
673996Sbill 	fprintf(stderr, f, s);
674996Sbill 	fprintf(stderr, CRLF);
675996Sbill }
676996Sbill 
677996Sbill exists(devname)
678996Sbill char *devname;
679996Sbill {
680996Sbill 	if (access(devname, 0)==0)
681996Sbill 		return(1);
682996Sbill 	prf("%s does not exist", devname);
683996Sbill 	return(0);
684996Sbill }
685*2370Smark 
686*2370Smark cleanup(code)
687*2370Smark {
688*2370Smark 	rmlock(NULL);
689*2370Smark 	exit(code);
690*2370Smark }
691*2370Smark 
692*2370Smark /*
693*2370Smark  * This code is taken directly from uucp and follows the same
694*2370Smark  * conventions.  This is important since uucp and cu should
695*2370Smark  * respect each others locks.
696*2370Smark  */
697*2370Smark 
698*2370Smark 	/*  ulockf 3.2  10/26/79  11:40:29  */
699*2370Smark /* #include "uucp.h" */
700*2370Smark #include <sys/types.h>
701*2370Smark #include <sys/stat.h>
702*2370Smark 
703*2370Smark 
704*2370Smark 
705*2370Smark /*******
706*2370Smark  *	ulockf(file, atime)
707*2370Smark  *	char *file;
708*2370Smark  *	time_t atime;
709*2370Smark  *
710*2370Smark  *	ulockf  -  this routine will create a lock file (file).
711*2370Smark  *	If one already exists, the create time is checked for
712*2370Smark  *	older than the age time (atime).
713*2370Smark  *	If it is older, an attempt will be made to unlink it
714*2370Smark  *	and create a new one.
715*2370Smark  *
716*2370Smark  *	return codes:  0  |  FAIL
717*2370Smark  */
718*2370Smark 
719*2370Smark ulockf(file, atime)
720*2370Smark char *file;
721*2370Smark time_t atime;
722*2370Smark {
723*2370Smark 	struct stat stbuf;
724*2370Smark 	time_t ptime;
725*2370Smark 	int ret;
726*2370Smark 	static int pid = -1;
727*2370Smark 	static char tempfile[NAMESIZE];
728*2370Smark 
729*2370Smark 	if (pid < 0) {
730*2370Smark 		pid = getpid();
731*2370Smark 		sprintf(tempfile, "/usr/spool/uucp/LTMP.%d", pid);
732*2370Smark 	}
733*2370Smark 	if (onelock(pid, tempfile, file) == -1) {
734*2370Smark 		/* lock file exists */
735*2370Smark 		/* get status to check age of the lock file */
736*2370Smark 		ret = stat(file, &stbuf);
737*2370Smark 		if (ret != -1) {
738*2370Smark 			time(&ptime);
739*2370Smark 			if ((ptime - stbuf.st_ctime) < atime) {
740*2370Smark 				/* file not old enough to delete */
741*2370Smark 				return(FAIL);
742*2370Smark 			}
743*2370Smark 		}
744*2370Smark 		ret = unlink(file);
745*2370Smark 		ret = onelock(pid, tempfile, file);
746*2370Smark 		if (ret != 0)
747*2370Smark 			return(FAIL);
748*2370Smark 	}
749*2370Smark 	stlock(file);
750*2370Smark 	return(0);
751*2370Smark }
752*2370Smark 
753*2370Smark 
754*2370Smark #define MAXLOCKS 10	/* maximum number of lock files */
755*2370Smark char *Lockfile[MAXLOCKS];
756*2370Smark int Nlocks = 0;
757*2370Smark 
758*2370Smark /***
759*2370Smark  *	stlock(name)	put name in list of lock files
760*2370Smark  *	char *name;
761*2370Smark  *
762*2370Smark  *	return codes:  none
763*2370Smark  */
764*2370Smark 
765*2370Smark stlock(name)
766*2370Smark char *name;
767*2370Smark {
768*2370Smark 	char *p;
769*2370Smark 	extern char *calloc();
770*2370Smark 	int i;
771*2370Smark 
772*2370Smark 	for (i = 0; i < Nlocks; i++) {
773*2370Smark 		if (Lockfile[i] == NULL)
774*2370Smark 			break;
775*2370Smark 	}
776*2370Smark 	ASSERT(i < MAXLOCKS, "TOO MANY LOCKS %d", i);
777*2370Smark 	if (i >= Nlocks)
778*2370Smark 		i = Nlocks++;
779*2370Smark 	p = calloc(strlen(name) + 1, sizeof (char));
780*2370Smark 	ASSERT(p != NULL, "CAN NOT ALLOCATE FOR %s", name);
781*2370Smark 	strcpy(p, name);
782*2370Smark 	Lockfile[i] = p;
783*2370Smark 	return;
784*2370Smark }
785*2370Smark 
786*2370Smark 
787*2370Smark /***
788*2370Smark  *	rmlock(name)	remove all lock files in list
789*2370Smark  *	char *name;	or name
790*2370Smark  *
791*2370Smark  *	return codes: none
792*2370Smark  */
793*2370Smark 
794*2370Smark rmlock(name)
795*2370Smark char *name;
796*2370Smark {
797*2370Smark 	int i;
798*2370Smark 
799*2370Smark 	for (i = 0; i < Nlocks; i++) {
800*2370Smark 		if (Lockfile[i] == NULL)
801*2370Smark 			continue;
802*2370Smark 		if (name == NULL
803*2370Smark 		|| strcmp(name, Lockfile[i]) == SAME) {
804*2370Smark 			unlink(Lockfile[i]);
805*2370Smark 			free(Lockfile[i]);
806*2370Smark 			Lockfile[i] = NULL;
807*2370Smark 		}
808*2370Smark 	}
809*2370Smark 	return;
810*2370Smark }
811*2370Smark 
812*2370Smark 
813*2370Smark /*  this stuff from pjw  */
814*2370Smark /*  /usr/pjw/bin/recover - check pids to remove unnecessary locks */
815*2370Smark /*	isalock(name) returns 0 if the name is a lock */
816*2370Smark /*	unlock(name)  unlocks name if it is a lock*/
817*2370Smark /*	onelock(pid,tempfile,name) makes lock a name
818*2370Smark 	on behalf of pid.  Tempfile must be in the same
819*2370Smark 	file system as name. */
820*2370Smark /*	lock(pid,tempfile,names) either locks all the
821*2370Smark 	names or none of them */
822*2370Smark isalock(name) char *name;
823*2370Smark {
824*2370Smark 	struct stat xstat;
825*2370Smark 	if(stat(name,&xstat)<0) return(0);
826*2370Smark 	if(xstat.st_size!=sizeof(int)) return(0);
827*2370Smark 	return(1);
828*2370Smark }
829*2370Smark unlock(name) char *name;
830*2370Smark {
831*2370Smark 	if(isalock(name)) return(unlink(name));
832*2370Smark 	else return(-1);
833*2370Smark }
834*2370Smark onelock(pid,tempfile,name) char *tempfile,*name;
835*2370Smark {	int fd;
836*2370Smark 	fd=creat(tempfile,0444);
837*2370Smark 	if(fd<0) return(-1);
838*2370Smark 	write(fd,(char *) &pid,sizeof(int));
839*2370Smark 	close(fd);
840*2370Smark 	if(link(tempfile,name)<0)
841*2370Smark 	{	unlink(tempfile);
842*2370Smark 		return(-1);
843*2370Smark 	}
844*2370Smark 	unlink(tempfile);
845*2370Smark 	return(0);
846*2370Smark }
847*2370Smark lock(pid,tempfile,names) char *tempfile,**names;
848*2370Smark {	int i,j;
849*2370Smark 	for(i=0;names[i]!=0;i++)
850*2370Smark 	{	if(onelock(pid,tempfile,names[i])==0) continue;
851*2370Smark 		for(j=0;j<i;j++) unlink(names[j]);
852*2370Smark 		return(-1);
853*2370Smark 	}
854*2370Smark 	return(0);
855*2370Smark }
856*2370Smark 
857*2370Smark #define LOCKPRE "/usr/spool/uucp/LCK."
858*2370Smark 
859*2370Smark /***
860*2370Smark  *	delock(s)	remove a lock file
861*2370Smark  *	char *s;
862*2370Smark  *
863*2370Smark  *	return codes:  0  |  FAIL
864*2370Smark  */
865*2370Smark 
866*2370Smark delock(s)
867*2370Smark char *s;
868*2370Smark {
869*2370Smark 	char ln[30];
870*2370Smark 
871*2370Smark 	sprintf(ln, "%s.%s", LOCKPRE, s);
872*2370Smark 	rmlock(ln);
873*2370Smark }
874*2370Smark 
875*2370Smark 
876*2370Smark /***
877*2370Smark  *	mlock(sys)	create system lock
878*2370Smark  *	char *sys;
879*2370Smark  *
880*2370Smark  *	return codes:  0  |  FAIL
881*2370Smark  */
882*2370Smark 
883*2370Smark mlock(sys)
884*2370Smark char *sys;
885*2370Smark {
886*2370Smark 	char lname[30];
887*2370Smark 	sprintf(lname, "%s.%s", LOCKPRE, sys);
888*2370Smark 	return(ulockf(lname, (time_t) SLCKTIME ) < 0 ? FAIL : 0);
889*2370Smark }
890*2370Smark 
891*2370Smark 
892*2370Smark 
893*2370Smark /***
894*2370Smark  *	ultouch()	update access and modify times for lock files
895*2370Smark  *
896*2370Smark  *	return code - none
897*2370Smark  */
898*2370Smark 
899*2370Smark ultouch()
900*2370Smark {
901*2370Smark 	time_t time();
902*2370Smark 	int i;
903*2370Smark 	struct ut {
904*2370Smark 		time_t actime;
905*2370Smark 		time_t modtime;
906*2370Smark 	} ut;
907*2370Smark 
908*2370Smark 	ut.actime = time(&ut.modtime);
909*2370Smark 	for (i = 0; i < Nlocks; i++) {
910*2370Smark 		if (Lockfile[i] == NULL)
911*2370Smark 			continue;
912*2370Smark 		utime(Lockfile[i], &ut);
913*2370Smark 	}
914*2370Smark 	return;
915*2370Smark }
916