1*8788Smckusick static char *sccsid = "@(#)cu.c 4.7 (Berkeley) 82/10/21";
2*8788Smckusick
3996Sbill #include <stdio.h>
4996Sbill #include <signal.h>
5996Sbill #include <sgtty.h>
62370Smark
7996Sbill /*
82370Smark * defs that come from uucp.h
92370Smark */
102370Smark #define NAMESIZE 15
112370Smark #define FAIL -1
122370Smark #define SAME 0
132370Smark #define SLCKTIME 5400 /* system/device timeout (LCK.. files) in seconds */
142370Smark #define ASSERT(e, f, v) if (!(e)) {\
152370Smark fprintf(stderr, "AERROR - (%s) ", "e");\
162370Smark fprintf(stderr, f, v);\
172370Smark cleanup(FAIL);\
182370Smark }
192370Smark
202370Smark /*
21*8788Smckusick * cu telno [-t] [-s speed] [-l line] [-a acu] [-p]
22996Sbill *
23996Sbill * -t is for dial-out to terminal.
24*8788Smckusick * speeds are: 110, 134, 150, 300, 1200, 2400. 300 is default.
25996Sbill *
26*8788Smckusick * -p says strip parity of characters transmitted. (to compensate
27*8788Smckusick * for c100's)
28*8788Smckusick *
29996Sbill * Escape with `~' at beginning of line.
30996Sbill * Ordinary diversions are ~<, ~> and ~>>.
31996Sbill * Silent output diversions are ~>: and ~>>:.
32996Sbill * Terminate output diversion with ~> alone.
33996Sbill * Quit is ~. and ~! gives local command or shell.
34996Sbill * Also ~$ for canned procedure pumping remote.
35996Sbill * ~%put from [to] and ~%take from [to] invoke builtins
36996Sbill */
37996Sbill
38996Sbill #define CRLF "\r\n"
39996Sbill #define wrc(ds) write(ds,&c,1)
40996Sbill
41996Sbill
42996Sbill char *devcul = "/dev/cul0";
43996Sbill char *devcua = "/dev/cua0";
44996Sbill char *lspeed = "300";
45996Sbill
46996Sbill int ln; /* fd for comm line */
47996Sbill char tkill, terase; /* current input kill & erase */
48996Sbill int efk; /* process of id of listener */
49996Sbill char c;
50996Sbill char oc;
51996Sbill
52996Sbill char *connmsg[] = {
53996Sbill "",
54996Sbill "line busy",
55996Sbill "call dropped",
56996Sbill "no carrier",
57996Sbill "can't fork",
58996Sbill "acu access",
59996Sbill "tty access",
60996Sbill "tty hung",
612370Smark "usage: cu telno [-t] [-s speed] [-l line] [-a acu]",
622370Smark "lock failed: line busy"
63996Sbill };
64996Sbill
rdc(ds)65996Sbill rdc(ds) {
66996Sbill
67996Sbill ds=read(ds,&c,1);
68996Sbill oc = c;
69996Sbill c &= 0177;
70996Sbill return (ds);
71996Sbill }
72996Sbill
73996Sbill int intr;
74996Sbill
sig2()75996Sbill sig2()
76996Sbill {
77996Sbill signal(SIGINT, SIG_IGN);
78996Sbill intr = 1;
79996Sbill }
80996Sbill
81996Sbill int set14;
82996Sbill
xsleep(n)83996Sbill xsleep(n)
84996Sbill {
85996Sbill xalarm(n);
86996Sbill pause();
87996Sbill xalarm(0);
88996Sbill }
89996Sbill
xalarm(n)90996Sbill xalarm(n)
91996Sbill {
92996Sbill set14=n;
93996Sbill alarm(n);
94996Sbill }
95996Sbill
sig14()96996Sbill sig14()
97996Sbill {
98996Sbill signal(SIGALRM, sig14);
99996Sbill if (set14) alarm(1);
100996Sbill }
101996Sbill
102996Sbill int dout;
103996Sbill int nhup;
104996Sbill int dbflag;
105*8788Smckusick int pflag; /* strip parity on chars sent to remote */
1062370Smark int nullbrk; /* turn breaks (nulls) into dels */
107*8788Smckusick int pipes[2] = { -1, -1 };
108996Sbill
109996Sbill /*
110996Sbill * main: get connection, set speed for line.
111996Sbill * spawn child to invoke rd to read from line, output to fd 1
112996Sbill * main line invokes wr to read tty, write to line
113996Sbill */
main(ac,av)114996Sbill main(ac,av)
115996Sbill char *av[];
116996Sbill {
117996Sbill int fk;
118996Sbill int speed;
119996Sbill char *telno;
120996Sbill struct sgttyb stbuf;
1212791Swnj int cleanup();
122996Sbill
123996Sbill signal(SIGALRM, sig14);
1242791Swnj signal(SIGINT, cleanup);
1252791Swnj signal(SIGHUP, cleanup);
1262791Swnj signal(SIGQUIT, cleanup);
127996Sbill if (ac < 2) {
128996Sbill prf(connmsg[8]);
129996Sbill exit(8);
130996Sbill }
131996Sbill for (; ac > 1; av++,ac--) {
132996Sbill if (av[1][0] != '-')
133996Sbill telno = av[1];
134996Sbill else switch(av[1][1]) {
135996Sbill case 't':
136996Sbill dout = 1;
137996Sbill --ac;
138996Sbill continue;
1392370Smark case 'b':
1402370Smark nullbrk++;
1412370Smark continue;
142996Sbill case 'd':
143996Sbill dbflag++;
144996Sbill continue;
145*8788Smckusick case 'p':
146*8788Smckusick pflag++;
147*8788Smckusick continue;
148996Sbill case 's':
149996Sbill lspeed = av[2]; ++av; --ac;
150996Sbill break;
151996Sbill case 'l':
152996Sbill devcul = av[2]; ++av; --ac;
153996Sbill break;
154996Sbill case 'a':
155996Sbill devcua = av[2]; ++av; --ac;
156996Sbill break;
157996Sbill case '0': case '1': case '2': case '3': case '4':
158996Sbill case '5': case '6': case '7': case '8': case '9':
159996Sbill devcua[strlen(devcua)-1] = av[1][1];
160996Sbill devcul[strlen(devcul)-1] = av[1][1];
161996Sbill break;
162996Sbill default:
163996Sbill prf("Bad flag %s", av[1]);
164996Sbill break;
165996Sbill }
166996Sbill }
167996Sbill if (!exists(devcua) || !exists(devcul))
168996Sbill exit(9);
169996Sbill ln = conn(devcul, devcua, telno);
170996Sbill if (ln < 0) {
171996Sbill prf("Connect failed: %s",connmsg[-ln]);
1722370Smark cleanup(-ln);
173996Sbill }
174996Sbill switch(atoi(lspeed)) {
175996Sbill case 110:
176996Sbill speed = B110;break;
177996Sbill case 150:
178996Sbill speed = B150;break;
179996Sbill default:
180996Sbill case 300:
181996Sbill speed = B300;break;
182996Sbill case 1200:
183996Sbill speed = B1200;break;
184*8788Smckusick case 2400:
185*8788Smckusick speed = B2400;break;
186996Sbill }
187996Sbill stbuf.sg_ispeed = speed;
188996Sbill stbuf.sg_ospeed = speed;
189996Sbill stbuf.sg_flags = EVENP|ODDP;
190996Sbill if (!dout) {
191996Sbill stbuf.sg_flags |= RAW;
192996Sbill stbuf.sg_flags &= ~ECHO;
193996Sbill }
194996Sbill ioctl(ln, TIOCSETP, &stbuf);
195996Sbill ioctl(ln, TIOCEXCL, (struct sgttyb *)NULL);
196996Sbill ioctl(ln, TIOCHPCL, (struct sgttyb *)NULL);
197996Sbill prf("Connected");
198*8788Smckusick pipe(pipes);
199996Sbill if (dout)
2003926Sbugs fk = -1;
201996Sbill else
202996Sbill fk = fork();
203996Sbill nhup = (int)signal(SIGINT, SIG_IGN);
204996Sbill if (fk == 0) {
205996Sbill chwrsig();
206996Sbill rd();
207996Sbill prf("\007Lost carrier");
2082370Smark cleanup(3);
209996Sbill }
210996Sbill mode(1);
211996Sbill efk = fk;
212996Sbill wr();
213996Sbill mode(0);
2143924Sroot if (fk != -1) kill(fk, SIGKILL);
215996Sbill wait((int *)NULL);
216996Sbill stbuf.sg_ispeed = 0;
217996Sbill stbuf.sg_ospeed = 0;
218996Sbill ioctl(ln, TIOCSETP, &stbuf);
219996Sbill prf("Disconnected");
2202370Smark cleanup(0);
221996Sbill }
222996Sbill
223996Sbill /*
224996Sbill * conn: establish dial-out connection.
225996Sbill * Example: fd = conn("/dev/ttyh","/dev/dn1","4500");
226996Sbill * Returns descriptor open to tty for reading and writing.
227996Sbill * Negative values (-1...-7) denote errors in connmsg.
228996Sbill * Uses alarm and fork/wait; requires sig14 handler.
229996Sbill * Be sure to disconnect tty when done, via HUPCL or stty 0.
230996Sbill */
231996Sbill
conn(dev,acu,telno)232996Sbill conn(dev,acu,telno)
233996Sbill char *dev, *acu, *telno;
234996Sbill {
235996Sbill struct sgttyb stbuf;
236996Sbill extern errno;
237996Sbill char *p, *q, b[30];
2382370Smark char *ltail, *atail;
2392370Smark char *rindex();
240996Sbill int er, fk, dn, dh, t;
241996Sbill er=0;
242996Sbill fk=(-1);
2432370Smark atail = rindex(acu, '/')+1;
2442370Smark if (mlock(atail) == FAIL) {
2452370Smark er = 9;
2462370Smark goto X;
2472370Smark }
2482370Smark ltail = rindex(dev, '/')+1;
2492370Smark if (mlock(ltail) == FAIL) {
2502370Smark er = 9;
2512370Smark delock(atail);
2522370Smark goto X;
2532370Smark }
254996Sbill if ((dn=open(acu,1))<0) {
255996Sbill er=(errno == 6? 1:5);
256996Sbill goto X;
257996Sbill }
258996Sbill if ((fk=fork()) == (-1)) {
259996Sbill er=4;
260996Sbill goto X;
261996Sbill }
262996Sbill if (fk == 0) {
263996Sbill open(dev,2);
264996Sbill for (;;) pause();
265996Sbill }
266996Sbill xsleep(2);
267996Sbill /*
268996Sbill * copy phone #, assure EON
269996Sbill */
270996Sbill p=b;
271996Sbill q=telno;
272996Sbill while (*p++=(*q++))
273996Sbill ;
274996Sbill p--;
275996Sbill if (*(p-1)!='<') {
276996Sbill /*if (*(p-1)!='-') *p++='-';*/
277996Sbill *p++='<';
278996Sbill }
279996Sbill t=p-b;
280996Sbill xalarm(5*t);
281996Sbill t=write(dn,b,t);
282996Sbill xalarm(0);
283996Sbill if (t<0) {
284996Sbill er=2;
285996Sbill goto X;
286996Sbill }
287996Sbill /* close(dn) */
288996Sbill xalarm(40); /* was 5; sometimes missed carrier */
289996Sbill dh = open(dev,2);
290996Sbill xalarm(0);
291996Sbill if (dh<0) {
292996Sbill er=(errno == 4? 3:6);
293996Sbill goto X;
294996Sbill }
2952370Smark ioctl(dh, TIOCGETP, &stbuf);
296996Sbill stbuf.sg_flags &= ~ECHO;
297996Sbill xalarm(10);
298996Sbill ioctl(dh, TIOCSETP, &stbuf);
299996Sbill ioctl(dh, TIOCHPCL, (struct sgttyb *)NULL);
300996Sbill xalarm(0);
301996Sbill X:
302996Sbill if (er) close(dn);
3032370Smark delock(atail);
304996Sbill if (fk!=(-1)) {
305996Sbill kill(fk, SIGKILL);
306996Sbill xalarm(10);
307996Sbill while ((t=wait((int *)NULL))!=(-1) && t!=fk);
308996Sbill xalarm(0);
309996Sbill }
310996Sbill return (er? -er:dh);
311996Sbill }
312996Sbill
313996Sbill /*
314996Sbill * wr: write to remote: 0 -> line.
315996Sbill * ~. terminate
316996Sbill * ~<file send file
317996Sbill * ~! local login-style shell
318996Sbill * ~!cmd execute cmd locally
319996Sbill * ~$proc execute proc locally, send output to line
320996Sbill * ~%cmd execute builtin cmd (put and take)
321996Sbill * ~# send 1-sec break
3222370Smark * ~^Z suspend cu process.
323996Sbill */
324996Sbill
wr()325996Sbill wr()
326996Sbill {
327996Sbill int ds,fk,lcl,x;
328996Sbill char *p,b[600];
329996Sbill for (;;) {
330996Sbill p=b;
331996Sbill while (rdc(0) == 1) {
332996Sbill if (p == b) lcl=(c == '~');
333996Sbill if (p == b+1 && b[0] == '~') lcl=(c!='~');
3342370Smark if (nullbrk && c == 0) oc=c=0177; /* fake break kludge */
335996Sbill if (!lcl) {
336*8788Smckusick if(!pflag)c = oc;
337996Sbill if (wrc(ln) == 0) {
338996Sbill prf("line gone"); return;
339996Sbill }
340996Sbill c &= 0177;
341996Sbill }
342996Sbill if (lcl) {
343996Sbill if (c == 0177) c=tkill;
344996Sbill if (c == '\r' || c == '\n') goto A;
345996Sbill if (!dout) wrc(0);
346996Sbill }
347996Sbill *p++=c;
348996Sbill if (c == terase) {
349996Sbill p=p-2;
350996Sbill if (p<b) p=b;
351996Sbill }
352996Sbill if (c == tkill || c == 0177 || c == '\4' || c == '\r' || c == '\n') p=b;
353996Sbill }
354996Sbill return;
355996Sbill A:
356996Sbill if (!dout) echo("");
357996Sbill *p=0;
358996Sbill switch (b[1]) {
359996Sbill case '.':
360996Sbill case '\004':
361996Sbill return;
362996Sbill case '#':
363996Sbill ioctl(ln, TIOCSBRK, 0);
364996Sbill sleep(1);
365996Sbill ioctl(ln, TIOCCBRK, 0);
366996Sbill continue;
367996Sbill case '!':
368996Sbill case '$':
369996Sbill fk = fork();
370996Sbill if (fk == 0) {
371996Sbill char *getenv();
372996Sbill char *shell = getenv("SHELL");
373996Sbill if (shell == 0) shell = "/bin/sh";
374996Sbill close(1);
375996Sbill dup(b[1] == '$'? ln:2);
376996Sbill close(ln);
377996Sbill mode(0);
378996Sbill if (!nhup) signal(SIGINT, SIG_DFL);
379996Sbill if (b[2] == 0) execl(shell,shell,0);
380996Sbill /* if (b[2] == 0) execl(shell,"-",0); */
381996Sbill else execl(shell,"sh","-c",b+2,0);
382996Sbill prf("Can't execute shell");
383996Sbill exit(~0);
384996Sbill }
385996Sbill if (fk!=(-1)) {
386996Sbill while (wait(&x)!=fk);
387996Sbill }
388996Sbill mode(1);
389996Sbill if (b[1] == '!') echo("!");
390996Sbill else {
391996Sbill if (dout) echo("$");
392996Sbill }
393996Sbill break;
394996Sbill case '<':
395996Sbill if (b[2] == 0) break;
396996Sbill if ((ds=open(b+2,0))<0) {
397996Sbill prf("Can't divert %s",b+1);
398996Sbill break;
399996Sbill }
400996Sbill intr=x=0;
401996Sbill mode(2);
402996Sbill if (!nhup) signal(SIGINT, sig2);
403996Sbill while (!intr && rdc(ds) == 1) {
404996Sbill if (wrc(ln) == 0) {
405996Sbill x=1;
406996Sbill break;
407996Sbill }
408996Sbill }
409996Sbill signal(SIGINT, SIG_IGN);
410996Sbill close(ds);
411996Sbill mode(1);
412996Sbill if (x) return;
413996Sbill if (dout) echo("<");
414996Sbill break;
415996Sbill case '>':
416996Sbill case ':':
417996Sbill {
418*8788Smckusick register char *q;
419*8788Smckusick
420*8788Smckusick if(pipes[1]==-1) {
421996Sbill prf("Can't tell other demon to divert");
422996Sbill break;
423996Sbill }
424*8788Smckusick q = b+1;
425*8788Smckusick if(*q=='>') q++;
426*8788Smckusick write(pipes[1],q,strlen(q)+1);
427*8788Smckusick if(dbflag) prf("msg to be delivered:"),prf(q);
4283924Sroot if (efk != -1) kill(efk,SIGEMT);
429996Sbill }
430996Sbill break;
431996Sbill #ifdef SIGTSTP
432996Sbill #define CTRLZ 26
433996Sbill case CTRLZ:
434996Sbill mode(0);
435996Sbill kill(getpid(), SIGTSTP);
436996Sbill mode(1);
437996Sbill break;
438996Sbill #endif
439996Sbill case '%':
440996Sbill dopercen(&b[2]);
441996Sbill break;
442996Sbill default:
443996Sbill prf("Use `~~' to start line with `~'");
444996Sbill }
445996Sbill continue;
446996Sbill }
447996Sbill }
448996Sbill
dopercen(line)449996Sbill dopercen(line)
450996Sbill register char *line;
451996Sbill {
452996Sbill char *args[10];
453996Sbill register narg, f;
454996Sbill int rcount;
455996Sbill for (narg = 0; narg < 10;) {
456996Sbill while(*line == ' ' || *line == '\t')
457996Sbill line++;
458996Sbill if (*line == '\0')
459996Sbill break;
460996Sbill args[narg++] = line;
461996Sbill while(*line != '\0' && *line != ' ' && *line != '\t')
462996Sbill line++;
463996Sbill if (*line == '\0')
464996Sbill break;
465996Sbill *line++ = '\0';
466996Sbill }
467996Sbill if (equal(args[0], "take")) {
468996Sbill if (narg < 2) {
469996Sbill prf("usage: ~%%take from [to]");
470996Sbill return;
471996Sbill }
472996Sbill if (narg < 3)
473996Sbill args[2] = args[1];
474*8788Smckusick write(pipes[1], ">:/dev/null",sizeof(">:/dev/null"));
475*8788Smckusick if(dbflag) prf("sending take message");
476*8788Smckusick if (efk != -1) kill(efk,SIGEMT);
477*8788Smckusick xsleep(5);
478*8788Smckusick wrln("echo '~>");
479996Sbill wrln(args[2]);
480*8788Smckusick wrln("'; tee /dev/null <");
481996Sbill wrln(args[1]);
482996Sbill wrln(";echo '~>'\n");
483996Sbill return;
484996Sbill } else if (equal(args[0], "put")) {
485996Sbill if (narg < 2) {
486996Sbill prf("usage: ~%%put from [to]");
487996Sbill return;
488996Sbill }
489996Sbill if (narg < 3)
490996Sbill args[2] = args[1];
491996Sbill if ((f = open(args[1], 0)) < 0) {
492996Sbill prf("cannot open: %s", args[1]);
493996Sbill return;
494996Sbill }
495996Sbill wrln("stty -echo;cat >");
496996Sbill wrln(args[2]);
497996Sbill wrln(";stty echo\n");
498996Sbill xsleep(5);
499996Sbill intr = 0;
500996Sbill if (!nhup)
501996Sbill signal(SIGINT, sig2);
502996Sbill mode(2);
503996Sbill rcount = 0;
504996Sbill while(!intr && rdc(f) == 1) {
505996Sbill rcount++;
506996Sbill if (c == tkill || c == terase)
507996Sbill wrln("\\");
508996Sbill if (wrc(ln) != 1) {
509996Sbill xsleep(2);
510996Sbill if (wrc(ln) != 1) {
511996Sbill prf("character missed");
512996Sbill intr = 1;
513996Sbill break;
514996Sbill }
515996Sbill }
516996Sbill }
517996Sbill signal(SIGINT, SIG_IGN);
518996Sbill close(f);
519996Sbill if (intr) {
520996Sbill wrln("\n");
521996Sbill prf("stopped after %d bytes", rcount);
522996Sbill }
523996Sbill wrln("\004");
524996Sbill xsleep(5);
525996Sbill mode(1);
526996Sbill return;
527996Sbill }
528996Sbill prf("~%%%s unknown\n", args[0]);
529996Sbill }
530996Sbill
equal(s1,s2)531996Sbill equal(s1, s2)
532996Sbill register char *s1, *s2;
533996Sbill {
534996Sbill while (*s1++ == *s2)
535996Sbill if (*s2++ == '\0')
536996Sbill return(1);
537996Sbill return(0);
538996Sbill }
539996Sbill
wrln(s)540996Sbill wrln(s)
541996Sbill register char *s;
542996Sbill {
543996Sbill while (*s)
544996Sbill write(ln, s++, 1);
545996Sbill }
546996Sbill /* chwrsig: Catch orders from wr process
547996Sbill * to instigate diversion
548996Sbill */
549996Sbill int whoami;
chwrsig()550996Sbill chwrsig(){
551*8788Smckusick int readmsg();
552996Sbill whoami = getpid();
553*8788Smckusick signal(SIGEMT,readmsg);
554996Sbill }
555*8788Smckusick int ds,slnt,taking;
556996Sbill int justrung;
readmsg()557*8788Smckusick readmsg(){
558*8788Smckusick static char dobuff[128], morejunk[256];
559*8788Smckusick int n;
560996Sbill justrung = 1;
561*8788Smckusick signal(SIGEMT,readmsg);
562996Sbill if(dbflag) {
563*8788Smckusick prf("About to read from pipe");
564996Sbill }
565*8788Smckusick n = read(pipes[0],morejunk,256);
566996Sbill if(dbflag) {
567*8788Smckusick prf("diversion mesg recieved is");
568*8788Smckusick prf(morejunk);
569*8788Smckusick prf(CRLF);
570996Sbill }
571*8788Smckusick dodiver(morejunk);
572*8788Smckusick }
dodiver(msg)573*8788Smckusick dodiver(msg)
574*8788Smckusick char *msg;
575*8788Smckusick {
576*8788Smckusick register char *cp = msg;
577*8788Smckusick
578996Sbill if (*cp=='>') cp++;
579996Sbill if (*cp==':') {
580996Sbill cp++;
581996Sbill if(*cp==0) {
582996Sbill slnt ^= 1;
583996Sbill return;
584996Sbill } else {
585996Sbill slnt = 1;
586996Sbill }
587996Sbill }
588996Sbill if (ds >= 0) close(ds);
589996Sbill if (*cp==0) {
590996Sbill slnt = 0;
591996Sbill ds = -1;
592996Sbill return;
593996Sbill }
594*8788Smckusick if (*msg!='>' || (ds=open(cp,1))<0) ds=creat(cp,0644);
595996Sbill lseek(ds, (long)0, 2);
596996Sbill if(ds < 0) prf("Creat failed:"), prf(cp);
597996Sbill if (ds<0) prf("Can't divert %s",cp+1);
598996Sbill }
599996Sbill
600996Sbill
601996Sbill /*
602996Sbill * rd: read from remote: line -> 1
603*8788Smckusick * catch: diversion caught by interrupt routine
604996Sbill */
605996Sbill
606*8788Smckusick #define ORDIN 0
607*8788Smckusick #define SAWCR 1
608*8788Smckusick #define EOL 2
609*8788Smckusick #define SAWTL 3
610*8788Smckusick #define DIVER 4
611*8788Smckusick
rd()612996Sbill rd()
613996Sbill {
614996Sbill extern int ds,slnt;
615*8788Smckusick char rb[600], lb[600], *rlim, *llim, c;
616*8788Smckusick register char *p,*q;
617*8788Smckusick int cnt, state = 0, mustecho, oldslnt;
618*8788Smckusick
619996Sbill ds=(-1);
620*8788Smckusick p = lb; llim = lb+600;
621996Sbill agin:
622*8788Smckusick while((cnt = read(ln,rb,600)) > 0) {
623*8788Smckusick if(!slnt) write(1,rb,cnt);
624*8788Smckusick if(ds < 0) continue;
625*8788Smckusick oldslnt = slnt;
626*8788Smckusick for( q=rb, rlim = rb + cnt - 1; q <= rlim; ) {
627*8788Smckusick c = *q++ & 0177;
628*8788Smckusick if(p < llim) *p++ = c;
629*8788Smckusick switch(state) {
630*8788Smckusick case ORDIN:
631*8788Smckusick if(c=='\r') state = SAWCR;
632*8788Smckusick break;
633*8788Smckusick case SAWCR:
634*8788Smckusick if(c=='\n') {
635*8788Smckusick state = EOL;
636*8788Smckusick p--;
637*8788Smckusick p[-1] = '\n';
638*8788Smckusick } else state = ORDIN;
639*8788Smckusick break;
640*8788Smckusick case EOL:
641*8788Smckusick state = (c=='~' ? SAWTL :
642*8788Smckusick (c=='\r' ? SAWCR : ORDIN));
643*8788Smckusick break;
644*8788Smckusick case SAWTL:
645*8788Smckusick state = (c=='>' ? DIVER :
646*8788Smckusick (c=='\r' ? SAWCR : ORDIN));
647*8788Smckusick break;
648*8788Smckusick case DIVER:
649*8788Smckusick if(c=='\r') {
650*8788Smckusick p--;
651*8788Smckusick } else if (c=='\n') {
652*8788Smckusick state = ORDIN;
653*8788Smckusick p[-1] = 0;
654*8788Smckusick dodiver(lb+2);
655*8788Smckusick c = 0; p = lb;
656*8788Smckusick }
657996Sbill }
658*8788Smckusick if(slnt==0 && oldslnt) {
659*8788Smckusick if(c=='\n') {
660*8788Smckusick write(ln,lb,p-lb-1);
661*8788Smckusick write(ln,CRLF,sizeof(CRLF));
662*8788Smckusick } else if(q==rlim) {
663*8788Smckusick write(ln,lb,p-lb);
664*8788Smckusick c = '\n'; /*force flush to file*/
665*8788Smckusick }
666*8788Smckusick }
667*8788Smckusick if(c=='\n') {
668*8788Smckusick if(ds >= 0)
669*8788Smckusick write(ds,lb,p-lb);
670*8788Smckusick p = lb;
671*8788Smckusick }
672996Sbill }
673996Sbill }
674996Sbill if(justrung) {
675996Sbill justrung = 0;
676996Sbill goto agin;
677996Sbill }
678996Sbill }
679996Sbill
680996Sbill struct {char lobyte; char hibyte;};
mode(f)681996Sbill mode(f)
682996Sbill {
683996Sbill struct sgttyb stbuf;
684996Sbill if (dout) return;
685996Sbill ioctl(0, TIOCGETP, &stbuf);
686996Sbill tkill = stbuf.sg_kill;
687996Sbill terase = stbuf.sg_erase;
688996Sbill if (f == 0) {
689996Sbill stbuf.sg_flags &= ~RAW;
690996Sbill stbuf.sg_flags |= ECHO|CRMOD;
691996Sbill }
692996Sbill if (f == 1) {
693996Sbill stbuf.sg_flags |= RAW;
694996Sbill stbuf.sg_flags &= ~(ECHO|CRMOD);
695996Sbill }
696996Sbill if (f == 2) {
697996Sbill stbuf.sg_flags &= ~RAW;
698996Sbill stbuf.sg_flags &= ~(ECHO|CRMOD);
699996Sbill }
700996Sbill ioctl(0, TIOCSETP, &stbuf);
701996Sbill }
702996Sbill
echo(s)703996Sbill echo(s)
704996Sbill char *s;
705996Sbill {
706996Sbill char *p;
707996Sbill for (p=s;*p;p++);
708996Sbill if (p>s) write(0,s,p-s);
709996Sbill write(0,CRLF, sizeof(CRLF));
710996Sbill }
711996Sbill
prf(f,s)712996Sbill prf(f, s)
713996Sbill char *f;
714996Sbill char *s;
715996Sbill {
716996Sbill fprintf(stderr, f, s);
717996Sbill fprintf(stderr, CRLF);
718996Sbill }
719996Sbill
exists(devname)720996Sbill exists(devname)
721996Sbill char *devname;
722996Sbill {
723996Sbill if (access(devname, 0)==0)
724996Sbill return(1);
725996Sbill prf("%s does not exist", devname);
726996Sbill return(0);
727996Sbill }
7282370Smark
cleanup(code)7292370Smark cleanup(code)
7302370Smark {
7312370Smark rmlock(NULL);
7322370Smark exit(code);
7332370Smark }
7342370Smark
7352370Smark /*
7362370Smark * This code is taken directly from uucp and follows the same
7372370Smark * conventions. This is important since uucp and cu should
7382370Smark * respect each others locks.
7392370Smark */
7402370Smark
7412370Smark /* ulockf 3.2 10/26/79 11:40:29 */
7422370Smark /* #include "uucp.h" */
7432370Smark #include <sys/types.h>
7442370Smark #include <sys/stat.h>
7452370Smark
7462370Smark
7472370Smark
7482370Smark /*******
7492370Smark * ulockf(file, atime)
7502370Smark * char *file;
7512370Smark * time_t atime;
7522370Smark *
7532370Smark * ulockf - this routine will create a lock file (file).
7542370Smark * If one already exists, the create time is checked for
7552370Smark * older than the age time (atime).
7562370Smark * If it is older, an attempt will be made to unlink it
7572370Smark * and create a new one.
7582370Smark *
7592370Smark * return codes: 0 | FAIL
7602370Smark */
7612370Smark
ulockf(file,atime)7622370Smark ulockf(file, atime)
7632370Smark char *file;
7642370Smark time_t atime;
7652370Smark {
7662370Smark struct stat stbuf;
7672370Smark time_t ptime;
7682370Smark int ret;
7692370Smark static int pid = -1;
7702370Smark static char tempfile[NAMESIZE];
7712370Smark
7722370Smark if (pid < 0) {
7732370Smark pid = getpid();
7742370Smark sprintf(tempfile, "/usr/spool/uucp/LTMP.%d", pid);
7752370Smark }
7762370Smark if (onelock(pid, tempfile, file) == -1) {
7772370Smark /* lock file exists */
7782370Smark /* get status to check age of the lock file */
7792370Smark ret = stat(file, &stbuf);
7802370Smark if (ret != -1) {
7812370Smark time(&ptime);
7822370Smark if ((ptime - stbuf.st_ctime) < atime) {
7832370Smark /* file not old enough to delete */
7842370Smark return(FAIL);
7852370Smark }
7862370Smark }
7872370Smark ret = unlink(file);
7882370Smark ret = onelock(pid, tempfile, file);
7892370Smark if (ret != 0)
7902370Smark return(FAIL);
7912370Smark }
7922370Smark stlock(file);
7932370Smark return(0);
7942370Smark }
7952370Smark
7962370Smark
7972370Smark #define MAXLOCKS 10 /* maximum number of lock files */
7982370Smark char *Lockfile[MAXLOCKS];
7992370Smark int Nlocks = 0;
8002370Smark
8012370Smark /***
8022370Smark * stlock(name) put name in list of lock files
8032370Smark * char *name;
8042370Smark *
8052370Smark * return codes: none
8062370Smark */
8072370Smark
stlock(name)8082370Smark stlock(name)
8092370Smark char *name;
8102370Smark {
8112370Smark char *p;
8122370Smark extern char *calloc();
8132370Smark int i;
8142370Smark
8152370Smark for (i = 0; i < Nlocks; i++) {
8162370Smark if (Lockfile[i] == NULL)
8172370Smark break;
8182370Smark }
8192370Smark ASSERT(i < MAXLOCKS, "TOO MANY LOCKS %d", i);
8202370Smark if (i >= Nlocks)
8212370Smark i = Nlocks++;
8222370Smark p = calloc(strlen(name) + 1, sizeof (char));
8232370Smark ASSERT(p != NULL, "CAN NOT ALLOCATE FOR %s", name);
8242370Smark strcpy(p, name);
8252370Smark Lockfile[i] = p;
8262370Smark return;
8272370Smark }
8282370Smark
8292370Smark
8302370Smark /***
8312370Smark * rmlock(name) remove all lock files in list
8322370Smark * char *name; or name
8332370Smark *
8342370Smark * return codes: none
8352370Smark */
8362370Smark
rmlock(name)8372370Smark rmlock(name)
8382370Smark char *name;
8392370Smark {
8402370Smark int i;
8412370Smark
8422370Smark for (i = 0; i < Nlocks; i++) {
8432370Smark if (Lockfile[i] == NULL)
8442370Smark continue;
8452370Smark if (name == NULL
8462370Smark || strcmp(name, Lockfile[i]) == SAME) {
8472370Smark unlink(Lockfile[i]);
8482370Smark free(Lockfile[i]);
8492370Smark Lockfile[i] = NULL;
8502370Smark }
8512370Smark }
8522370Smark return;
8532370Smark }
8542370Smark
8552370Smark
8562370Smark /* this stuff from pjw */
8572370Smark /* /usr/pjw/bin/recover - check pids to remove unnecessary locks */
8582370Smark /* isalock(name) returns 0 if the name is a lock */
8592370Smark /* unlock(name) unlocks name if it is a lock*/
8602370Smark /* onelock(pid,tempfile,name) makes lock a name
8612370Smark on behalf of pid. Tempfile must be in the same
8622370Smark file system as name. */
8632370Smark /* lock(pid,tempfile,names) either locks all the
8642370Smark names or none of them */
isalock(name)8652370Smark isalock(name) char *name;
8662370Smark {
8672370Smark struct stat xstat;
8682370Smark if(stat(name,&xstat)<0) return(0);
8692370Smark if(xstat.st_size!=sizeof(int)) return(0);
8702370Smark return(1);
8712370Smark }
unlock(name)8722370Smark unlock(name) char *name;
8732370Smark {
8742370Smark if(isalock(name)) return(unlink(name));
8752370Smark else return(-1);
8762370Smark }
onelock(pid,tempfile,name)8772370Smark onelock(pid,tempfile,name) char *tempfile,*name;
8782370Smark { int fd;
8792370Smark fd=creat(tempfile,0444);
8802370Smark if(fd<0) return(-1);
8812370Smark write(fd,(char *) &pid,sizeof(int));
8822370Smark close(fd);
8832370Smark if(link(tempfile,name)<0)
8842370Smark { unlink(tempfile);
8852370Smark return(-1);
8862370Smark }
8872370Smark unlink(tempfile);
8882370Smark return(0);
8892370Smark }
lock(pid,tempfile,names)8902370Smark lock(pid,tempfile,names) char *tempfile,**names;
8912370Smark { int i,j;
8922370Smark for(i=0;names[i]!=0;i++)
8932370Smark { if(onelock(pid,tempfile,names[i])==0) continue;
8942370Smark for(j=0;j<i;j++) unlink(names[j]);
8952370Smark return(-1);
8962370Smark }
8972370Smark return(0);
8982370Smark }
8992370Smark
9002370Smark #define LOCKPRE "/usr/spool/uucp/LCK."
9012370Smark
9022370Smark /***
9032370Smark * delock(s) remove a lock file
9042370Smark * char *s;
9052370Smark *
9062370Smark * return codes: 0 | FAIL
9072370Smark */
9082370Smark
delock(s)9092370Smark delock(s)
9102370Smark char *s;
9112370Smark {
9122370Smark char ln[30];
9132370Smark
9142370Smark sprintf(ln, "%s.%s", LOCKPRE, s);
9152370Smark rmlock(ln);
9162370Smark }
9172370Smark
9182370Smark
9192370Smark /***
9202370Smark * mlock(sys) create system lock
9212370Smark * char *sys;
9222370Smark *
9232370Smark * return codes: 0 | FAIL
9242370Smark */
9252370Smark
mlock(sys)9262370Smark mlock(sys)
9272370Smark char *sys;
9282370Smark {
9292370Smark char lname[30];
9302370Smark sprintf(lname, "%s.%s", LOCKPRE, sys);
9312370Smark return(ulockf(lname, (time_t) SLCKTIME ) < 0 ? FAIL : 0);
9322370Smark }
9332370Smark
9342370Smark
9352370Smark
9362370Smark /***
9372370Smark * ultouch() update access and modify times for lock files
9382370Smark *
9392370Smark * return code - none
9402370Smark */
9412370Smark
ultouch()9422370Smark ultouch()
9432370Smark {
9442370Smark time_t time();
9452370Smark int i;
9462370Smark struct ut {
9472370Smark time_t actime;
9482370Smark time_t modtime;
9492370Smark } ut;
9502370Smark
9512370Smark ut.actime = time(&ut.modtime);
9522370Smark for (i = 0; i < Nlocks; i++) {
9532370Smark if (Lockfile[i] == NULL)
9542370Smark continue;
9552370Smark utime(Lockfile[i], &ut);
9562370Smark }
9572370Smark return;
9582370Smark }
959