xref: /original-bsd/old/cu/cu.c (revision e59fb703)
1 static	char *sccsid = "@(#)cu.c	4.7 (Berkeley) 82/10/21";
2 
3 #include <stdio.h>
4 #include <signal.h>
5 #include <sgtty.h>
6 
7 /*
8  * defs that come from uucp.h
9  */
10 #define NAMESIZE 15
11 #define FAIL -1
12 #define SAME 0
13 #define SLCKTIME 5400	/* system/device timeout (LCK.. files) in seconds */
14 #define ASSERT(e, f, v) if (!(e)) {\
15 	fprintf(stderr, "AERROR - (%s) ", "e");\
16 	fprintf(stderr, f, v);\
17 	cleanup(FAIL);\
18 }
19 
20 /*
21  *	cu telno [-t] [-s speed] [-l line] [-a acu] [-p]
22  *
23  *	-t is for dial-out to terminal.
24  *	speeds are: 110, 134, 150, 300, 1200, 2400. 300 is default.
25  *
26  *	-p says strip parity of characters transmitted.  (to compensate
27  *	for c100's)
28  *
29  *	Escape with `~' at beginning of line.
30  *	Ordinary diversions are ~<, ~> and ~>>.
31  *	Silent output diversions are ~>: and ~>>:.
32  *	Terminate output diversion with ~> alone.
33  *	Quit is ~. and ~! gives local command or shell.
34  *	Also ~$ for canned procedure pumping remote.
35  *	~%put from [to]  and  ~%take from [to] invoke builtins
36  */
37 
38 #define CRLF "\r\n"
39 #define wrc(ds) write(ds,&c,1)
40 
41 
42 char	*devcul	= "/dev/cul0";
43 char	*devcua	= "/dev/cua0";
44 char	*lspeed	= "300";
45 
46 int	ln;	/* fd for comm line */
47 char	tkill, terase;	/* current input kill & erase */
48 int	efk;		/* process of id of listener  */
49 char	c;
50 char	oc;
51 
52 char	*connmsg[] = {
53 	"",
54 	"line busy",
55 	"call dropped",
56 	"no carrier",
57 	"can't fork",
58 	"acu access",
59 	"tty access",
60 	"tty hung",
61 	"usage: cu telno [-t] [-s speed] [-l line] [-a acu]",
62 	"lock failed: line busy"
63 };
64 
65 rdc(ds) {
66 
67 	ds=read(ds,&c,1);
68 	oc = c;
69 	c &= 0177;
70 	return (ds);
71 }
72 
73 int intr;
74 
75 sig2()
76 {
77 	signal(SIGINT, SIG_IGN);
78 	intr = 1;
79 }
80 
81 int set14;
82 
83 xsleep(n)
84 {
85 	xalarm(n);
86 	pause();
87 	xalarm(0);
88 }
89 
90 xalarm(n)
91 {
92 	set14=n;
93 	alarm(n);
94 }
95 
96 sig14()
97 {
98 	signal(SIGALRM, sig14);
99 	if (set14) alarm(1);
100 }
101 
102 int	dout;
103 int	nhup;
104 int	dbflag;
105 int	pflag;		/* strip parity on chars sent to remote */
106 int	nullbrk;	/* turn breaks (nulls) into dels */
107 int	pipes[2] = { -1, -1 };
108 
109 /*
110  *	main: get connection, set speed for line.
111  *	spawn child to invoke rd to read from line, output to fd 1
112  *	main line invokes wr to read tty, write to line
113  */
114 main(ac,av)
115 char *av[];
116 {
117 	int fk;
118 	int speed;
119 	char *telno;
120 	struct sgttyb stbuf;
121 	int cleanup();
122 
123 	signal(SIGALRM, sig14);
124 	signal(SIGINT, cleanup);
125 	signal(SIGHUP, cleanup);
126 	signal(SIGQUIT, cleanup);
127 	if (ac < 2) {
128 		prf(connmsg[8]);
129 		exit(8);
130 	}
131 	for (; ac > 1; av++,ac--) {
132 		if (av[1][0] != '-')
133 			telno = av[1];
134 		else switch(av[1][1]) {
135 		case 't':
136 			dout = 1;
137 			--ac;
138 			continue;
139 		case 'b':
140 			nullbrk++;
141 			continue;
142 		case 'd':
143 			dbflag++;
144 			continue;
145 		case 'p':
146 			pflag++;
147 			continue;
148 		case 's':
149 			lspeed = av[2]; ++av; --ac;
150 			break;
151 		case 'l':
152 			devcul = av[2]; ++av; --ac;
153 			break;
154 		case 'a':
155 			devcua = av[2]; ++av; --ac;
156 			break;
157 		case '0': case '1': case '2': case '3': case '4':
158 		case '5': case '6': case '7': case '8': case '9':
159 			devcua[strlen(devcua)-1] = av[1][1];
160 			devcul[strlen(devcul)-1] = av[1][1];
161 			break;
162 		default:
163 			prf("Bad flag %s", av[1]);
164 			break;
165 		}
166 	}
167 	if (!exists(devcua) || !exists(devcul))
168 		exit(9);
169 	ln = conn(devcul, devcua, telno);
170 	if (ln < 0) {
171 		prf("Connect failed: %s",connmsg[-ln]);
172 		cleanup(-ln);
173 	}
174 	switch(atoi(lspeed)) {
175 	case 110:
176 		speed = B110;break;
177 	case 150:
178 		speed = B150;break;
179 	default:
180 	case 300:
181 		speed = B300;break;
182 	case 1200:
183 		speed = B1200;break;
184 	case 2400:
185 		speed = B2400;break;
186 	}
187 	stbuf.sg_ispeed = speed;
188 	stbuf.sg_ospeed = speed;
189 	stbuf.sg_flags = EVENP|ODDP;
190 	if (!dout) {
191 		stbuf.sg_flags |= RAW;
192 		stbuf.sg_flags &= ~ECHO;
193 	}
194 	ioctl(ln, TIOCSETP, &stbuf);
195 	ioctl(ln, TIOCEXCL, (struct sgttyb *)NULL);
196 	ioctl(ln, TIOCHPCL, (struct sgttyb *)NULL);
197 	prf("Connected");
198 	pipe(pipes);
199 	if (dout)
200 		fk = -1;
201 	else
202 		fk = fork();
203 	nhup = (int)signal(SIGINT, SIG_IGN);
204 	if (fk == 0) {
205 		chwrsig();
206 		rd();
207 		prf("\007Lost carrier");
208 		cleanup(3);
209 	}
210 	mode(1);
211 	efk = fk;
212 	wr();
213 	mode(0);
214 	if (fk != -1) kill(fk, SIGKILL);
215 	wait((int *)NULL);
216 	stbuf.sg_ispeed = 0;
217 	stbuf.sg_ospeed = 0;
218 	ioctl(ln, TIOCSETP, &stbuf);
219 	prf("Disconnected");
220 	cleanup(0);
221 }
222 
223 /*
224  *	conn: establish dial-out connection.
225  *	Example:  fd = conn("/dev/ttyh","/dev/dn1","4500");
226  *	Returns descriptor open to tty for reading and writing.
227  *	Negative values (-1...-7) denote errors in connmsg.
228  *	Uses alarm and fork/wait; requires sig14 handler.
229  *	Be sure to disconnect tty when done, via HUPCL or stty 0.
230  */
231 
232 conn(dev,acu,telno)
233 char *dev, *acu, *telno;
234 {
235 	struct sgttyb stbuf;
236 	extern errno;
237 	char *p, *q, b[30];
238 	char *ltail, *atail;
239 	char *rindex();
240 	int er, fk, dn, dh, t;
241 	er=0;
242 	fk=(-1);
243 	atail = rindex(acu, '/')+1;
244 	if (mlock(atail) == FAIL) {
245 		er = 9;
246 		goto X;
247 	}
248 	ltail = rindex(dev, '/')+1;
249 	if (mlock(ltail) == FAIL) {
250 		er = 9;
251 		delock(atail);
252 		goto X;
253 	}
254 	if ((dn=open(acu,1))<0) {
255 		er=(errno == 6? 1:5);
256 		goto X;
257 	}
258 	if ((fk=fork()) == (-1)) {
259 		er=4;
260 		goto X;
261 	}
262 	if (fk == 0) {
263 		open(dev,2);
264 		for (;;) pause();
265 	}
266 	xsleep(2);
267 	/*
268 	 *	copy phone #, assure EON
269 	 */
270 	p=b;
271 	q=telno;
272 	while (*p++=(*q++))
273 		;
274 	p--;
275 	if (*(p-1)!='<') {
276 		/*if (*(p-1)!='-') *p++='-';*/
277 		*p++='<';
278 	}
279 	t=p-b;
280 	xalarm(5*t);
281 	t=write(dn,b,t);
282 	xalarm(0);
283 	if (t<0) {
284 		er=2;
285 		goto X;
286 	}
287 	/* close(dn) */
288 	xalarm(40);		/* was 5; sometimes missed carrier */
289 	dh = open(dev,2);
290 	xalarm(0);
291 	if (dh<0) {
292 		er=(errno == 4? 3:6);
293 		goto X;
294 	}
295 	ioctl(dh, TIOCGETP, &stbuf);
296 	stbuf.sg_flags &= ~ECHO;
297 	xalarm(10);
298 	ioctl(dh, TIOCSETP, &stbuf);
299 	ioctl(dh, TIOCHPCL, (struct sgttyb *)NULL);
300 	xalarm(0);
301 X:
302 	if (er) close(dn);
303 	delock(atail);
304 	if (fk!=(-1)) {
305 		kill(fk, SIGKILL);
306 		xalarm(10);
307 		while ((t=wait((int *)NULL))!=(-1) && t!=fk);
308 		xalarm(0);
309 	}
310 	return (er? -er:dh);
311 }
312 
313 /*
314  *	wr: write to remote: 0 -> line.
315  *	~.	terminate
316  *	~<file	send file
317  *	~!	local login-style shell
318  *	~!cmd	execute cmd locally
319  *	~$proc	execute proc locally, send output to line
320  *	~%cmd	execute builtin cmd (put and take)
321  *	~#	send 1-sec break
322  *	~^Z	suspend cu process.
323  */
324 
325 wr()
326 {
327 	int ds,fk,lcl,x;
328 	char *p,b[600];
329 	for (;;) {
330 		p=b;
331 		while (rdc(0) == 1) {
332 			if (p == b) lcl=(c == '~');
333 			if (p == b+1 && b[0] == '~') lcl=(c!='~');
334 			if (nullbrk && c == 0) oc=c=0177; /* fake break kludge */
335 			if (!lcl) {
336 				if(!pflag)c = oc;
337 				if (wrc(ln) == 0) {
338 					prf("line gone"); return;
339 				}
340 				c &= 0177;
341 			}
342 			if (lcl) {
343 				if (c == 0177) c=tkill;
344 				if (c == '\r' || c == '\n') goto A;
345 				if (!dout) wrc(0);
346 			}
347 			*p++=c;
348 			if (c == terase) {
349 				p=p-2;
350 				if (p<b) p=b;
351 			}
352 			if (c == tkill || c == 0177 || c == '\4' || c == '\r' || c == '\n') p=b;
353 		}
354 		return;
355 A:
356 		if (!dout) echo("");
357 		*p=0;
358 		switch (b[1]) {
359 		case '.':
360 		case '\004':
361 			return;
362 		case '#':
363 			ioctl(ln, TIOCSBRK, 0);
364 			sleep(1);
365 			ioctl(ln, TIOCCBRK, 0);
366 			continue;
367 		case '!':
368 		case '$':
369 			fk = fork();
370 			if (fk == 0) {
371 				char *getenv();
372 				char *shell = getenv("SHELL");
373 				if (shell == 0) shell = "/bin/sh";
374 				close(1);
375 				dup(b[1] == '$'? ln:2);
376 				close(ln);
377 				mode(0);
378 				if (!nhup) signal(SIGINT, SIG_DFL);
379 				if (b[2] == 0) execl(shell,shell,0);
380 				/* if (b[2] == 0) execl(shell,"-",0); */
381 				else execl(shell,"sh","-c",b+2,0);
382 				prf("Can't execute shell");
383 				exit(~0);
384 			}
385 			if (fk!=(-1)) {
386 				while (wait(&x)!=fk);
387 			}
388 			mode(1);
389 			if (b[1] == '!') echo("!");
390 			else {
391 				if (dout) echo("$");
392 			}
393 			break;
394 		case '<':
395 			if (b[2] == 0) break;
396 			if ((ds=open(b+2,0))<0) {
397 				prf("Can't divert %s",b+1);
398 				break;
399 			}
400 			intr=x=0;
401 			mode(2);
402 			if (!nhup) signal(SIGINT, sig2);
403 			while (!intr && rdc(ds) == 1) {
404 				if (wrc(ln) == 0) {
405 					x=1;
406 					break;
407 				}
408 			}
409 			signal(SIGINT, SIG_IGN);
410 			close(ds);
411 			mode(1);
412 			if (x) return;
413 			if (dout) echo("<");
414 			break;
415 		case '>':
416 		case ':':
417 			{
418 			register char *q;
419 
420 			if(pipes[1]==-1) {
421 				prf("Can't tell other demon to divert");
422 				break;
423 			}
424 			q = b+1;
425 			if(*q=='>') q++;
426 			write(pipes[1],q,strlen(q)+1);
427 			if(dbflag) prf("msg to be delivered:"),prf(q);
428 			if (efk != -1) kill(efk,SIGEMT);
429 			}
430 			break;
431 #ifdef SIGTSTP
432 #define CTRLZ	26
433 		case CTRLZ:
434 			mode(0);
435 			kill(getpid(), SIGTSTP);
436 			mode(1);
437 			break;
438 #endif
439 		case '%':
440 			dopercen(&b[2]);
441 			break;
442 		default:
443 			prf("Use `~~' to start line with `~'");
444 		}
445 		continue;
446 	}
447 }
448 
449 dopercen(line)
450 register char *line;
451 {
452 	char *args[10];
453 	register narg, f;
454 	int rcount;
455 	for (narg = 0; narg < 10;) {
456 		while(*line == ' ' || *line == '\t')
457 			line++;
458 		if (*line == '\0')
459 			break;
460 		args[narg++] = line;
461 		while(*line != '\0' && *line != ' ' && *line != '\t')
462 			line++;
463 		if (*line == '\0')
464 			break;
465 		*line++ = '\0';
466 	}
467 	if (equal(args[0], "take")) {
468 		if (narg < 2) {
469 			prf("usage: ~%%take from [to]");
470 			return;
471 		}
472 		if (narg < 3)
473 			args[2] = args[1];
474 		write(pipes[1], ">:/dev/null",sizeof(">:/dev/null"));
475 		if(dbflag) prf("sending take message");
476 		if (efk != -1) kill(efk,SIGEMT);
477 		xsleep(5);
478 		wrln("echo '~>");
479 		wrln(args[2]);
480 		wrln("'; tee /dev/null <");
481 		wrln(args[1]);
482 		wrln(";echo '~>'\n");
483 		return;
484 	} else if (equal(args[0], "put")) {
485 		if (narg < 2) {
486 			prf("usage: ~%%put from [to]");
487 			return;
488 		}
489 		if (narg < 3)
490 			args[2] = args[1];
491 		if ((f = open(args[1], 0)) < 0) {
492 			prf("cannot open: %s", args[1]);
493 			return;
494 		}
495 		wrln("stty -echo;cat >");
496 		wrln(args[2]);
497 		wrln(";stty echo\n");
498 		xsleep(5);
499 		intr = 0;
500 		if (!nhup)
501 			signal(SIGINT, sig2);
502 		mode(2);
503 		rcount = 0;
504 		while(!intr && rdc(f) == 1) {
505 			rcount++;
506 			if (c == tkill || c == terase)
507 				wrln("\\");
508 			if (wrc(ln) != 1) {
509 				xsleep(2);
510 				if (wrc(ln) != 1) {
511 					prf("character missed");
512 					intr = 1;
513 					break;
514 				}
515 			}
516 		}
517 		signal(SIGINT, SIG_IGN);
518 		close(f);
519 		if (intr) {
520 			wrln("\n");
521 			prf("stopped after %d bytes", rcount);
522 		}
523 		wrln("\004");
524 		xsleep(5);
525 		mode(1);
526 		return;
527 	}
528 	prf("~%%%s unknown\n", args[0]);
529 }
530 
531 equal(s1, s2)
532 register char *s1, *s2;
533 {
534 	while (*s1++ == *s2)
535 		if (*s2++ == '\0')
536 			return(1);
537 	return(0);
538 }
539 
540 wrln(s)
541 register char *s;
542 {
543 	while (*s)
544 		write(ln, s++, 1);
545 }
546 /*	chwrsig:  Catch orders from wr process
547  *	to instigate diversion
548  */
549 int whoami;
550 chwrsig(){
551 	int readmsg();
552 	whoami = getpid();
553 	signal(SIGEMT,readmsg);
554 }
555 int ds,slnt,taking;
556 int justrung;
557 readmsg(){
558 	static char dobuff[128], morejunk[256];
559 	int n;
560 	justrung = 1;
561 	signal(SIGEMT,readmsg);
562 	if(dbflag) {
563 		prf("About to read from pipe");
564 	}
565 	n = read(pipes[0],morejunk,256);
566 	if(dbflag) {
567 		prf("diversion mesg recieved is");
568 		prf(morejunk);
569 		prf(CRLF);
570 	}
571 	dodiver(morejunk);
572 }
573 dodiver(msg)
574 char *msg;
575 {
576 	register char *cp = msg;
577 
578 	if (*cp=='>') cp++;
579 	if (*cp==':') {
580 		cp++;
581 		if(*cp==0) {
582 			slnt ^= 1;
583 			return;
584 		} else  {
585 			slnt = 1;
586 		}
587 	}
588 	if (ds >= 0) close(ds);
589 	if (*cp==0) {
590 		slnt = 0;
591 		ds = -1;
592 		return;
593 	}
594 	if (*msg!='>' || (ds=open(cp,1))<0) ds=creat(cp,0644);
595 	lseek(ds, (long)0, 2);
596 	if(ds < 0) prf("Creat failed:"), prf(cp);
597 	if (ds<0) prf("Can't divert %s",cp+1);
598 }
599 
600 
601 /*
602  *	rd: read from remote: line -> 1
603  *	catch: diversion caught by interrupt routine
604  */
605 
606 #define ORDIN 0
607 #define SAWCR 1
608 #define EOL   2
609 #define SAWTL 3
610 #define DIVER 4
611 
612 rd()
613 {
614 	extern int ds,slnt;
615 	char rb[600], lb[600], *rlim, *llim, c;
616 	register char *p,*q;
617 	int cnt, state = 0, mustecho, oldslnt;
618 
619 	ds=(-1);
620 	p = lb; llim = lb+600;
621 agin:
622 	while((cnt = read(ln,rb,600)) > 0) {
623 		if(!slnt) write(1,rb,cnt);
624 		if(ds < 0) continue;
625 		oldslnt = slnt;
626 		for( q=rb, rlim = rb + cnt - 1; q <= rlim; ) {
627 			c = *q++ & 0177;
628 			if(p < llim) *p++ = c;
629 			switch(state) {
630 			case ORDIN:
631 				if(c=='\r') state = SAWCR;
632 				break;
633 			case SAWCR:
634 				if(c=='\n') {
635 					state = EOL;
636 					p--;
637 					p[-1] = '\n';
638 				} else state = ORDIN;
639 				break;
640 			case EOL:
641 				state = (c=='~' ? SAWTL :
642 					 (c=='\r' ? SAWCR : ORDIN));
643 				break;
644 			case SAWTL:
645 				state = (c=='>' ? DIVER :
646 					 (c=='\r' ? SAWCR : ORDIN));
647 				break;
648 			case DIVER:
649 				if(c=='\r') {
650 					p--;
651 				} else if (c=='\n') {
652 					state = ORDIN;
653 					p[-1] = 0;
654 					dodiver(lb+2);
655 					c = 0; p = lb;
656 				}
657 			}
658 			if(slnt==0 && oldslnt) {
659 				if(c=='\n') {
660 					write(ln,lb,p-lb-1);
661 					write(ln,CRLF,sizeof(CRLF));
662 				} else if(q==rlim) {
663 					write(ln,lb,p-lb);
664 					c = '\n';  /*force flush to file*/
665 				}
666 			}
667 			if(c=='\n') {
668 				if(ds >= 0)
669 					write(ds,lb,p-lb);
670 				p = lb;
671 			}
672 		}
673 	}
674 	if(justrung) {
675 		justrung = 0;
676 		goto agin;
677 	}
678 }
679 
680 struct {char lobyte; char hibyte;};
681 mode(f)
682 {
683 	struct sgttyb stbuf;
684 	if (dout) return;
685 	ioctl(0, TIOCGETP, &stbuf);
686 	tkill = stbuf.sg_kill;
687 	terase = stbuf.sg_erase;
688 	if (f == 0) {
689 		stbuf.sg_flags &= ~RAW;
690 		stbuf.sg_flags |= ECHO|CRMOD;
691 	}
692 	if (f == 1) {
693 		stbuf.sg_flags |= RAW;
694 		stbuf.sg_flags &= ~(ECHO|CRMOD);
695 	}
696 	if (f == 2) {
697 		stbuf.sg_flags &= ~RAW;
698 		stbuf.sg_flags &= ~(ECHO|CRMOD);
699 	}
700 	ioctl(0, TIOCSETP, &stbuf);
701 }
702 
703 echo(s)
704 char *s;
705 {
706 	char *p;
707 	for (p=s;*p;p++);
708 	if (p>s) write(0,s,p-s);
709 	write(0,CRLF, sizeof(CRLF));
710 }
711 
712 prf(f, s)
713 char *f;
714 char *s;
715 {
716 	fprintf(stderr, f, s);
717 	fprintf(stderr, CRLF);
718 }
719 
720 exists(devname)
721 char *devname;
722 {
723 	if (access(devname, 0)==0)
724 		return(1);
725 	prf("%s does not exist", devname);
726 	return(0);
727 }
728 
729 cleanup(code)
730 {
731 	rmlock(NULL);
732 	exit(code);
733 }
734 
735 /*
736  * This code is taken directly from uucp and follows the same
737  * conventions.  This is important since uucp and cu should
738  * respect each others locks.
739  */
740 
741 	/*  ulockf 3.2  10/26/79  11:40:29  */
742 /* #include "uucp.h" */
743 #include <sys/types.h>
744 #include <sys/stat.h>
745 
746 
747 
748 /*******
749  *	ulockf(file, atime)
750  *	char *file;
751  *	time_t atime;
752  *
753  *	ulockf  -  this routine will create a lock file (file).
754  *	If one already exists, the create time is checked for
755  *	older than the age time (atime).
756  *	If it is older, an attempt will be made to unlink it
757  *	and create a new one.
758  *
759  *	return codes:  0  |  FAIL
760  */
761 
762 ulockf(file, atime)
763 char *file;
764 time_t atime;
765 {
766 	struct stat stbuf;
767 	time_t ptime;
768 	int ret;
769 	static int pid = -1;
770 	static char tempfile[NAMESIZE];
771 
772 	if (pid < 0) {
773 		pid = getpid();
774 		sprintf(tempfile, "/usr/spool/uucp/LTMP.%d", pid);
775 	}
776 	if (onelock(pid, tempfile, file) == -1) {
777 		/* lock file exists */
778 		/* get status to check age of the lock file */
779 		ret = stat(file, &stbuf);
780 		if (ret != -1) {
781 			time(&ptime);
782 			if ((ptime - stbuf.st_ctime) < atime) {
783 				/* file not old enough to delete */
784 				return(FAIL);
785 			}
786 		}
787 		ret = unlink(file);
788 		ret = onelock(pid, tempfile, file);
789 		if (ret != 0)
790 			return(FAIL);
791 	}
792 	stlock(file);
793 	return(0);
794 }
795 
796 
797 #define MAXLOCKS 10	/* maximum number of lock files */
798 char *Lockfile[MAXLOCKS];
799 int Nlocks = 0;
800 
801 /***
802  *	stlock(name)	put name in list of lock files
803  *	char *name;
804  *
805  *	return codes:  none
806  */
807 
808 stlock(name)
809 char *name;
810 {
811 	char *p;
812 	extern char *calloc();
813 	int i;
814 
815 	for (i = 0; i < Nlocks; i++) {
816 		if (Lockfile[i] == NULL)
817 			break;
818 	}
819 	ASSERT(i < MAXLOCKS, "TOO MANY LOCKS %d", i);
820 	if (i >= Nlocks)
821 		i = Nlocks++;
822 	p = calloc(strlen(name) + 1, sizeof (char));
823 	ASSERT(p != NULL, "CAN NOT ALLOCATE FOR %s", name);
824 	strcpy(p, name);
825 	Lockfile[i] = p;
826 	return;
827 }
828 
829 
830 /***
831  *	rmlock(name)	remove all lock files in list
832  *	char *name;	or name
833  *
834  *	return codes: none
835  */
836 
837 rmlock(name)
838 char *name;
839 {
840 	int i;
841 
842 	for (i = 0; i < Nlocks; i++) {
843 		if (Lockfile[i] == NULL)
844 			continue;
845 		if (name == NULL
846 		|| strcmp(name, Lockfile[i]) == SAME) {
847 			unlink(Lockfile[i]);
848 			free(Lockfile[i]);
849 			Lockfile[i] = NULL;
850 		}
851 	}
852 	return;
853 }
854 
855 
856 /*  this stuff from pjw  */
857 /*  /usr/pjw/bin/recover - check pids to remove unnecessary locks */
858 /*	isalock(name) returns 0 if the name is a lock */
859 /*	unlock(name)  unlocks name if it is a lock*/
860 /*	onelock(pid,tempfile,name) makes lock a name
861 	on behalf of pid.  Tempfile must be in the same
862 	file system as name. */
863 /*	lock(pid,tempfile,names) either locks all the
864 	names or none of them */
865 isalock(name) char *name;
866 {
867 	struct stat xstat;
868 	if(stat(name,&xstat)<0) return(0);
869 	if(xstat.st_size!=sizeof(int)) return(0);
870 	return(1);
871 }
872 unlock(name) char *name;
873 {
874 	if(isalock(name)) return(unlink(name));
875 	else return(-1);
876 }
877 onelock(pid,tempfile,name) char *tempfile,*name;
878 {	int fd;
879 	fd=creat(tempfile,0444);
880 	if(fd<0) return(-1);
881 	write(fd,(char *) &pid,sizeof(int));
882 	close(fd);
883 	if(link(tempfile,name)<0)
884 	{	unlink(tempfile);
885 		return(-1);
886 	}
887 	unlink(tempfile);
888 	return(0);
889 }
890 lock(pid,tempfile,names) char *tempfile,**names;
891 {	int i,j;
892 	for(i=0;names[i]!=0;i++)
893 	{	if(onelock(pid,tempfile,names[i])==0) continue;
894 		for(j=0;j<i;j++) unlink(names[j]);
895 		return(-1);
896 	}
897 	return(0);
898 }
899 
900 #define LOCKPRE "/usr/spool/uucp/LCK."
901 
902 /***
903  *	delock(s)	remove a lock file
904  *	char *s;
905  *
906  *	return codes:  0  |  FAIL
907  */
908 
909 delock(s)
910 char *s;
911 {
912 	char ln[30];
913 
914 	sprintf(ln, "%s.%s", LOCKPRE, s);
915 	rmlock(ln);
916 }
917 
918 
919 /***
920  *	mlock(sys)	create system lock
921  *	char *sys;
922  *
923  *	return codes:  0  |  FAIL
924  */
925 
926 mlock(sys)
927 char *sys;
928 {
929 	char lname[30];
930 	sprintf(lname, "%s.%s", LOCKPRE, sys);
931 	return(ulockf(lname, (time_t) SLCKTIME ) < 0 ? FAIL : 0);
932 }
933 
934 
935 
936 /***
937  *	ultouch()	update access and modify times for lock files
938  *
939  *	return code - none
940  */
941 
942 ultouch()
943 {
944 	time_t time();
945 	int i;
946 	struct ut {
947 		time_t actime;
948 		time_t modtime;
949 	} ut;
950 
951 	ut.actime = time(&ut.modtime);
952 	for (i = 0; i < Nlocks; i++) {
953 		if (Lockfile[i] == NULL)
954 			continue;
955 		utime(Lockfile[i], &ut);
956 	}
957 	return;
958 }
959