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