xref: /csrg-svn/old/cu/cu.c (revision 3924)
1*3924Sroot static	char *sccsid = "@(#)cu.c	4.5 (Berkeley) 81/07/02";
2996Sbill #include <stdio.h>
3996Sbill #include <signal.h>
4996Sbill #include <sgtty.h>
52370Smark 
6996Sbill /*
72370Smark  * defs that come from uucp.h
82370Smark  */
92370Smark #define NAMESIZE 15
102370Smark #define FAIL -1
112370Smark #define SAME 0
122370Smark #define SLCKTIME 5400	/* system/device timeout (LCK.. files) in seconds */
132370Smark #define ASSERT(e, f, v) if (!(e)) {\
142370Smark 	fprintf(stderr, "AERROR - (%s) ", "e");\
152370Smark 	fprintf(stderr, f, v);\
162370Smark 	cleanup(FAIL);\
172370Smark }
182370Smark 
192370Smark /*
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",
572370Smark 	"usage: cu telno [-t] [-s speed] [-l line] [-a acu]",
582370Smark 	"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;
1012370Smark 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;
1152791Swnj 	int cleanup();
116996Sbill 
117996Sbill 	signal(SIGALRM, sig14);
1182791Swnj 	signal(SIGINT, cleanup);
1192791Swnj 	signal(SIGHUP, cleanup);
1202791Swnj 	signal(SIGQUIT, cleanup);
121996Sbill 	if (ac < 2) {
122996Sbill 		prf(connmsg[8]);
123996Sbill 		exit(8);
124996Sbill 	}
125996Sbill 	for (; ac > 1; av++,ac--) {
126996Sbill 		if (av[1][0] != '-')
127996Sbill 			telno = av[1];
128996Sbill 		else switch(av[1][1]) {
129996Sbill 		case 't':
130996Sbill 			dout = 1;
131996Sbill 			--ac;
132996Sbill 			continue;
1332370Smark 		case 'b':
1342370Smark 			nullbrk++;
1352370Smark 			continue;
136996Sbill 		case 'd':
137996Sbill 			dbflag++;
138996Sbill 			continue;
139996Sbill 		case 's':
140996Sbill 			lspeed = av[2]; ++av; --ac;
141996Sbill 			break;
142996Sbill 		case 'l':
143996Sbill 			devcul = av[2]; ++av; --ac;
144996Sbill 			break;
145996Sbill 		case 'a':
146996Sbill 			devcua = av[2]; ++av; --ac;
147996Sbill 			break;
148996Sbill 		case '0': case '1': case '2': case '3': case '4':
149996Sbill 		case '5': case '6': case '7': case '8': case '9':
150996Sbill 			devcua[strlen(devcua)-1] = av[1][1];
151996Sbill 			devcul[strlen(devcul)-1] = av[1][1];
152996Sbill 			break;
153996Sbill 		default:
154996Sbill 			prf("Bad flag %s", av[1]);
155996Sbill 			break;
156996Sbill 		}
157996Sbill 	}
158996Sbill 	if (!exists(devcua) || !exists(devcul))
159996Sbill 		exit(9);
160996Sbill 	ln = conn(devcul, devcua, telno);
161996Sbill 	if (ln < 0) {
162996Sbill 		prf("Connect failed: %s",connmsg[-ln]);
1632370Smark 		cleanup(-ln);
164996Sbill 	}
165996Sbill 	switch(atoi(lspeed)) {
166996Sbill 	case 110:
167996Sbill 		speed = B110;break;
168996Sbill 	case 150:
169996Sbill 		speed = B150;break;
170996Sbill 	default:
171996Sbill 	case 300:
172996Sbill 		speed = B300;break;
173996Sbill 	case 1200:
174996Sbill 		speed = B1200;break;
175996Sbill 	}
176996Sbill 	stbuf.sg_ispeed = speed;
177996Sbill 	stbuf.sg_ospeed = speed;
178996Sbill 	stbuf.sg_flags = EVENP|ODDP;
179996Sbill 	if (!dout) {
180996Sbill 		stbuf.sg_flags |= RAW;
181996Sbill 		stbuf.sg_flags &= ~ECHO;
182996Sbill 	}
183996Sbill 	ioctl(ln, TIOCSETP, &stbuf);
184996Sbill 	ioctl(ln, TIOCEXCL, (struct sgttyb *)NULL);
185996Sbill 	ioctl(ln, TIOCHPCL, (struct sgttyb *)NULL);
186996Sbill 	prf("Connected");
187996Sbill 	if (dout)
1883923Sroot 		fk = -12345;
189996Sbill 	else
190996Sbill 		fk = fork();
191996Sbill 	nhup = (int)signal(SIGINT, SIG_IGN);
192996Sbill 	if (fk == 0) {
193996Sbill 		chwrsig();
194996Sbill 		rd();
195996Sbill 		prf("\007Lost carrier");
1962370Smark 		cleanup(3);
197996Sbill 	}
198996Sbill 	mode(1);
199996Sbill 	efk = fk;
200996Sbill 	wr();
201996Sbill 	mode(0);
202*3924Sroot 	if (fk != -1) kill(fk, SIGKILL);
203996Sbill 	wait((int *)NULL);
204996Sbill 	stbuf.sg_ispeed = 0;
205996Sbill 	stbuf.sg_ospeed = 0;
206996Sbill 	ioctl(ln, TIOCSETP, &stbuf);
207996Sbill 	prf("Disconnected");
2082370Smark 	cleanup(0);
209996Sbill }
210996Sbill 
211996Sbill /*
212996Sbill  *	conn: establish dial-out connection.
213996Sbill  *	Example:  fd = conn("/dev/ttyh","/dev/dn1","4500");
214996Sbill  *	Returns descriptor open to tty for reading and writing.
215996Sbill  *	Negative values (-1...-7) denote errors in connmsg.
216996Sbill  *	Uses alarm and fork/wait; requires sig14 handler.
217996Sbill  *	Be sure to disconnect tty when done, via HUPCL or stty 0.
218996Sbill  */
219996Sbill 
220996Sbill conn(dev,acu,telno)
221996Sbill char *dev, *acu, *telno;
222996Sbill {
223996Sbill 	struct sgttyb stbuf;
224996Sbill 	extern errno;
225996Sbill 	char *p, *q, b[30];
2262370Smark 	char *ltail, *atail;
2272370Smark 	char *rindex();
228996Sbill 	int er, fk, dn, dh, t;
229996Sbill 	er=0;
230996Sbill 	fk=(-1);
2312370Smark 	atail = rindex(acu, '/')+1;
2322370Smark 	if (mlock(atail) == FAIL) {
2332370Smark 		er = 9;
2342370Smark 		goto X;
2352370Smark 	}
2362370Smark 	ltail = rindex(dev, '/')+1;
2372370Smark 	if (mlock(ltail) == FAIL) {
2382370Smark 		er = 9;
2392370Smark 		delock(atail);
2402370Smark 		goto X;
2412370Smark 	}
242996Sbill 	if ((dn=open(acu,1))<0) {
243996Sbill 		er=(errno == 6? 1:5);
244996Sbill 		goto X;
245996Sbill 	}
246996Sbill 	if ((fk=fork()) == (-1)) {
247996Sbill 		er=4;
248996Sbill 		goto X;
249996Sbill 	}
250996Sbill 	if (fk == 0) {
251996Sbill 		open(dev,2);
252996Sbill 		for (;;) pause();
253996Sbill 	}
254996Sbill 	xsleep(2);
255996Sbill 	/*
256996Sbill 	 *	copy phone #, assure EON
257996Sbill 	 */
258996Sbill 	p=b;
259996Sbill 	q=telno;
260996Sbill 	while (*p++=(*q++))
261996Sbill 		;
262996Sbill 	p--;
263996Sbill 	if (*(p-1)!='<') {
264996Sbill 		/*if (*(p-1)!='-') *p++='-';*/
265996Sbill 		*p++='<';
266996Sbill 	}
267996Sbill 	t=p-b;
268996Sbill 	xalarm(5*t);
269996Sbill 	t=write(dn,b,t);
270996Sbill 	xalarm(0);
271996Sbill 	if (t<0) {
272996Sbill 		er=2;
273996Sbill 		goto X;
274996Sbill 	}
275996Sbill 	/* close(dn) */
276996Sbill 	xalarm(40);		/* was 5; sometimes missed carrier */
277996Sbill 	dh = open(dev,2);
278996Sbill 	xalarm(0);
279996Sbill 	if (dh<0) {
280996Sbill 		er=(errno == 4? 3:6);
281996Sbill 		goto X;
282996Sbill 	}
2832370Smark 	ioctl(dh, TIOCGETP, &stbuf);
284996Sbill 	stbuf.sg_flags &= ~ECHO;
285996Sbill 	xalarm(10);
286996Sbill 	ioctl(dh, TIOCSETP, &stbuf);
287996Sbill 	ioctl(dh, TIOCHPCL, (struct sgttyb *)NULL);
288996Sbill 	xalarm(0);
289996Sbill X:
290996Sbill 	if (er) close(dn);
2912370Smark 	delock(atail);
292996Sbill 	if (fk!=(-1)) {
293996Sbill 		kill(fk, SIGKILL);
294996Sbill 		xalarm(10);
295996Sbill 		while ((t=wait((int *)NULL))!=(-1) && t!=fk);
296996Sbill 		xalarm(0);
297996Sbill 	}
298996Sbill 	return (er? -er:dh);
299996Sbill }
300996Sbill 
301996Sbill /*
302996Sbill  *	wr: write to remote: 0 -> line.
303996Sbill  *	~.	terminate
304996Sbill  *	~<file	send file
305996Sbill  *	~!	local login-style shell
306996Sbill  *	~!cmd	execute cmd locally
307996Sbill  *	~$proc	execute proc locally, send output to line
308996Sbill  *	~%cmd	execute builtin cmd (put and take)
309996Sbill  *	~#	send 1-sec break
3102370Smark  *	~^Z	suspend cu process.
311996Sbill  */
312996Sbill 
313996Sbill wr()
314996Sbill {
315996Sbill 	int ds,fk,lcl,x;
316996Sbill 	char *p,b[600];
317996Sbill 	for (;;) {
318996Sbill 		p=b;
319996Sbill 		while (rdc(0) == 1) {
320996Sbill 			if (p == b) lcl=(c == '~');
321996Sbill 			if (p == b+1 && b[0] == '~') lcl=(c!='~');
3222370Smark 			if (nullbrk && c == 0) oc=c=0177; /* fake break kludge */
323996Sbill 			if (!lcl) {
324996Sbill 				c = oc;
325996Sbill 				if (wrc(ln) == 0) {
326996Sbill 					prf("line gone"); return;
327996Sbill 				}
328996Sbill 				c &= 0177;
329996Sbill 			}
330996Sbill 			if (lcl) {
331996Sbill 				if (c == 0177) c=tkill;
332996Sbill 				if (c == '\r' || c == '\n') goto A;
333996Sbill 				if (!dout) wrc(0);
334996Sbill 			}
335996Sbill 			*p++=c;
336996Sbill 			if (c == terase) {
337996Sbill 				p=p-2;
338996Sbill 				if (p<b) p=b;
339996Sbill 			}
340996Sbill 			if (c == tkill || c == 0177 || c == '\4' || c == '\r' || c == '\n') p=b;
341996Sbill 		}
342996Sbill 		return;
343996Sbill A:
344996Sbill 		if (!dout) echo("");
345996Sbill 		*p=0;
346996Sbill 		switch (b[1]) {
347996Sbill 		case '.':
348996Sbill 		case '\004':
349996Sbill 			return;
350996Sbill 		case '#':
351996Sbill 			ioctl(ln, TIOCSBRK, 0);
352996Sbill 			sleep(1);
353996Sbill 			ioctl(ln, TIOCCBRK, 0);
354996Sbill 			continue;
355996Sbill 		case '!':
356996Sbill 		case '$':
357996Sbill 			fk = fork();
358996Sbill 			if (fk == 0) {
359996Sbill 				char *getenv();
360996Sbill 				char *shell = getenv("SHELL");
361996Sbill 				if (shell == 0) shell = "/bin/sh";
362996Sbill 				close(1);
363996Sbill 				dup(b[1] == '$'? ln:2);
364996Sbill 				close(ln);
365996Sbill 				mode(0);
366996Sbill 				if (!nhup) signal(SIGINT, SIG_DFL);
367996Sbill 				if (b[2] == 0) execl(shell,shell,0);
368996Sbill 				/* if (b[2] == 0) execl(shell,"-",0); */
369996Sbill 				else execl(shell,"sh","-c",b+2,0);
370996Sbill 				prf("Can't execute shell");
371996Sbill 				exit(~0);
372996Sbill 			}
373996Sbill 			if (fk!=(-1)) {
374996Sbill 				while (wait(&x)!=fk);
375996Sbill 			}
376996Sbill 			mode(1);
377996Sbill 			if (b[1] == '!') echo("!");
378996Sbill 			else {
379996Sbill 				if (dout) echo("$");
380996Sbill 			}
381996Sbill 			break;
382996Sbill 		case '<':
383996Sbill 			if (b[2] == 0) break;
384996Sbill 			if ((ds=open(b+2,0))<0) {
385996Sbill 				prf("Can't divert %s",b+1);
386996Sbill 				break;
387996Sbill 			}
388996Sbill 			intr=x=0;
389996Sbill 			mode(2);
390996Sbill 			if (!nhup) signal(SIGINT, sig2);
391996Sbill 			while (!intr && rdc(ds) == 1) {
392996Sbill 				if (wrc(ln) == 0) {
393996Sbill 					x=1;
394996Sbill 					break;
395996Sbill 				}
396996Sbill 			}
397996Sbill 			signal(SIGINT, SIG_IGN);
398996Sbill 			close(ds);
399996Sbill 			mode(1);
400996Sbill 			if (x) return;
401996Sbill 			if (dout) echo("<");
402996Sbill 			break;
403996Sbill 		case '>':
404996Sbill 		case ':':
405996Sbill 			{
406996Sbill 			FILE *fp; char tbuff[128]; register char *q;
407996Sbill 			sprintf(tbuff,"/tmp/cu%d",efk);
408996Sbill 			if(NULL==(fp = fopen(tbuff,"w"))) {
409996Sbill 				prf("Can't tell other demon to divert");
410996Sbill 				break;
411996Sbill 			}
412996Sbill 			fprintf(fp,"%s\n",(b[1]=='>'?&b[2]: &b[1] ));
413996Sbill 			if(dbflag) prf("name to be written in temporary:"),prf(&b[2]);
414996Sbill 			fclose(fp);
415*3924Sroot 			if (efk != -1) kill(efk,SIGEMT);
416996Sbill 			}
417996Sbill 			break;
418996Sbill #ifdef SIGTSTP
419996Sbill #define CTRLZ	26
420996Sbill 		case CTRLZ:
421996Sbill 			mode(0);
422996Sbill 			kill(getpid(), SIGTSTP);
423996Sbill 			mode(1);
424996Sbill 			break;
425996Sbill #endif
426996Sbill 		case '%':
427996Sbill 			dopercen(&b[2]);
428996Sbill 			break;
429996Sbill 		default:
430996Sbill 			prf("Use `~~' to start line with `~'");
431996Sbill 		}
432996Sbill 		continue;
433996Sbill 	}
434996Sbill }
435996Sbill 
436996Sbill dopercen(line)
437996Sbill register char *line;
438996Sbill {
439996Sbill 	char *args[10];
440996Sbill 	register narg, f;
441996Sbill 	int rcount;
442996Sbill 	for (narg = 0; narg < 10;) {
443996Sbill 		while(*line == ' ' || *line == '\t')
444996Sbill 			line++;
445996Sbill 		if (*line == '\0')
446996Sbill 			break;
447996Sbill 		args[narg++] = line;
448996Sbill 		while(*line != '\0' && *line != ' ' && *line != '\t')
449996Sbill 			line++;
450996Sbill 		if (*line == '\0')
451996Sbill 			break;
452996Sbill 		*line++ = '\0';
453996Sbill 	}
454996Sbill 	if (equal(args[0], "take")) {
455996Sbill 		if (narg < 2) {
456996Sbill 			prf("usage: ~%%take from [to]");
457996Sbill 			return;
458996Sbill 		}
459996Sbill 		if (narg < 3)
460996Sbill 			args[2] = args[1];
461996Sbill 		wrln("echo '~>:'");
462996Sbill 		wrln(args[2]);
463996Sbill 		wrln(";tee /dev/null <");
464996Sbill 		wrln(args[1]);
465996Sbill 		wrln(";echo '~>'\n");
466996Sbill 		return;
467996Sbill 	} else if (equal(args[0], "put")) {
468996Sbill 		if (narg < 2) {
469996Sbill 			prf("usage: ~%%put from [to]");
470996Sbill 			return;
471996Sbill 		}
472996Sbill 		if (narg < 3)
473996Sbill 			args[2] = args[1];
474996Sbill 		if ((f = open(args[1], 0)) < 0) {
475996Sbill 			prf("cannot open: %s", args[1]);
476996Sbill 			return;
477996Sbill 		}
478996Sbill 		wrln("stty -echo;cat >");
479996Sbill 		wrln(args[2]);
480996Sbill 		wrln(";stty echo\n");
481996Sbill 		xsleep(5);
482996Sbill 		intr = 0;
483996Sbill 		if (!nhup)
484996Sbill 			signal(SIGINT, sig2);
485996Sbill 		mode(2);
486996Sbill 		rcount = 0;
487996Sbill 		while(!intr && rdc(f) == 1) {
488996Sbill 			rcount++;
489996Sbill 			if (c == tkill || c == terase)
490996Sbill 				wrln("\\");
491996Sbill 			if (wrc(ln) != 1) {
492996Sbill 				xsleep(2);
493996Sbill 				if (wrc(ln) != 1) {
494996Sbill 					prf("character missed");
495996Sbill 					intr = 1;
496996Sbill 					break;
497996Sbill 				}
498996Sbill 			}
499996Sbill 		}
500996Sbill 		signal(SIGINT, SIG_IGN);
501996Sbill 		close(f);
502996Sbill 		if (intr) {
503996Sbill 			wrln("\n");
504996Sbill 			prf("stopped after %d bytes", rcount);
505996Sbill 		}
506996Sbill 		wrln("\004");
507996Sbill 		xsleep(5);
508996Sbill 		mode(1);
509996Sbill 		return;
510996Sbill 	}
511996Sbill 	prf("~%%%s unknown\n", args[0]);
512996Sbill }
513996Sbill 
514996Sbill equal(s1, s2)
515996Sbill register char *s1, *s2;
516996Sbill {
517996Sbill 	while (*s1++ == *s2)
518996Sbill 		if (*s2++ == '\0')
519996Sbill 			return(1);
520996Sbill 	return(0);
521996Sbill }
522996Sbill 
523996Sbill wrln(s)
524996Sbill register char *s;
525996Sbill {
526996Sbill 	while (*s)
527996Sbill 		write(ln, s++, 1);
528996Sbill }
529996Sbill /*	chwrsig:  Catch orders from wr process
530996Sbill  *	to instigate diversion
531996Sbill  */
532996Sbill int whoami;
533996Sbill chwrsig(){
534996Sbill 	int dodiver();
535996Sbill 	whoami = getpid();
536996Sbill 	signal(SIGEMT,dodiver);
537996Sbill }
538996Sbill int ds,slnt;
539996Sbill int justrung;
540996Sbill dodiver(){
541996Sbill 	static char dobuff[128], morejunk[256]; register char *cp;
542996Sbill 	FILE *fp;
543996Sbill 	justrung = 1;
544996Sbill 	signal(SIGEMT,dodiver);
545996Sbill 	sprintf(dobuff,"/tmp/cu%d",whoami);
546996Sbill 	fp = fopen(dobuff,"r");
547996Sbill 	if(fp==NULL) prf("Couldn't open temporary");
548996Sbill 	unlink(dobuff);
549996Sbill 	if(dbflag) {
550996Sbill 		prf("Name of temporary:");
551996Sbill 		prf(dobuff);
552996Sbill 	}
553996Sbill 	fgets(dobuff,128,fp); fclose(fp);
554996Sbill 	if(dbflag) {
555996Sbill 		prf("Name of target file:");
556996Sbill 		prf(dobuff);
557996Sbill 	}
558996Sbill 	for(cp = dobuff-1; *++cp; ) /* squash newline */
559996Sbill 		if(*cp=='\n') *cp=0;
560996Sbill 	cp = dobuff;
561996Sbill 	if (*cp=='>') cp++;
562996Sbill 	if (*cp==':') {
563996Sbill 		cp++;
564996Sbill 		if(*cp==0) {
565996Sbill 			slnt ^= 1;
566996Sbill 			return;
567996Sbill 		} else  {
568996Sbill 			slnt = 1;
569996Sbill 		}
570996Sbill 	}
571996Sbill 	if (ds >= 0) close(ds);
572996Sbill 	if (*cp==0) {
573996Sbill 		slnt = 0;
574996Sbill 		ds = -1;
575996Sbill 		return;
576996Sbill 	}
577996Sbill 	if (*dobuff!='>' || (ds=open(cp,1))<0) ds=creat(cp,0644);
578996Sbill 	lseek(ds, (long)0, 2);
579996Sbill 	if(ds < 0) prf("Creat failed:"), prf(cp);
580996Sbill 	if (ds<0) prf("Can't divert %s",cp+1);
581996Sbill }
582996Sbill 
583996Sbill 
584996Sbill /*
585996Sbill  *	rd: read from remote: line -> 1
586996Sbill  *	catch:
587996Sbill  *	~>[>][:][file]
588996Sbill  *	stuff from file...
589996Sbill  *	~>	(ends diversion)
590996Sbill  */
591996Sbill 
592996Sbill rd()
593996Sbill {
594996Sbill 	extern int ds,slnt;
595996Sbill 	char *p,*q,b[600];
596996Sbill 	p=b;
597996Sbill 	ds=(-1);
598996Sbill agin:
599996Sbill 	while (rdc(ln) == 1) {
600996Sbill 		if (!slnt) wrc(1);
6012791Swnj 		if (p < &b[600])
6022791Swnj 			*p++=c;
603996Sbill 		if (c!='\n') continue;
604996Sbill 		q=p;
605996Sbill 		p=b;
606996Sbill 		if (b[0]!='~' || b[1]!='>') {
607996Sbill 			if (*(q-2) == '\r') {
608996Sbill 				q--;
609996Sbill 				*(q-1)=(*q);
610996Sbill 			}
611996Sbill 			if (ds>=0) write(ds,b,q-b);
612996Sbill 			continue;
613996Sbill 		}
614996Sbill 		if (ds>=0) close(ds);
615996Sbill 		if (slnt) {
616996Sbill 			write(1, b, q - b);
617996Sbill 			write(1, CRLF, sizeof(CRLF));
618996Sbill 		}
619996Sbill 		if (*(q-2) == '\r') q--;
620996Sbill 		*(q-1)=0;
621996Sbill 		slnt=0;
622996Sbill 		q=b+2;
623996Sbill 		if (*q == '>') q++;
624996Sbill 		if (*q == ':') {
625996Sbill 			slnt=1;
626996Sbill 			q++;
627996Sbill 		}
628996Sbill 		if (*q == 0) {
629996Sbill 			ds=(-1);
630996Sbill 			continue;
631996Sbill 		}
632996Sbill 		if (b[2]!='>' || (ds=open(q,1))<0) ds=creat(q,0644);
633996Sbill 		lseek(ds, (long)0, 2);
634996Sbill 		if (ds<0) prf("Can't divert %s",b+1);
635996Sbill 	}
636996Sbill 	if(justrung) {
637996Sbill 		justrung = 0;
638996Sbill 		goto agin;
639996Sbill 	}
640996Sbill }
641996Sbill 
642996Sbill struct {char lobyte; char hibyte;};
643996Sbill mode(f)
644996Sbill {
645996Sbill 	struct sgttyb stbuf;
646996Sbill 	if (dout) return;
647996Sbill 	ioctl(0, TIOCGETP, &stbuf);
648996Sbill 	tkill = stbuf.sg_kill;
649996Sbill 	terase = stbuf.sg_erase;
650996Sbill 	if (f == 0) {
651996Sbill 		stbuf.sg_flags &= ~RAW;
652996Sbill 		stbuf.sg_flags |= ECHO|CRMOD;
653996Sbill 	}
654996Sbill 	if (f == 1) {
655996Sbill 		stbuf.sg_flags |= RAW;
656996Sbill 		stbuf.sg_flags &= ~(ECHO|CRMOD);
657996Sbill 	}
658996Sbill 	if (f == 2) {
659996Sbill 		stbuf.sg_flags &= ~RAW;
660996Sbill 		stbuf.sg_flags &= ~(ECHO|CRMOD);
661996Sbill 	}
662996Sbill 	ioctl(0, TIOCSETP, &stbuf);
663996Sbill }
664996Sbill 
665996Sbill echo(s)
666996Sbill char *s;
667996Sbill {
668996Sbill 	char *p;
669996Sbill 	for (p=s;*p;p++);
670996Sbill 	if (p>s) write(0,s,p-s);
671996Sbill 	write(0,CRLF, sizeof(CRLF));
672996Sbill }
673996Sbill 
674996Sbill prf(f, s)
675996Sbill char *f;
676996Sbill char *s;
677996Sbill {
678996Sbill 	fprintf(stderr, f, s);
679996Sbill 	fprintf(stderr, CRLF);
680996Sbill }
681996Sbill 
682996Sbill exists(devname)
683996Sbill char *devname;
684996Sbill {
685996Sbill 	if (access(devname, 0)==0)
686996Sbill 		return(1);
687996Sbill 	prf("%s does not exist", devname);
688996Sbill 	return(0);
689996Sbill }
6902370Smark 
6912370Smark cleanup(code)
6922370Smark {
6932370Smark 	rmlock(NULL);
6942370Smark 	exit(code);
6952370Smark }
6962370Smark 
6972370Smark /*
6982370Smark  * This code is taken directly from uucp and follows the same
6992370Smark  * conventions.  This is important since uucp and cu should
7002370Smark  * respect each others locks.
7012370Smark  */
7022370Smark 
7032370Smark 	/*  ulockf 3.2  10/26/79  11:40:29  */
7042370Smark /* #include "uucp.h" */
7052370Smark #include <sys/types.h>
7062370Smark #include <sys/stat.h>
7072370Smark 
7082370Smark 
7092370Smark 
7102370Smark /*******
7112370Smark  *	ulockf(file, atime)
7122370Smark  *	char *file;
7132370Smark  *	time_t atime;
7142370Smark  *
7152370Smark  *	ulockf  -  this routine will create a lock file (file).
7162370Smark  *	If one already exists, the create time is checked for
7172370Smark  *	older than the age time (atime).
7182370Smark  *	If it is older, an attempt will be made to unlink it
7192370Smark  *	and create a new one.
7202370Smark  *
7212370Smark  *	return codes:  0  |  FAIL
7222370Smark  */
7232370Smark 
7242370Smark ulockf(file, atime)
7252370Smark char *file;
7262370Smark time_t atime;
7272370Smark {
7282370Smark 	struct stat stbuf;
7292370Smark 	time_t ptime;
7302370Smark 	int ret;
7312370Smark 	static int pid = -1;
7322370Smark 	static char tempfile[NAMESIZE];
7332370Smark 
7342370Smark 	if (pid < 0) {
7352370Smark 		pid = getpid();
7362370Smark 		sprintf(tempfile, "/usr/spool/uucp/LTMP.%d", pid);
7372370Smark 	}
7382370Smark 	if (onelock(pid, tempfile, file) == -1) {
7392370Smark 		/* lock file exists */
7402370Smark 		/* get status to check age of the lock file */
7412370Smark 		ret = stat(file, &stbuf);
7422370Smark 		if (ret != -1) {
7432370Smark 			time(&ptime);
7442370Smark 			if ((ptime - stbuf.st_ctime) < atime) {
7452370Smark 				/* file not old enough to delete */
7462370Smark 				return(FAIL);
7472370Smark 			}
7482370Smark 		}
7492370Smark 		ret = unlink(file);
7502370Smark 		ret = onelock(pid, tempfile, file);
7512370Smark 		if (ret != 0)
7522370Smark 			return(FAIL);
7532370Smark 	}
7542370Smark 	stlock(file);
7552370Smark 	return(0);
7562370Smark }
7572370Smark 
7582370Smark 
7592370Smark #define MAXLOCKS 10	/* maximum number of lock files */
7602370Smark char *Lockfile[MAXLOCKS];
7612370Smark int Nlocks = 0;
7622370Smark 
7632370Smark /***
7642370Smark  *	stlock(name)	put name in list of lock files
7652370Smark  *	char *name;
7662370Smark  *
7672370Smark  *	return codes:  none
7682370Smark  */
7692370Smark 
7702370Smark stlock(name)
7712370Smark char *name;
7722370Smark {
7732370Smark 	char *p;
7742370Smark 	extern char *calloc();
7752370Smark 	int i;
7762370Smark 
7772370Smark 	for (i = 0; i < Nlocks; i++) {
7782370Smark 		if (Lockfile[i] == NULL)
7792370Smark 			break;
7802370Smark 	}
7812370Smark 	ASSERT(i < MAXLOCKS, "TOO MANY LOCKS %d", i);
7822370Smark 	if (i >= Nlocks)
7832370Smark 		i = Nlocks++;
7842370Smark 	p = calloc(strlen(name) + 1, sizeof (char));
7852370Smark 	ASSERT(p != NULL, "CAN NOT ALLOCATE FOR %s", name);
7862370Smark 	strcpy(p, name);
7872370Smark 	Lockfile[i] = p;
7882370Smark 	return;
7892370Smark }
7902370Smark 
7912370Smark 
7922370Smark /***
7932370Smark  *	rmlock(name)	remove all lock files in list
7942370Smark  *	char *name;	or name
7952370Smark  *
7962370Smark  *	return codes: none
7972370Smark  */
7982370Smark 
7992370Smark rmlock(name)
8002370Smark char *name;
8012370Smark {
8022370Smark 	int i;
8032370Smark 
8042370Smark 	for (i = 0; i < Nlocks; i++) {
8052370Smark 		if (Lockfile[i] == NULL)
8062370Smark 			continue;
8072370Smark 		if (name == NULL
8082370Smark 		|| strcmp(name, Lockfile[i]) == SAME) {
8092370Smark 			unlink(Lockfile[i]);
8102370Smark 			free(Lockfile[i]);
8112370Smark 			Lockfile[i] = NULL;
8122370Smark 		}
8132370Smark 	}
8142370Smark 	return;
8152370Smark }
8162370Smark 
8172370Smark 
8182370Smark /*  this stuff from pjw  */
8192370Smark /*  /usr/pjw/bin/recover - check pids to remove unnecessary locks */
8202370Smark /*	isalock(name) returns 0 if the name is a lock */
8212370Smark /*	unlock(name)  unlocks name if it is a lock*/
8222370Smark /*	onelock(pid,tempfile,name) makes lock a name
8232370Smark 	on behalf of pid.  Tempfile must be in the same
8242370Smark 	file system as name. */
8252370Smark /*	lock(pid,tempfile,names) either locks all the
8262370Smark 	names or none of them */
8272370Smark isalock(name) char *name;
8282370Smark {
8292370Smark 	struct stat xstat;
8302370Smark 	if(stat(name,&xstat)<0) return(0);
8312370Smark 	if(xstat.st_size!=sizeof(int)) return(0);
8322370Smark 	return(1);
8332370Smark }
8342370Smark unlock(name) char *name;
8352370Smark {
8362370Smark 	if(isalock(name)) return(unlink(name));
8372370Smark 	else return(-1);
8382370Smark }
8392370Smark onelock(pid,tempfile,name) char *tempfile,*name;
8402370Smark {	int fd;
8412370Smark 	fd=creat(tempfile,0444);
8422370Smark 	if(fd<0) return(-1);
8432370Smark 	write(fd,(char *) &pid,sizeof(int));
8442370Smark 	close(fd);
8452370Smark 	if(link(tempfile,name)<0)
8462370Smark 	{	unlink(tempfile);
8472370Smark 		return(-1);
8482370Smark 	}
8492370Smark 	unlink(tempfile);
8502370Smark 	return(0);
8512370Smark }
8522370Smark lock(pid,tempfile,names) char *tempfile,**names;
8532370Smark {	int i,j;
8542370Smark 	for(i=0;names[i]!=0;i++)
8552370Smark 	{	if(onelock(pid,tempfile,names[i])==0) continue;
8562370Smark 		for(j=0;j<i;j++) unlink(names[j]);
8572370Smark 		return(-1);
8582370Smark 	}
8592370Smark 	return(0);
8602370Smark }
8612370Smark 
8622370Smark #define LOCKPRE "/usr/spool/uucp/LCK."
8632370Smark 
8642370Smark /***
8652370Smark  *	delock(s)	remove a lock file
8662370Smark  *	char *s;
8672370Smark  *
8682370Smark  *	return codes:  0  |  FAIL
8692370Smark  */
8702370Smark 
8712370Smark delock(s)
8722370Smark char *s;
8732370Smark {
8742370Smark 	char ln[30];
8752370Smark 
8762370Smark 	sprintf(ln, "%s.%s", LOCKPRE, s);
8772370Smark 	rmlock(ln);
8782370Smark }
8792370Smark 
8802370Smark 
8812370Smark /***
8822370Smark  *	mlock(sys)	create system lock
8832370Smark  *	char *sys;
8842370Smark  *
8852370Smark  *	return codes:  0  |  FAIL
8862370Smark  */
8872370Smark 
8882370Smark mlock(sys)
8892370Smark char *sys;
8902370Smark {
8912370Smark 	char lname[30];
8922370Smark 	sprintf(lname, "%s.%s", LOCKPRE, sys);
8932370Smark 	return(ulockf(lname, (time_t) SLCKTIME ) < 0 ? FAIL : 0);
8942370Smark }
8952370Smark 
8962370Smark 
8972370Smark 
8982370Smark /***
8992370Smark  *	ultouch()	update access and modify times for lock files
9002370Smark  *
9012370Smark  *	return code - none
9022370Smark  */
9032370Smark 
9042370Smark ultouch()
9052370Smark {
9062370Smark 	time_t time();
9072370Smark 	int i;
9082370Smark 	struct ut {
9092370Smark 		time_t actime;
9102370Smark 		time_t modtime;
9112370Smark 	} ut;
9122370Smark 
9132370Smark 	ut.actime = time(&ut.modtime);
9142370Smark 	for (i = 0; i < Nlocks; i++) {
9152370Smark 		if (Lockfile[i] == NULL)
9162370Smark 			continue;
9172370Smark 		utime(Lockfile[i], &ut);
9182370Smark 	}
9192370Smark 	return;
9202370Smark }
921