now uses vfork instead for fork, also has central routine
[unix-history] / usr / src / old / cu / cu.c
CommitLineData
6f9f1b0c
KM
1static char *sccsid = "@(#)cu.c 4.7 (Berkeley) 82/10/21";
2
fb5d50d1
BJ
3#include <stdio.h>
4#include <signal.h>
5#include <sgtty.h>
50402a01
MH
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
fb5d50d1 20/*
6f9f1b0c 21 * cu telno [-t] [-s speed] [-l line] [-a acu] [-p]
fb5d50d1
BJ
22 *
23 * -t is for dial-out to terminal.
6f9f1b0c
KM
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)
fb5d50d1
BJ
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
42char *devcul = "/dev/cul0";
43char *devcua = "/dev/cua0";
44char *lspeed = "300";
45
46int ln; /* fd for comm line */
47char tkill, terase; /* current input kill & erase */
48int efk; /* process of id of listener */
49char c;
50char oc;
51
52char *connmsg[] = {
53 "",
54 "line busy",
55 "call dropped",
56 "no carrier",
57 "can't fork",
58 "acu access",
59 "tty access",
60 "tty hung",
50402a01
MH
61 "usage: cu telno [-t] [-s speed] [-l line] [-a acu]",
62 "lock failed: line busy"
fb5d50d1
BJ
63};
64
65rdc(ds) {
66
67 ds=read(ds,&c,1);
68 oc = c;
69 c &= 0177;
70 return (ds);
71}
72
73int intr;
74
75sig2()
76{
77 signal(SIGINT, SIG_IGN);
78 intr = 1;
79}
80
81int set14;
82
83xsleep(n)
84{
85 xalarm(n);
86 pause();
87 xalarm(0);
88}
89
90xalarm(n)
91{
92 set14=n;
93 alarm(n);
94}
95
96sig14()
97{
98 signal(SIGALRM, sig14);
99 if (set14) alarm(1);
100}
101
102int dout;
103int nhup;
104int dbflag;
6f9f1b0c 105int pflag; /* strip parity on chars sent to remote */
50402a01 106int nullbrk; /* turn breaks (nulls) into dels */
6f9f1b0c 107int pipes[2] = { -1, -1 };
fb5d50d1
BJ
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 */
114main(ac,av)
115char *av[];
116{
117 int fk;
118 int speed;
119 char *telno;
120 struct sgttyb stbuf;
5de5487c 121 int cleanup();
fb5d50d1
BJ
122
123 signal(SIGALRM, sig14);
5de5487c
BJ
124 signal(SIGINT, cleanup);
125 signal(SIGHUP, cleanup);
126 signal(SIGQUIT, cleanup);
fb5d50d1
BJ
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;
50402a01
MH
139 case 'b':
140 nullbrk++;
141 continue;
fb5d50d1
BJ
142 case 'd':
143 dbflag++;
144 continue;
6f9f1b0c
KM
145 case 'p':
146 pflag++;
147 continue;
fb5d50d1
BJ
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]);
50402a01 172 cleanup(-ln);
fb5d50d1
BJ
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;
6f9f1b0c
KM
184 case 2400:
185 speed = B2400;break;
fb5d50d1
BJ
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");
6f9f1b0c 198 pipe(pipes);
fb5d50d1 199 if (dout)
391f3aab 200 fk = -1;
fb5d50d1
BJ
201 else
202 fk = fork();
203 nhup = (int)signal(SIGINT, SIG_IGN);
204 if (fk == 0) {
205 chwrsig();
206 rd();
207 prf("\007Lost carrier");
50402a01 208 cleanup(3);
fb5d50d1
BJ
209 }
210 mode(1);
211 efk = fk;
212 wr();
213 mode(0);
dc03ac0b 214 if (fk != -1) kill(fk, SIGKILL);
fb5d50d1
BJ
215 wait((int *)NULL);
216 stbuf.sg_ispeed = 0;
217 stbuf.sg_ospeed = 0;
218 ioctl(ln, TIOCSETP, &stbuf);
219 prf("Disconnected");
50402a01 220 cleanup(0);
fb5d50d1
BJ
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
232conn(dev,acu,telno)
233char *dev, *acu, *telno;
234{
235 struct sgttyb stbuf;
236 extern errno;
237 char *p, *q, b[30];
50402a01
MH
238 char *ltail, *atail;
239 char *rindex();
fb5d50d1
BJ
240 int er, fk, dn, dh, t;
241 er=0;
242 fk=(-1);
50402a01
MH
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 }
fb5d50d1
BJ
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 }
50402a01 295 ioctl(dh, TIOCGETP, &stbuf);
fb5d50d1
BJ
296 stbuf.sg_flags &= ~ECHO;
297 xalarm(10);
298 ioctl(dh, TIOCSETP, &stbuf);
299 ioctl(dh, TIOCHPCL, (struct sgttyb *)NULL);
300 xalarm(0);
301X:
302 if (er) close(dn);
50402a01 303 delock(atail);
fb5d50d1
BJ
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
50402a01 322 * ~^Z suspend cu process.
fb5d50d1
BJ
323 */
324
325wr()
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!='~');
50402a01 334 if (nullbrk && c == 0) oc=c=0177; /* fake break kludge */
fb5d50d1 335 if (!lcl) {
6f9f1b0c 336 if(!pflag)c = oc;
fb5d50d1
BJ
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;
355A:
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 {
6f9f1b0c
KM
418 register char *q;
419
420 if(pipes[1]==-1) {
fb5d50d1
BJ
421 prf("Can't tell other demon to divert");
422 break;
423 }
6f9f1b0c
KM
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);
dc03ac0b 428 if (efk != -1) kill(efk,SIGEMT);
fb5d50d1
BJ
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
449dopercen(line)
450register 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];
6f9f1b0c
KM
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 '~>");
fb5d50d1 479 wrln(args[2]);
6f9f1b0c 480 wrln("'; tee /dev/null <");
fb5d50d1
BJ
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
531equal(s1, s2)
532register char *s1, *s2;
533{
534 while (*s1++ == *s2)
535 if (*s2++ == '\0')
536 return(1);
537 return(0);
538}
539
540wrln(s)
541register char *s;
542{
543 while (*s)
544 write(ln, s++, 1);
545}
546/* chwrsig: Catch orders from wr process
547 * to instigate diversion
548 */
549int whoami;
550chwrsig(){
6f9f1b0c 551 int readmsg();
fb5d50d1 552 whoami = getpid();
6f9f1b0c 553 signal(SIGEMT,readmsg);
fb5d50d1 554}
6f9f1b0c 555int ds,slnt,taking;
fb5d50d1 556int justrung;
6f9f1b0c
KM
557readmsg(){
558 static char dobuff[128], morejunk[256];
559 int n;
fb5d50d1 560 justrung = 1;
6f9f1b0c 561 signal(SIGEMT,readmsg);
fb5d50d1 562 if(dbflag) {
6f9f1b0c 563 prf("About to read from pipe");
fb5d50d1 564 }
6f9f1b0c 565 n = read(pipes[0],morejunk,256);
fb5d50d1 566 if(dbflag) {
6f9f1b0c
KM
567 prf("diversion mesg recieved is");
568 prf(morejunk);
569 prf(CRLF);
fb5d50d1 570 }
6f9f1b0c
KM
571 dodiver(morejunk);
572}
573dodiver(msg)
574char *msg;
575{
576 register char *cp = msg;
577
fb5d50d1
BJ
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 }
6f9f1b0c 594 if (*msg!='>' || (ds=open(cp,1))<0) ds=creat(cp,0644);
fb5d50d1
BJ
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
6f9f1b0c 603 * catch: diversion caught by interrupt routine
fb5d50d1
BJ
604 */
605
6f9f1b0c
KM
606#define ORDIN 0
607#define SAWCR 1
608#define EOL 2
609#define SAWTL 3
610#define DIVER 4
611
fb5d50d1
BJ
612rd()
613{
614 extern int ds,slnt;
6f9f1b0c
KM
615 char rb[600], lb[600], *rlim, *llim, c;
616 register char *p,*q;
617 int cnt, state = 0, mustecho, oldslnt;
618
fb5d50d1 619 ds=(-1);
6f9f1b0c 620 p = lb; llim = lb+600;
fb5d50d1 621agin:
6f9f1b0c
KM
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;
fb5d50d1 671 }
fb5d50d1 672 }
fb5d50d1
BJ
673 }
674 if(justrung) {
675 justrung = 0;
676 goto agin;
677 }
678}
679
680struct {char lobyte; char hibyte;};
681mode(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
703echo(s)
704char *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
712prf(f, s)
713char *f;
714char *s;
715{
716 fprintf(stderr, f, s);
717 fprintf(stderr, CRLF);
718}
719
720exists(devname)
721char *devname;
722{
723 if (access(devname, 0)==0)
724 return(1);
725 prf("%s does not exist", devname);
726 return(0);
727}
50402a01
MH
728
729cleanup(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
762ulockf(file, atime)
763char *file;
764time_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 */
798char *Lockfile[MAXLOCKS];
799int Nlocks = 0;
800
801/***
802 * stlock(name) put name in list of lock files
803 * char *name;
804 *
805 * return codes: none
806 */
807
808stlock(name)
809char *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
837rmlock(name)
838char *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 */
865isalock(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}
872unlock(name) char *name;
873{
874 if(isalock(name)) return(unlink(name));
875 else return(-1);
876}
877onelock(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}
890lock(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
909delock(s)
910char *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
926mlock(sys)
927char *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
942ultouch()
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}