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